import { describe, it, expect } from "vitest"; import { Value } from "@alkdev/typebox/value"; import { OperationEdgeAttrs, type OperationEdgeAttrs as OperationEdgeAttrsType, TriggeredEdgeAttrs, DependencyEdgeAttrs, TemplateEdgeAttrs, type TemplateEdgeAttrs as TemplateEdgeAttrsType, CallResultSchema, type CallResult, } from "../../src/schema/edge"; import { type OperationNodeAttrs } from "../../src/schema/node"; describe("OperationEdgeAttrs", () => { const valid: OperationEdgeAttrsType = { compatible: true, }; it("accepts valid attributes with no optional fields", () => { expect(Value.Check(OperationEdgeAttrs, valid)).toBe(true); }); it("accepts compatible false", () => { expect(Value.Check(OperationEdgeAttrs, { compatible: false })).toBe(true); }); it("accepts valid attributes with all optional fields", () => { const withOptional: OperationEdgeAttrsType = { compatible: false, detail: "Output schema mismatch", mismatches: [ { path: "/properties/name", expected: "string", actual: "number" }, ], }; expect(Value.Check(OperationEdgeAttrs, withOptional)).toBe(true); }); it("accepts empty mismatches array", () => { expect( Value.Check(OperationEdgeAttrs, { compatible: true, mismatches: [] }), ).toBe(true); }); it("rejects missing required compatible field", () => { expect(Value.Check(OperationEdgeAttrs, {})).toBe(false); }); it("rejects wrong type for compatible", () => { expect(Value.Check(OperationEdgeAttrs, { compatible: "yes" })).toBe(false); }); it("rejects wrong type for detail", () => { expect( Value.Check(OperationEdgeAttrs, { compatible: true, detail: 42 }), ).toBe(false); }); it("rejects mismatches with missing required fields", () => { expect( Value.Check(OperationEdgeAttrs, { compatible: false, mismatches: [{ path: "/x" }], }), ).toBe(false); }); }); describe("TriggeredEdgeAttrs", () => { it("accepts empty object", () => { expect(Value.Check(TriggeredEdgeAttrs, {})).toBe(true); }); it("rejects non-object", () => { expect(Value.Check(TriggeredEdgeAttrs, null)).toBe(false); expect(Value.Check(TriggeredEdgeAttrs, "x")).toBe(false); }); }); describe("DependencyEdgeAttrs", () => { it("accepts empty object", () => { expect(Value.Check(DependencyEdgeAttrs, {})).toBe(true); }); it("rejects non-object", () => { expect(Value.Check(DependencyEdgeAttrs, null)).toBe(false); expect(Value.Check(DependencyEdgeAttrs, 1)).toBe(false); }); }); describe("TemplateEdgeAttrs", () => { const valid: TemplateEdgeAttrsType = { edgeType: "sequential", }; it("accepts valid sequential edge", () => { expect(Value.Check(TemplateEdgeAttrs, valid)).toBe(true); }); it("accepts conditional edge", () => { expect( Value.Check(TemplateEdgeAttrs, { edgeType: "conditional" }), ).toBe(true); }); it("rejected edgeType values are rejected", () => { expect( Value.Check(TemplateEdgeAttrs, { edgeType: "triggered" }), ).toBe(false); expect( Value.Check(TemplateEdgeAttrs, { edgeType: "depends_on" }), ).toBe(false); expect( Value.Check(TemplateEdgeAttrs, { edgeType: "typed" }), ).toBe(false); }); it("accepts optional condition (string)", () => { expect( Value.Check(TemplateEdgeAttrs, { edgeType: "conditional", condition: "fetch-data", }), ).toBe(true); }); it("accepts optional condition (function)", () => { expect( Value.Check(TemplateEdgeAttrs, { edgeType: "conditional", condition: ((results: Record) => true) as unknown, }), ).toBe(true); }); it("accepts optional negated", () => { expect( Value.Check(TemplateEdgeAttrs, { edgeType: "conditional", negated: true, }), ).toBe(true); }); it("accepts optional dataFlow", () => { expect( Value.Check(TemplateEdgeAttrs, { edgeType: "sequential", dataFlow: true, }), ).toBe(true); expect( Value.Check(TemplateEdgeAttrs, { edgeType: "sequential", dataFlow: false, }), ).toBe(true); }); it("accepts all optional fields together", () => { const full: TemplateEdgeAttrsType = { edgeType: "conditional", condition: "fetch-data", negated: true, dataFlow: true, }; expect(Value.Check(TemplateEdgeAttrs, full)).toBe(true); }); it("rejects missing required edgeType", () => { expect(Value.Check(TemplateEdgeAttrs, {})).toBe(false); }); it("rejects invalid edgeType", () => { expect(Value.Check(TemplateEdgeAttrs, { edgeType: "parallel" })).toBe( false, ); }); it("rejects wrong type for negated", () => { expect( Value.Check(TemplateEdgeAttrs, { edgeType: "sequential", negated: 1 }), ).toBe(false); }); it("rejects wrong type for dataFlow", () => { expect( Value.Check(TemplateEdgeAttrs, { edgeType: "sequential", dataFlow: "yes", }), ).toBe(false); }); }); describe("CallResultSchema", () => { const valid: CallResult = { status: "completed", output: { label: "greeting" }, }; it("accepts valid result without optional error", () => { expect(Value.Check(CallResultSchema, valid)).toBe(true); }); it("accepts valid result with error", () => { const withError: CallResult = { status: "failed", output: null, error: { code: "INTERNAL", message: "Something went wrong" }, }; expect(Value.Check(CallResultSchema, withError)).toBe(true); }); it("accepts error with optional details", () => { const withDetails: CallResult = { status: "failed", output: null, error: { code: "INTERNAL", message: "Error", details: { stack: "..." }, }, }; expect(Value.Check(CallResultSchema, withDetails)).toBe(true); }); it("accepts all valid statuses", () => { for (const status of [ "idle", "waiting", "ready", "running", "completed", "failed", "skipped", "aborted", ] as const) { expect(Value.Check(CallResultSchema, { ...valid, status })).toBe(true); } }); it("rejects missing required status", () => { expect(Value.Check(CallResultSchema, { output: {} })).toBe(false); }); it("rejects invalid status", () => { expect( Value.Check(CallResultSchema, { status: "pending", output: null }), ).toBe(false); }); it("rejects error with missing required fields", () => { expect( Value.Check(CallResultSchema, { status: "failed", output: null, error: { code: "X" }, }), ).toBe(false); }); }); describe("TemplateNodeAttrs type alias", () => { it("TemplateNodeAttrs is an alias for OperationNodeAttrs type", () => { const attrs: OperationNodeAttrs = { name: "classify", namespace: "task", version: "1.0.0", type: "query", inputSchema: { type: "object" }, outputSchema: { type: "object" }, }; expect(attrs.name).toBe("classify"); expect(attrs.type).toBe("query"); }); });