Files
reverse-engineering-anything/tests/boundary/filesystem/ciTestProjects.test.ts
T

196 lines
6.3 KiB
TypeScript

import { execFileSync } from "node:child_process";
import { readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { pathToFileURL } from "node:url";
import { describe, expect, it } from "vitest";
import {
BUILT_TEST_PROJECTS,
SOURCE_TEST_PROJECTS,
projectForTest,
} from "../../../scripts/lib/test-projects.mjs";
import {
developmentTestPlan,
parseDevelopmentTestRequest,
} from "../../../scripts/lib/development-tests.mjs";
import { execFileOutput } from "../../../src/process/ExecFileOutput.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
const repository = process.cwd();
describe("canonical test-project ownership", () => {
it("assigns every tracked test file exactly once to source or built", () => {
const files = execFileSync("git", ["ls-files", "*.test.ts"], {
cwd: repository,
encoding: "utf8",
})
.trim()
.split("\n")
.filter(Boolean);
const grouped = new Map<string, string[]>();
for (const file of files) {
const project = projectForTest(file);
grouped.set(project.group, [...(grouped.get(project.group) ?? []), file]);
}
expect(grouped.get("source")).not.toBeUndefined();
expect(grouped.get("built")).not.toBeUndefined();
expect(
(grouped.get("source")?.length ?? 0) +
(grouped.get("built")?.length ?? 0),
).toBe(files.length);
expect(
SOURCE_TEST_PROJECTS.reduce(
(count, project) => count + project.include.length,
0,
),
).toBeGreaterThan(0);
expect(
BUILT_TEST_PROJECTS.every((project) => project.group === "built"),
).toBe(true);
expect(() => projectForTest("tests/unowned/example.test.ts")).toThrow(
"No test project owns",
);
});
it("owns the Hopper real-provider conformance test as built and requires preparation", () => {
const testPath =
"tests/conformance/providers/hopper/realHopperSearch.test.ts";
expect(projectForTest(testPath)).toMatchObject({
name: "boundary",
group: "built",
});
expect(() => parseDevelopmentTestRequest("local", [testPath])).toThrow(
`Use test:focused for built test projects: ${testPath}`,
);
const request = parseDevelopmentTestRequest("focused", [testPath]);
expect(developmentTestPlan(request)).toMatchObject({ needsBuild: true });
});
it("uses canonical selectors in Vitest while retaining independent runner policy", async () => {
const config = await readFile(join(repository, "vitest.config.ts"), "utf8");
expect(config).toContain(
"[...SOURCE_TEST_PROJECTS, ...BUILT_TEST_PROJECTS]",
);
expect(config).toContain("PROJECT_POLICIES");
expect(config).not.toContain('"src/{contracts,domain}/**/*.test.ts"');
});
it.each([
{ flags: [], timeout: 30_000, lines: 68 },
{ flags: ["--coverage"], timeout: 60_000, lines: 68 },
{ flags: ["--coverage.enabled"], timeout: 60_000, lines: 68 },
{ flags: ["--coverage=false"], timeout: 30_000, lines: 68 },
{
flags: ["--coverage.enabled=false"],
timeout: 30_000,
lines: 68,
},
{
flags: ["--coverage.provider=v8"],
timeout: 30_000,
lines: 68,
},
{
flags: ["--coverage.enabled", "--shard", "1/6"],
timeout: 60_000,
lines: 0,
},
{
flags: ["--coverage.enabled=false", "--shard=1/6"],
timeout: 30_000,
lines: 0,
},
])(
"resolves worker resources from actual CLI options: $flags",
async ({ flags, timeout, lines }) => {
const root = await createTestTempDirectory("rea-vitest-worker-policy-");
const script = join(root, "worker-policy.mjs");
await writeFile(
script,
`
import config from ${JSON.stringify(pathToFileURL(join(repository, "vitest.config.ts")).href)};
const project = config.test.projects.find(project => project.test.name === 'cli-boundary');
console.log(JSON.stringify({
execArgv: project.test.execArgv,
timeout: config.test.testTimeout,
lines: config.test.coverage.thresholds.lines,
}));
`,
);
const result = await execFileOutput(
process.execPath,
["--import", "tsx", script, ...flags],
{
cwd: repository,
timeout: 10_000,
maxBuffer: 64 * 1024,
stopSignal: "SIGTERM",
},
);
expect(JSON.parse(result.stdout)).toEqual({
execArgv: ["--max-old-space-size=512"],
timeout,
lines,
});
},
);
});
describe("test module isolation", () => {
it.each([
[
"tests/process-global/evidenceBundleHeadroom.test.ts",
"process-global",
"built",
],
[
"tests/process-global/javascriptAnalysisCancellation.test.ts",
"process-global",
"built",
],
])("keeps %s in its isolated preparation group", (path, name, group) => {
expect(projectForTest(path)).toMatchObject({ name, group });
});
it("keeps module mocks out of projects that share one module graph", async () => {
// A mock registered after another file in the same worker loaded the
// module never applies, so the test's outcome depends on file scheduling.
const root = await createTestTempDirectory("rea-vitest-mock-isolation-");
const script = join(root, "project-isolation.mjs");
await writeFile(
script,
`
import config from ${JSON.stringify(pathToFileURL(join(repository, "vitest.config.ts")).href)};
console.log(JSON.stringify(Object.fromEntries(
config.test.projects.map(project => [project.test.name, project.test.isolate !== false]),
)));
`,
);
const result = await execFileOutput(
process.execPath,
["--import", "tsx", script],
{
cwd: repository,
timeout: 10_000,
maxBuffer: 64 * 1024,
stopSignal: "SIGTERM",
},
);
const isolated = JSON.parse(result.stdout) as Record<string, boolean>;
const mocking = execFileSync(
"git",
["grep", "-l", "-E", String.raw`vi\.(mock|doMock)\(`, "--", "*.test.ts"],
{ cwd: repository, encoding: "utf8" },
)
.trim()
.split("\n")
.filter(Boolean);
expect(mocking.length).toBeGreaterThan(0);
expect(
mocking.filter((file) => isolated[projectForTest(file).name] !== true),
).toEqual([]);
});
});