test(FN-2358): harden clean-worktree CI verification tests
- Assert contributing docs explicitly state that pnpm test must run without prior build outputs - Add CI workflow test coverage to keep docs and verify:workspace ordering aligned - Expand Vitest workspace alias assertions to include @fusion/test-utils and src-only replacements - Validate real symbol imports from workspace packages when dist directories are absent
This commit is contained in:
@@ -23,12 +23,14 @@ describe("CI workflow (.github/workflows/ci.yml)", () => {
|
||||
let workflow: any;
|
||||
let content: string;
|
||||
let ciSteps: any[];
|
||||
let contributingContent: string;
|
||||
|
||||
beforeAll(() => {
|
||||
const result = loadWorkflow("ci.yml");
|
||||
workflow = result.parsed;
|
||||
content = result.content;
|
||||
ciSteps = workflow.jobs?.ci?.steps ?? [];
|
||||
contributingContent = readFileSync(join(workspaceRoot, "docs", "contributing.md"), "utf-8");
|
||||
});
|
||||
|
||||
const findStepByRun = (runSnippet: string) => ciSteps.find((step) => typeof step.run === "string" && step.run.includes(runSnippet));
|
||||
@@ -74,6 +76,14 @@ describe("CI workflow (.github/workflows/ci.yml)", () => {
|
||||
expect(buildExeIdx).toBeGreaterThan(verifyIdx);
|
||||
});
|
||||
|
||||
it("keeps contributing docs aligned with the clean-worktree verification contract", () => {
|
||||
expect(contributingContent).toContain("pnpm test` must be runnable in a clean worktree without requiring a prior `pnpm build`.");
|
||||
expect(contributingContent).toContain("`pnpm verify:workspace` is the canonical pre-merge gate");
|
||||
expect(contributingContent).toContain("1. `pnpm lint`");
|
||||
expect(contributingContent).toContain("2. `pnpm test`");
|
||||
expect(contributingContent).toContain("3. `pnpm build`");
|
||||
});
|
||||
|
||||
it("includes binary build step", () => {
|
||||
expect(content).toContain("build:exe");
|
||||
});
|
||||
|
||||
@@ -64,17 +64,27 @@ describe("CLI Vitest workspace resolution", () => {
|
||||
find: String(/^@fusion\/engine$/),
|
||||
replacement: join(workspaceRoot, "packages", "engine", "src", "index.ts"),
|
||||
},
|
||||
{
|
||||
find: String(/^@fusion\/dashboard\/planning$/),
|
||||
replacement: join(workspaceRoot, "packages", "dashboard", "src", "planning.ts"),
|
||||
},
|
||||
{
|
||||
find: String(/^@fusion\/dashboard$/),
|
||||
replacement: join(workspaceRoot, "packages", "dashboard", "src", "index.ts"),
|
||||
},
|
||||
{
|
||||
find: String(/^@fusion\/dashboard\/planning$/),
|
||||
replacement: join(workspaceRoot, "packages", "dashboard", "src", "planning.ts"),
|
||||
find: String(/^@fusion\/test-utils$/),
|
||||
replacement: join(workspaceRoot, "packages", "core", "src", "__test-utils__", "workspace.ts"),
|
||||
},
|
||||
]),
|
||||
);
|
||||
|
||||
for (const entry of normalized) {
|
||||
expect(entry.replacement).toContain(`${join("packages", "")}`);
|
||||
expect(entry.replacement).toContain(`${join("src", "")}`);
|
||||
expect(entry.replacement).not.toContain(`${join("dist", "")}`);
|
||||
}
|
||||
|
||||
const coreGhCliIndex = normalized.findIndex((entry) => entry.find === String(/^@fusion\/core\/gh-cli$/));
|
||||
const coreIndex = normalized.findIndex((entry) => entry.find === String(/^@fusion\/core$/));
|
||||
const planningIndex = normalized.findIndex((entry) => entry.find === String(/^@fusion\/dashboard\/planning$/));
|
||||
@@ -86,11 +96,25 @@ describe("CLI Vitest workspace resolution", () => {
|
||||
expect(dashboardIndex).toBeGreaterThan(planningIndex);
|
||||
});
|
||||
|
||||
it("resolves internal workspace imports during CLI tests when dist outputs are absent", async () => {
|
||||
await expect(import("@fusion/core")).resolves.toBeTruthy();
|
||||
await expect(import("@fusion/core/gh-cli")).resolves.toBeTruthy();
|
||||
await expect(import("@fusion/engine")).resolves.toBeTruthy();
|
||||
await expect(import("@fusion/dashboard")).resolves.toBeTruthy();
|
||||
await expect(import("@fusion/dashboard/planning")).resolves.toBeTruthy();
|
||||
it("resolves non-mocked symbols from internal workspace packages when dist outputs are absent", async () => {
|
||||
const [{ tempWorkspace }, { PRIORITY_EXECUTE }, { createRuntimeLogger }, { parseAgentResponse }] = await Promise.all([
|
||||
import("@fusion/test-utils"),
|
||||
import("@fusion/engine"),
|
||||
import("@fusion/dashboard"),
|
||||
import("@fusion/dashboard/planning"),
|
||||
]);
|
||||
|
||||
expect(typeof tempWorkspace).toBe("function");
|
||||
expect(typeof PRIORITY_EXECUTE).toBe("number");
|
||||
expect(typeof createRuntimeLogger).toBe("function");
|
||||
expect(parseAgentResponse('{"type":"question","data":{"id":"q","type":"confirm","question":"Ok?","description":"desc"}}')).toEqual({
|
||||
type: "question",
|
||||
data: {
|
||||
id: "q",
|
||||
type: "confirm",
|
||||
question: "Ok?",
|
||||
description: "desc",
|
||||
},
|
||||
});
|
||||
}, 30_000);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user