mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-11 21:57:14 +03:00
* test: harden the test strategy (triggers, runner speed, release guards) Follow-ups from an end-to-end testing strategy review: - Suite triggers are now auto-generated from each suite's own file list, so change-based CI can never miss a test file again (four files were unreachable by their own edits, and tests/lib/detector-bundle.test.js triggered core while running in detector). Two new meta-tests pin the invariant. Hand-written trigger patterns now carry only source paths and fixture dirs; palette dropped from the live triggers since no suite tests it. - The node runner batches all files into one node --test invocation at concurrency 4 instead of spawning per file. Default suite drops from ~159s to ~100s; the live suite soaked clean three times. - scripts/release.mjs gets its first tests: 12 scenarios spawning the real script inside a disposable git repo with a local bare origin, covering every refusal guard plus notes/tweet rendering, all under --dry-run. - skill/scripts/live/ui-core.mjs deleted: zero references repo-wide, superseded by the July live rewrite, yet still shipping to users. cli/lib/download-providers.js annotated with its cross-repo consumers (impeccable-site Pages Functions) so it is not mistaken for dead code. - CLAUDE.md gains an area-to-suite table for the opt-in suites a change owes; AGENTS.md syncs the plugin-e2e commands and obligations. AI-assisted via Claude Code under maintainer direction. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix: exclude peeled tag lines from release-test origin cleanup Copilot: git ls-remote --tags emits ^{} peel lines for annotated tags, which are not deletable refs; --refs filters them so the cleanup loop survives a future scenario that pushes an annotated tag. AI-assisted via Claude Code under maintainer direction. Co-Authored-By: Claude Code <noreply@anthropic.com> --------- Co-authored-by: Claude Code <noreply@anthropic.com>
70 lines
2.4 KiB
JavaScript
70 lines
2.4 KiB
JavaScript
import { describe, it } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
|
|
import {
|
|
DEFAULT_SUITES,
|
|
OPT_IN_SUITES,
|
|
SUITES,
|
|
expandSuites,
|
|
findTestFiles,
|
|
matchesSuiteTriggers,
|
|
suiteFiles,
|
|
} from '../scripts/test-suites.mjs';
|
|
|
|
describe('test suite registry', () => {
|
|
it('assigns every test file to a default or opt-in suite', () => {
|
|
const allDiscovered = findTestFiles();
|
|
const allRegistered = new Set(suiteFiles([...DEFAULT_SUITES, ...OPT_IN_SUITES]));
|
|
const missing = allDiscovered.filter((file) => !allRegistered.has(file));
|
|
|
|
assert.deepEqual(
|
|
missing,
|
|
[],
|
|
'new test files must be added to scripts/test-suites.mjs, either in a default suite or an opt-in suite',
|
|
);
|
|
});
|
|
|
|
it('keeps default local suites free of duplicate test files', () => {
|
|
const files = suiteFiles(DEFAULT_SUITES);
|
|
const duplicates = files.filter((file, index) => files.indexOf(file) !== index);
|
|
|
|
assert.deepEqual(duplicates, []);
|
|
});
|
|
|
|
it('keeps opt-in suites out of the default alias', () => {
|
|
const expanded = expandSuites(['default']);
|
|
for (const suite of expanded) {
|
|
assert.equal(SUITES[suite].optIn, undefined, `${suite} should not be opt-in`);
|
|
}
|
|
});
|
|
|
|
it('selects every suite when one of its own test files changes', () => {
|
|
// Change-based CI (ci-test-plan.mjs) picks suites via matchesSuiteTriggers.
|
|
// A test file whose edits select no suite, or only a suite that does not
|
|
// run it, is a silent CI gap; the generated own-file triggers close it.
|
|
for (const [name, suite] of Object.entries(SUITES)) {
|
|
for (const file of suiteFiles([name])) {
|
|
assert.equal(
|
|
matchesSuiteTriggers(name, [file]),
|
|
true,
|
|
`editing ${file} must select suite "${name}"`,
|
|
);
|
|
}
|
|
}
|
|
});
|
|
|
|
it('never lets a test file trigger only suites that do not run it', () => {
|
|
const allSuiteNames = Object.keys(SUITES);
|
|
for (const file of findTestFiles()) {
|
|
const triggered = allSuiteNames.filter((name) => matchesSuiteTriggers(name, [file]));
|
|
const runsIn = allSuiteNames.filter((name) => suiteFiles([name]).includes(file));
|
|
const useful = triggered.filter((name) => runsIn.includes(name));
|
|
assert.ok(
|
|
useful.length > 0,
|
|
`${file} triggers [${triggered.join(', ')}] but runs in [${runsIn.join(', ')}]; ` +
|
|
'at least one triggered suite must actually run it',
|
|
);
|
|
}
|
|
});
|
|
});
|