feat(plan): the Test first File line follows the 1.9 grammar [skip-docs]
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
3e1a811c60
commit
fc157c3ad5
3 changed files with 132 additions and 9 deletions
|
|
@ -12,6 +12,8 @@ import { readFileSync } from 'node:fs';
|
|||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import * as m from '../../lib/parsers/plan-schema.mjs';
|
||||
import { validatePlanContent } from '../../lib/validators/plan-validator.mjs';
|
||||
import { buildPlan } from '../helpers/plan-v18-builder.mjs';
|
||||
|
||||
const HERE = dirname(fileURLToPath(import.meta.url));
|
||||
const ROOT = join(HERE, '..', '..');
|
||||
|
|
@ -80,3 +82,71 @@ test('prose: the executor and the step helper name every file on the Test first
|
|||
assert.ok(text.includes(phrase), `${rel.join('/')} says "${phrase}"`);
|
||||
}
|
||||
});
|
||||
|
||||
// ---- plan_version 1.9 (plan step 5) ----------------------------------------
|
||||
// From 1.9 a `Test first:` `File:` line is every line that opens with `File:`
|
||||
// (after an optional list marker and `**`), backticked or not, and its rest is
|
||||
// one entry read by entryPaths: the leading backticked paths are the test
|
||||
// files, the rest is description. The validator puts the same grammar on it.
|
||||
|
||||
const PATH_CODES = ['PLAN_STEP_PATH_NOT_FIRST', 'PLAN_STEP_PATH_NOT_A_PATH'];
|
||||
// A plan of the given version whose first step has `Files:` `files` and the
|
||||
// `Test first:` `File:` line `fileLine` (both verbatim).
|
||||
const planWith = (version, files, fileLine) => buildPlan({
|
||||
version,
|
||||
steps: [{ filesRaw: files, testFirstRaw: fileLine }, { endToEnd: 'bash tests/e2e.sh' }],
|
||||
});
|
||||
|
||||
test('1.9: every leading backticked path on the File: line is a test file', () => {
|
||||
const body = step('`tests/a.test.mjs`, `tests/b.test.mjs`', [
|
||||
' - File: `tests/a.test.mjs`, `tests/b.test.mjs` (new)',
|
||||
' - Verifies: x',
|
||||
]);
|
||||
assert.deepEqual(testFirstFiles(body, '1.9'), ['tests/a.test.mjs', 'tests/b.test.mjs']);
|
||||
});
|
||||
|
||||
test('1.9: a backticked path in the description of the File: line is not a test file', () => {
|
||||
const body = step('`tests/a.test.mjs`', [
|
||||
' - File: `tests/a.test.mjs` (new), covers `tests/b.test.mjs`',
|
||||
' - Verifies: x',
|
||||
]);
|
||||
assert.deepEqual(testFirstFiles(body, '1.9'), ['tests/a.test.mjs']);
|
||||
// Below 1.9 the line is read as 6.3.1 + Step 3 read it: every path-shaped span.
|
||||
assert.deepEqual(testFirstFiles(body, '1.8'), ['tests/a.test.mjs', 'tests/b.test.mjs']);
|
||||
});
|
||||
|
||||
test('1.9: a code file named only in the File: line description keeps the step from being tests-only; in 1.8 it is tests-only', () => {
|
||||
const files = '`tests/a.test.mjs`, `checks/smoke.mjs`';
|
||||
const line = ' - File: `tests/a.test.mjs` (new), covers `checks/smoke.mjs`';
|
||||
const body = step(files, [line, ' - Verifies: x']);
|
||||
assert.equal(m.stepTestsOnly(body, '1.9').testsOnly, false, JSON.stringify(m.stepTestsOnly(body, '1.9')));
|
||||
assert.equal(m.stepTestsOnly(body, '1.8').testsOnly, true, JSON.stringify(m.stepTestsOnly(body, '1.8')));
|
||||
|
||||
const v19 = validatePlanContent(planWith('1.9', files, line));
|
||||
assert.ok(!v19.warnings.some((w) => w.code === 'PLAN_STEP_TESTS_ONLY'), JSON.stringify(v19.warnings));
|
||||
assert.deepEqual(v19.errors.filter((e) => PATH_CODES.includes(e.code)), [], JSON.stringify(v19.errors));
|
||||
const v18 = validatePlanContent(planWith('1.8', files, line));
|
||||
assert.ok(v18.warnings.some((w) => w.code === 'PLAN_STEP_TESTS_ONLY'), JSON.stringify(v18.warnings));
|
||||
});
|
||||
|
||||
test('1.9: a File: line that opens with `parse()` is refused as no path (error strict, warning soft)', () => {
|
||||
const text = planWith('1.9', '`tests/a.test.mjs`', ' - File: `parse()`');
|
||||
const strict = validatePlanContent(text);
|
||||
const e = strict.errors.find((i) => i.code === 'PLAN_STEP_PATH_NOT_A_PATH');
|
||||
assert.ok(e, JSON.stringify(strict.errors));
|
||||
assert.match(e.message, /Step 1/);
|
||||
assert.match(e.message, /Test first/);
|
||||
const soft = validatePlanContent(text, { strict: false });
|
||||
assert.ok(soft.warnings.some((w) => w.code === 'PLAN_STEP_PATH_NOT_A_PATH'), JSON.stringify(soft.warnings));
|
||||
assert.deepEqual(soft.errors.filter((i) => PATH_CODES.includes(i.code)), []);
|
||||
});
|
||||
|
||||
test('1.9: an unticked File: line gets PLAN_STEP_PATH_NOT_FIRST next to PLAN_STEP_NO_TEST_FIRST', () => {
|
||||
const r = validatePlanContent(planWith('1.9', '`tests/a.test.mjs`', ' - File: tests/a.test.mjs'));
|
||||
const codes = r.errors.map((e) => e.code);
|
||||
assert.ok(codes.includes('PLAN_STEP_PATH_NOT_FIRST'), codes.join(','));
|
||||
assert.ok(codes.includes('PLAN_STEP_NO_TEST_FIRST'), codes.join(','));
|
||||
const e = r.errors.find((i) => i.code === 'PLAN_STEP_PATH_NOT_FIRST');
|
||||
assert.match(e.message, /Step 1/);
|
||||
assert.match(e.message, /tests\/a\.test\.mjs/);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue