Ctrl K
ComunidadGuías…

test/release.test.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { describe, it, expect } from 'vitest';
import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, readdirSync } from 'fs';
import { tmpdir } from 'os';
import { join } from 'path';
import { parseFragment, nextVersion, changelogWith, release } from '../scripts/release.js';

const frag = (bump, body) => `---\nbump: ${bump}\n---\n${body}\n`;

describe('nextVersion', () => {
  it('bumps one part and zeroes the parts after it', () => {
    expect(nextVersion('0.6.6.3', ['micro'])).toBe('0.6.6.4');
    expect(nextVersion('0.6.6.3', ['patch'])).toBe('0.6.7.0');
    expect(nextVersion('0.6.6.3', ['minor'])).toBe('0.7.0.0');
    expect(nextVersion('0.6.6.3\n', ['major'])).toBe('1.0.0.0');
  });

  it('takes the largest level when several fragments land together', () => {
    expect(nextVersion('0.6.6.0', ['micro', 'patch', 'micro'])).toBe('0.6.7.0');
  });

  it('rejects a VERSION that is not four-part', () => {
    expect(() => nextVersion('0.6.6', ['patch'])).toThrow(/MAJOR.MINOR.PATCH.MICRO/);
  });
});

describe('parseFragment', () => {
  it('reads the bump and the notes, CRLF too', () => {
    expect(parseFragment(frag('micro', '### Fixed\n\n- a').replace(/\n/g, '\r\n')))
      .toEqual({ bump: 'micro', body: '### Fixed\n\n- a' });
  });

  it('rejects a missing or unknown bump and empty notes', () => {
    expect(() => parseFragment('### Fixed\n\n- a', 'x.md')).toThrow(/x.md: needs front matter/);
    expect(() => parseFragment(frag('huge', '- a'))).toThrow(/front matter/);
    expect(() => parseFragment(frag('patch', ''))).toThrow(/no release notes/);
  });
});

describe('changelogWith', () => {
  it('puts the new section above the newest one', () => {
    const out = changelogWith('# Changelog\n\nintro\n\n## [0.1.0.0] - 2026-01-01\n\nold\n', '0.1.1.0', '2026-02-02', ['a', 'b']);
    expect(out).toBe('# Changelog\n\nintro\n\n## [0.1.1.0] - 2026-02-02\n\na\n\nb\n\n## [0.1.0.0] - 2026-01-01\n\nold\n');
  });
});

// A malformed fragment would only fail the release run after merge; catch it
// in the PR's own test run instead.
describe('changelog.d in this repo', () => {
  it('holds only fragments the release script can read', () => {
    for (const n of readdirSync('changelog.d').filter((n) => n.endsWith('.md') && n !== 'README.md')) {
      expect(() => parseFragment(readFileSync(join('changelog.d', n), 'utf8'), n)).not.toThrow();
    }
  });
});

describe('release', () => {
  function repo() {
    const root = mkdtempSync(join(tmpdir(), 'release-'));
    mkdirSync(join(root, 'changelog.d'));
    writeFileSync(join(root, 'VERSION'), '0.6.6.0\n');
    writeFileSync(join(root, 'package.json'), '{\n  "name": "x",\n  "version": "0.6.6"\n}\n');
    writeFileSync(join(root, 'package-lock.json'), JSON.stringify({ version: '0.6.6', packages: { '': { version: '0.6.6' } } }));
    writeFileSync(join(root, 'CHANGELOG.md'), '# Changelog\n\n## [0.6.6.0] - 2026-09-25\n\nold\n');
    writeFileSync(join(root, 'changelog.d', 'README.md'), 'how to write a fragment');
    return root;
  }
  const read = (root, f) => readFileSync(join(root, f), 'utf8');

  it('does nothing without fragments', () => {
    const root = repo();
    expect(release(root)).toBe(null);
    expect(read(root, 'VERSION')).toBe('0.6.6.0\n');
  });

  it('releases two parallel PRs as one version with both notes, and deletes the fragments', () => {
    const root = repo();
    writeFileSync(join(root, 'changelog.d', 'branch-a.md'), frag('micro', '### Fixed\n\n- **A.** from branch a'));
    writeFileSync(join(root, 'changelog.d', 'branch-b.md'), frag('patch', '### Added\n\n- **B.** from branch b'));

    expect(release(root, '2026-09-26')).toBe('0.6.7.0');
    expect(read(root, 'VERSION')).toBe('0.6.7.0\n');
    expect(JSON.parse(read(root, 'package.json')).version).toBe('0.6.7');
    const lock = JSON.parse(read(root, 'package-lock.json'));
    expect([lock.version, lock.packages[''].version]).toEqual(['0.6.7', '0.6.7']);
    expect(read(root, 'CHANGELOG.md')).toBe(
      '# Changelog\n\n## [0.6.7.0] - 2026-09-26\n\n### Fixed\n\n- **A.** from branch a\n\n### Added\n\n- **B.** from branch b\n\n## [0.6.6.0] - 2026-09-25\n\nold\n',
    );
    expect(readdirSync(join(root, 'changelog.d'))).toEqual(['README.md']);
  });

  it('writes nothing when a fragment is malformed', () => {
    const root = repo();
    writeFileSync(join(root, 'changelog.d', 'ok.md'), frag('patch', '- ok'));
    writeFileSync(join(root, 'changelog.d', 'bad.md'), '- no front matter');
    expect(() => release(root)).toThrow(/changelog.d\/bad.md/);
    expect(read(root, 'VERSION')).toBe('0.6.6.0\n');
    expect(readdirSync(join(root, 'changelog.d')).sort()).toEqual(['README.md', 'bad.md', 'ok.md']);
  });
});