setup: add vitest test infrastructure with helpers, fixtures, and reactive test patterns
This commit is contained in:
171
test/helpers/helpers.test.ts
Normal file
171
test/helpers/helpers.test.ts
Normal file
@@ -0,0 +1,171 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import {
|
||||
createLinearGraph,
|
||||
createDiamondGraph,
|
||||
createOperationGraph,
|
||||
createCallGraph,
|
||||
} from "@test/graph-factory.js";
|
||||
import {
|
||||
createTestReactiveRoot,
|
||||
assertStatus,
|
||||
assertPreconditions,
|
||||
assertBlockedByFailure,
|
||||
} from "@test/reactive.js";
|
||||
import {
|
||||
CompatibleInputSchema,
|
||||
CompatibleOutputSchema,
|
||||
NarrowOutputSchema,
|
||||
WideInputSchema,
|
||||
IncompatibleNumberOutputSchema,
|
||||
IncompatibleStringInputSchema,
|
||||
compatiblePairs,
|
||||
incompatiblePairs,
|
||||
unknownSchemas,
|
||||
} from "@test/schemas.js";
|
||||
|
||||
describe("test helpers smoke tests", () => {
|
||||
describe("graph-factory", () => {
|
||||
it("creates a linear graph", () => {
|
||||
const graph = createLinearGraph(["A", "B", "C"]);
|
||||
expect(graph.nodes()).toEqual(["A", "B", "C"]);
|
||||
expect(graph.edges()).toEqual(["A->B", "B->C"]);
|
||||
});
|
||||
|
||||
it("creates a diamond graph", () => {
|
||||
const graph = createDiamondGraph("top", "left", "right", "bottom");
|
||||
expect(graph.nodes()).toEqual(["top", "left", "right", "bottom"]);
|
||||
expect(graph.edges()).toEqual([
|
||||
"top->left",
|
||||
"top->right",
|
||||
"left->bottom",
|
||||
"right->bottom",
|
||||
]);
|
||||
});
|
||||
|
||||
it("creates an operation graph", () => {
|
||||
const graph = createOperationGraph(
|
||||
[
|
||||
{ name: "classify", namespace: "task" },
|
||||
{ name: "enrich", namespace: "task" },
|
||||
],
|
||||
[{ source: "task.classify", target: "task.enrich" }],
|
||||
);
|
||||
expect(graph.nodes()).toEqual(["task.classify", "task.enrich"]);
|
||||
expect(graph.edges()).toEqual(["task.classify->task.enrich"]);
|
||||
});
|
||||
|
||||
it("creates a call graph", () => {
|
||||
const graph = createCallGraph([
|
||||
{ requestId: "req1", operationId: "op1", status: "completed" },
|
||||
{
|
||||
requestId: "req2",
|
||||
operationId: "op2",
|
||||
status: "running",
|
||||
parentRequestId: "req1",
|
||||
},
|
||||
]);
|
||||
expect(graph.nodes()).toEqual(["req1", "req2"]);
|
||||
expect(graph.edges()).toEqual(["req1->req2"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("reactive", () => {
|
||||
it("creates reactive root with setup-transition-assert-dispose", () => {
|
||||
const graph = createDiamondGraph("A", "B", "C", "D");
|
||||
const root = createTestReactiveRoot(graph);
|
||||
|
||||
try {
|
||||
assertStatus(root, "A", "idle");
|
||||
assertStatus(root, "B", "idle");
|
||||
assertPreconditions(root, "A", true);
|
||||
assertPreconditions(root, "D", false);
|
||||
|
||||
root.statusMap.get("A")!.value = "completed";
|
||||
assertPreconditions(root, "B", true);
|
||||
assertPreconditions(root, "C", true);
|
||||
assertPreconditions(root, "D", false);
|
||||
|
||||
root.statusMap.get("B")!.value = "completed";
|
||||
root.statusMap.get("C")!.value = "completed";
|
||||
assertPreconditions(root, "D", true);
|
||||
} finally {
|
||||
root.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
it("propagates failure to blockedByFailure", () => {
|
||||
const graph = createLinearGraph(["A", "B"]);
|
||||
const root = createTestReactiveRoot(graph);
|
||||
|
||||
try {
|
||||
assertBlockedByFailure(root, "B", false);
|
||||
root.statusMap.get("A")!.value = "failed";
|
||||
assertBlockedByFailure(root, "B", true);
|
||||
} finally {
|
||||
root.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
it("auto-aborts idle nodes when blockedByFailure fires", () => {
|
||||
const graph = createLinearGraph(["A", "B"]);
|
||||
const root = createTestReactiveRoot(graph);
|
||||
|
||||
try {
|
||||
assertStatus(root, "B", "idle");
|
||||
assertBlockedByFailure(root, "B", false);
|
||||
|
||||
root.statusMap.get("A")!.value = "failed";
|
||||
|
||||
assertBlockedByFailure(root, "B", true);
|
||||
assertStatus(root, "B", "aborted");
|
||||
} finally {
|
||||
root.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
it("skipped satisfies preconditions", () => {
|
||||
const graph = createLinearGraph(["A", "B"]);
|
||||
const root = createTestReactiveRoot(graph);
|
||||
|
||||
try {
|
||||
root.statusMap.get("A")!.value = "skipped";
|
||||
assertPreconditions(root, "B", true);
|
||||
} finally {
|
||||
root.dispose();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("schemas", () => {
|
||||
it("provides compatible pairs", () => {
|
||||
expect(compatiblePairs.length).toBeGreaterThan(0);
|
||||
for (const pair of compatiblePairs) {
|
||||
expect(pair.name).toBeTruthy();
|
||||
expect(pair.output).toBeDefined();
|
||||
expect(pair.input).toBeDefined();
|
||||
}
|
||||
});
|
||||
|
||||
it("provides incompatible pairs", () => {
|
||||
expect(incompatiblePairs.length).toBeGreaterThan(0);
|
||||
for (const pair of incompatiblePairs) {
|
||||
expect(pair.name).toBeTruthy();
|
||||
expect(pair.output).toBeDefined();
|
||||
expect(pair.input).toBeDefined();
|
||||
}
|
||||
});
|
||||
|
||||
it("provides unknown schemas", () => {
|
||||
expect(unknownSchemas.length).toBeGreaterThan(0);
|
||||
for (const item of unknownSchemas) {
|
||||
expect(item.name).toBeTruthy();
|
||||
expect(item.schema).toBeDefined();
|
||||
}
|
||||
});
|
||||
|
||||
it("CompatibleInputSchema and CompatibleOutputSchema have same structure", () => {
|
||||
expect(CompatibleInputSchema).toBeDefined();
|
||||
expect(CompatibleOutputSchema).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user