71 lines
2.2 KiB
TypeScript
71 lines
2.2 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import { ContractRegistry, checkContractCompatibility, defineEvent, v } from "../src/index.ts";
|
|
|
|
describe("boundary contract registry", () => {
|
|
test("registers typed, deterministic multi-boundary snapshots", () => {
|
|
const registry = new ContractRegistry()
|
|
.register(
|
|
defineEvent({
|
|
name: "user.created",
|
|
version: 1,
|
|
payload: v.object({ id: v.string().uuid() }),
|
|
}),
|
|
)
|
|
.register({
|
|
kind: "queue",
|
|
name: "email.send",
|
|
version: 1,
|
|
payload: v.object({ to: v.string().email() }),
|
|
});
|
|
expect(registry.snapshot().contracts.map((item) => `${item.kind}:${item.name}`)).toEqual([
|
|
"pubsub:user.created",
|
|
"queue:email.send",
|
|
]);
|
|
});
|
|
|
|
test("rejects duplicate identities", () => {
|
|
const registry = new ContractRegistry();
|
|
const contract = {
|
|
kind: "api",
|
|
name: "users",
|
|
version: 1,
|
|
payload: v.object({ id: v.string() }),
|
|
} as const;
|
|
registry.register(contract);
|
|
expect(() => registry.register(contract)).toThrow("Duplicate contract");
|
|
});
|
|
|
|
test("reports breaking fields, types, requirements, rules, and consumers", () => {
|
|
const previous = new ContractRegistry()
|
|
.register({
|
|
kind: "webhook",
|
|
name: "invoice.paid",
|
|
version: 1,
|
|
consumers: ["accounting", "email"],
|
|
payload: v.object({
|
|
email: v.string().optional(),
|
|
count: v.number().min(0),
|
|
legacy: v.string(),
|
|
}),
|
|
})
|
|
.snapshot();
|
|
const current = new ContractRegistry()
|
|
.register({
|
|
kind: "webhook",
|
|
name: "invoice.paid",
|
|
version: 1,
|
|
payload: v.object({ email: v.string(), count: v.string().min(2), added: v.string() }),
|
|
})
|
|
.snapshot();
|
|
const issues = checkContractCompatibility(previous, current);
|
|
expect(issues.map((issue) => issue.code)).toEqual([
|
|
"WRN-CONTRACT-FIELD-REQUIRED",
|
|
"WRN-CONTRACT-FIELD-TYPE",
|
|
"WRN-CONTRACT-RULE-TIGHTENED",
|
|
"WRN-CONTRACT-FIELD-REMOVED",
|
|
"WRN-CONTRACT-FIELD-REQUIRED",
|
|
]);
|
|
expect(issues.every((issue) => issue.consumers.includes("accounting"))).toBe(true);
|
|
});
|
|
});
|