// The rename check, checked. // // A check that has never been shown to fail is a check nobody knows the state of. // This one gates the only instructions a reader has for the first thing they do // with the template, so both directions of it are exercised here against // fixtures — no filesystem, because `problems()` takes its three inputs as // arguments precisely so that it can be tested this way. // // Run by CI as `node --test scripts/`, which needs no dependencies and no // package.json: Node's own test runner, over a repo with nothing installed. const test = require('node:test') const assert = require('node:assert') const { PLACEHOLDER, checklistPaths, problems } = require('./checkRenameSites') /** `problems()` with a `contains` built from a set of file names. */ const check = (files, listed, dirty) => problems({ files, listed, contains: (f) => new Set(dirty).has(f) }) test('a clean, complete checklist has no problems', () => { assert.deepStrictEqual(check(['a.js', 'b.js', 'clean.js'], ['a.js', 'b.js'], ['a.js', 'b.js']), []) }) test('a file that mentions the placeholder and is not listed fails', () => { const found = check(['a.js', 'new.js'], ['a.js'], ['a.js', 'new.js']) assert.strictEqual(found.length, 1) assert.match(found[0], /new\.js.*NOT in the rename checklist/s) }) test('a listed file that no longer mentions the placeholder fails', () => { // The direction that is easy to leave out, and the more valuable of the two: a // row that has stopped matching reads as instructions to edit something that is // not there any more. const found = check(['a.js', 'b.js'], ['a.js', 'b.js'], ['a.js']) assert.strictEqual(found.length, 1) assert.match(found[0], /b\.js.*no longer mentions/s) }) test('a listed file that has been deleted fails', () => { const found = check(['a.js'], ['a.js', 'gone.js'], ['a.js']) assert.strictEqual(found.length, 1) assert.match(found[0], /gone\.js.*does not exist/s) }) test('a duplicated row fails', () => { const found = check(['a.js'], ['a.js', 'a.js'], ['a.js']) assert.ok(found.some((p) => /listed in the checklist twice/.test(p))) }) test('the checklist file itself is exempt', () => { // It is a table OF the placeholder, so it would otherwise always list itself. assert.deepStrictEqual(check(['README.md'], [], ['README.md']), []) }) test('the placeholder pattern matches every form a rename touches', () => { for (const text of [ "const ID = 'examplegame'", 'ExamplegameWorldStatus', 'name: "Example Game"', "worldName: 'Example World'", 'examplegame_world_status', 'example-game', ]) { assert.ok(PLACEHOLDER.test(text), `should match: ${text}`) } }) test('the placeholder pattern does not fire on ordinary prose', () => { // The reason the id is `examplegame` rather than `example`: a check that // false-alarms on the word "example" in a comment is a check whose failures // stop being read. for (const text of [ '// for example, a router mounted under /shard', 'an example of what to catch', 'exampleValue', 'the game world', ]) { assert.ok(!PLACEHOLDER.test(text), `should not match: ${text}`) } }) test('checklistPaths reads only the rows between the markers', () => { const md = [ '# Heading', '', 'Prose quoting `not/a/row.js` and a tree diagram.', '', '', '', '| File | What to change |', '| --- | --- |', '| `module.json` | the id |', '| `server/core.js` | the message |', '', '', '', 'More prose about `also/not/a/row.js`.', ].join('\n') assert.deepStrictEqual(checklistPaths(md), ['module.json', 'server/core.js']) }) test('a README with no markers is an error, not an empty checklist', () => { // Silently reading zero entries would make every later assertion vacuous, and // the check would pass on a README whose checklist someone deleted. assert.throws(() => checklistPaths('# Heading\n\nno markers here\n'), /rename-sites/) })