import { describe, expect, it } from "vitest"; import { classifyObjectSchemaChange, isVersionCompatible, parseNumericVersion, verifyCompatibilityTuple, } from "../../src/application/policies/compatibility.ts"; describe("contract compatibility", () => { it("uses numeric version parsing rather than lexical comparison", () => { expect(parseNumericVersion("1.10.0")).toEqual({ major: 1, minor: 10, patch: 0 }); expect(isVersionCompatible("1.9", "1.10")).toBe(true); expect(isVersionCompatible("1.9", "2.0")).toBe(false); expect(isVersionCompatible("next", "1.0")).toBe(false); }); it("distinguishes additive and breaking object changes", () => { const base = { required: ["id"], properties: { id: {} } }; expect( classifyObjectSchemaChange(base, { required: ["id"], properties: { id: {}, name: {} }, }), ).toBe("additive"); expect( classifyObjectSchemaChange(base, { required: ["id", "name"], properties: { id: {}, name: {} }, }), ).toBe("breaking"); }); it("treats release ID mismatch as a warning when the blocking tuple is coherent", () => { const frontend = { buildId: "build-a", configSchemaVersion: "1.0", apiContractVersion: "1.0", assetManifestHash: "hash-a", releaseId: "release-a", }; expect( verifyCompatibilityTuple({ frontend, runtime: { ...frontend, releaseId: "release-b" }, }), ).toEqual({ compatible: true, mismatches: [], warnings: ["releaseId"], }); }); it("blocks mixed build, config, API, or asset tuples", () => { const frontend = { buildId: "build-a", configSchemaVersion: "1.0", apiContractVersion: "1.0", assetManifestHash: "hash-a", releaseId: "release-a", }; expect( verifyCompatibilityTuple({ frontend, runtime: { ...frontend, buildId: "build-b", configSchemaVersion: "2.0", assetManifestHash: "hash-b", }, }), ).toMatchObject({ compatible: false, mismatches: ["buildId", "configSchemaVersion", "assetManifestHash"], }); }); });