mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-19 21:32:20 +03:00
* fix(ci): clear the tap.testFiles drift that reds the gate on every PR
check-mutation-test-coverage --strict fails on a pristine checkout of
release/v3.8.51 with no PR diff involved, so the mutation-test-coverage
gate is red on every open PR regardless of what it changes.
Six covering unit tests across four mutated modules were absent from
stryker.conf.json tap.testFiles, which means their mutant kills were not
being counted:
accountFallback.ts daily-reset-tz-threading, noauth-model-lockout
sse/services/auth.ts free-badge-provider-gate, noauth-model-lockout
combo/comboPredicates.ts local-token-budget-429-skips-cooldown
combo/rrState.ts daily-reset-tz-threading
Four distinct files — two of them cover two modules each. Inserted into
the alphabetical run, matching the file's existing convention; the list
has a second unsorted appended group that is left alone.
After: "No drift — every covering unit test is listed in tap.testFiles",
exit 0. All four files pass (31 tests) so registering them does not
introduce a failing mutation run.
Noticed while reviewing #13743, which targets a fifth file that has
already been registered by 25bc16d87e.
* fix(ci): drop a dangling tap.testFiles entry and guard against new ones
Merging the release line in surfaced that stryker.conf.json still names
tests/unit/plugin-sandbox-permissions.test.ts, which does not exist —
one dangling path out of 428 entries, pre-existing on the base rather
than introduced here.
check-mutation-test-coverage already guards one direction: a test that
covers a mutated module but is missing from tap.testFiles. The other
direction was silent. Stryker resolves the list into its sandbox, so an
entry left behind after its test file is deleted or renamed costs
coverage without failing loudly — the same class of drift this PR is
about, arriving from the opposite side.
110 lines
4.0 KiB
TypeScript
110 lines
4.0 KiB
TypeScript
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import {
|
|
moduleFragment,
|
|
testImportsModule,
|
|
findCoverageDrift,
|
|
} from "../../../scripts/check/check-mutation-test-coverage.mjs";
|
|
|
|
test("moduleFragment returns the 3-segment suffix without extension", () => {
|
|
assert.equal(
|
|
moduleFragment("open-sse/handlers/chatCore/headers.ts"),
|
|
"handlers/chatCore/headers"
|
|
);
|
|
assert.equal(moduleFragment("src/sse/services/auth.ts"), "sse/services/auth");
|
|
// shallow paths just use what is available
|
|
assert.equal(moduleFragment("a/b.ts"), "a/b");
|
|
});
|
|
|
|
test("testImportsModule matches static, dynamic and require imports of the module path", () => {
|
|
const frag = "handlers/chatCore/headers";
|
|
// static import-from
|
|
assert.equal(
|
|
testImportsModule(`import { x } from "@omniroute/open-sse/handlers/chatCore/headers";`, frag),
|
|
true
|
|
);
|
|
// dynamic await import, even split across lines
|
|
assert.equal(
|
|
testImportsModule(
|
|
`const { y } = await import(\n "../../open-sse/handlers/chatCore/headers.ts"\n);`,
|
|
frag
|
|
),
|
|
true
|
|
);
|
|
// require()
|
|
assert.equal(
|
|
testImportsModule(`const z = require("../../open-sse/handlers/chatCore/headers.ts");`, frag),
|
|
true
|
|
);
|
|
// unrelated module is not matched
|
|
assert.equal(
|
|
testImportsModule(
|
|
`import { a } from "@omniroute/open-sse/handlers/chatCore/idempotency";`,
|
|
frag
|
|
),
|
|
false
|
|
);
|
|
// the fragment appearing only in a comment (not an import string) is NOT a match
|
|
assert.equal(
|
|
testImportsModule(`// see handlers/chatCore/headers for details\nconst a = 1;`, frag),
|
|
false
|
|
);
|
|
});
|
|
|
|
test("findCoverageDrift flags covering unit tests absent from tap.testFiles", () => {
|
|
const mutate = [
|
|
"open-sse/handlers/chatCore/headers.ts",
|
|
"open-sse/handlers/chatCore/idempotency.ts",
|
|
"_a_comment_entry",
|
|
];
|
|
const tapTestFiles = ["tests/unit/chatcore-headers.test.ts"];
|
|
const unitTests = [
|
|
// covers headers, already in tap -> not drift
|
|
{
|
|
path: "tests/unit/chatcore-headers.test.ts",
|
|
content: `await import("../../open-sse/handlers/chatCore/headers.ts");`,
|
|
},
|
|
// covers headers, NOT in tap -> drift
|
|
{
|
|
path: "tests/unit/no-memory-header.test.ts",
|
|
content: `const { isNoMemoryRequested } = await import("../../open-sse/handlers/chatCore/headers.ts");`,
|
|
},
|
|
// covers idempotency, NOT in tap -> drift
|
|
{
|
|
path: "tests/unit/idempo.test.ts",
|
|
content: `import { x } from "@omniroute/open-sse/handlers/chatCore/idempotency";`,
|
|
},
|
|
// covers nothing mutated -> ignored
|
|
{ path: "tests/unit/unrelated.test.ts", content: `import { z } from "@/lib/foo";` },
|
|
];
|
|
const drift = findCoverageDrift({ mutate, tapTestFiles, unitTests });
|
|
assert.deepEqual(drift["open-sse/handlers/chatCore/headers.ts"], [
|
|
"tests/unit/no-memory-header.test.ts",
|
|
]);
|
|
assert.deepEqual(drift["open-sse/handlers/chatCore/idempotency.ts"], [
|
|
"tests/unit/idempo.test.ts",
|
|
]);
|
|
// comment-only mutate entries are skipped
|
|
assert.equal("_a_comment_entry" in drift, false);
|
|
});
|
|
|
|
test("every tap.testFiles entry names a file that still exists", () => {
|
|
// The existing drift check runs one way: a test that covers a mutated module
|
|
// but is missing from tap.testFiles. The other way is silent — an entry left
|
|
// behind after its test file is deleted or renamed. Stryker resolves the list
|
|
// into its sandbox, so a dangling path costs coverage without failing loudly.
|
|
const repoRoot = path.resolve(import.meta.dirname, "../../..");
|
|
const conf = JSON.parse(fs.readFileSync(path.join(repoRoot, "stryker.conf.json"), "utf8")) as {
|
|
tap?: { testFiles?: string[] };
|
|
};
|
|
const entries = conf.tap?.testFiles ?? [];
|
|
assert.ok(entries.length > 0, "stryker.conf.json declares no tap.testFiles");
|
|
|
|
const missing = entries
|
|
.filter((entry) => !entry.includes("*"))
|
|
.filter((entry) => !fs.existsSync(path.join(repoRoot, entry)));
|
|
assert.deepEqual(missing, [], `tap.testFiles names ${missing.length} file(s) that do not exist`);
|
|
});
|