From 82f94423e58bcf830ca28c667f7b057b255f14f7 Mon Sep 17 00:00:00 2001 From: DongHyeonka Date: Sat, 15 Aug 2026 18:16:21 +0900 Subject: [PATCH] test: enforce exact TechLog contract keys --- tests/features/tech-log/feature-input.test.ts | 32 ++++----- .../features/tech-log/studio-contract.test.ts | 66 ++++++++----------- 2 files changed, 39 insertions(+), 59 deletions(-) diff --git a/tests/features/tech-log/feature-input.test.ts b/tests/features/tech-log/feature-input.test.ts index 3e4432a..73d500a 100644 --- a/tests/features/tech-log/feature-input.test.ts +++ b/tests/features/tech-log/feature-input.test.ts @@ -5,29 +5,23 @@ import { TECH_LOG_FEATURE_ID, type TechLogFeatureInput, } from "../../../src/features/tech-log/application/tech-log-feature-input.ts"; -import type { PublicContentQueries } from "../../../src/features/tech-log/application/ports/public-content-queries.ts"; -import type { StudioGateway } from "../../../src/features/tech-log/application/ports/studio-gateway.ts"; -function acceptsApplicationFeatureInput( - input: ApplicationFeatureInputs["tech-log"], -): TechLogFeatureInput { - return input; -} +type Equal = + (() => Value extends Left ? 1 : 2) extends + (() => Value extends Right ? 1 : 2) + ? true + : false; +type Assert = Condition; + +type TechLogFeatureInputExposesNoMissingOrAdditionalKeys = Assert< + Equal +>; +type TechLogFeatureInputRegistryValueMatchesFeatureContract = Assert< + Equal +>; describe("TechLog feature input", () => { it("uses the fixed application feature identifier", () => { expect(TECH_LOG_FEATURE_ID).toBe("tech-log"); }); - - it("accepts public queries and a Studio gateway factory through the application registry", () => { - const publicContent = {} as PublicContentQueries; - const gateway = {} as StudioGateway; - const input = acceptsApplicationFeatureInput({ - publicContent, - createStudioGateway: () => gateway, - }); - - expect(input.publicContent).toBe(publicContent); - expect(input.createStudioGateway()).toBe(gateway); - }); }); diff --git a/tests/features/tech-log/studio-contract.test.ts b/tests/features/tech-log/studio-contract.test.ts index 83239fe..c62a184 100644 --- a/tests/features/tech-log/studio-contract.test.ts +++ b/tests/features/tech-log/studio-contract.test.ts @@ -9,6 +9,13 @@ import type { StudioGateway, } from "../../../src/features/tech-log/application/ports/studio-gateway.ts"; +type Equal = + (() => Value extends Left ? 1 : 2) extends + (() => Value extends Right ? 1 : 2) + ? true + : false; +type Assert = Condition; + type Inline = components["schemas"]["Inline"]; type CaseRenderBlock = components["schemas"]["CaseRenderBlock"]; @@ -40,39 +47,24 @@ const blocks: CaseRenderBlock[] = [ { type: "EVIDENCE_FIGURE", key: "fetch-plan", alt: "Fetch plan", caption: "Measured fetch plan", zoom: true }, ]; -const gatewayMethodNames = [ - "getDashboard", - "listDocuments", - "createDocument", - "getDocument", - "saveDocument", - "validateDocument", - "createPreview", - "getCurrentPreview", - "publishDocument", - "unpublishPublication", - "listPublications", - "getPublicationSnapshot", - "getCatalog", -] as const; +type RequiredStudioGatewayOperation = + | "getDashboard" + | "listDocuments" + | "createDocument" + | "getDocument" + | "saveDocument" + | "validateDocument" + | "createPreview" + | "getCurrentPreview" + | "publishDocument" + | "unpublishPublication" + | "listPublications" + | "getPublicationSnapshot" + | "getCatalog"; -function gatewayWithEveryRequiredMethod(): StudioGateway { - return { - getDashboard: async () => undefined as never, - listDocuments: async () => undefined as never, - createDocument: async () => undefined as never, - getDocument: async () => undefined as never, - saveDocument: async () => undefined as never, - validateDocument: async () => undefined as never, - createPreview: async () => undefined as never, - getCurrentPreview: async () => undefined as never, - publishDocument: async () => undefined as never, - unpublishPublication: async () => undefined as never, - listPublications: async () => undefined as never, - getPublicationSnapshot: async () => undefined as never, - getCatalog: async () => undefined as never, - }; -} +type StudioGatewayExposesNoMissingOrAdditionalOperations = Assert< + Equal +>; describe("TechLog Studio contracts", () => { it("preserves every public wire discriminator exactly once", () => { @@ -98,26 +90,20 @@ describe("TechLog Studio contracts", () => { expect(new Set(blocks.map((block) => block.type)).size).toBe(blocks.length); }); - it("requires the exact Studio gateway operation set", () => { - expect(Object.keys(gatewayWithEveryRequiredMethod()).sort()).toEqual( - [...gatewayMethodNames].sort(), - ); - }); - it("keeps RFC 9457-style gateway failures inspectable at the application boundary", () => { const error = new StudioGatewayError({ type: "https://techlog.dev/problems/conflict", title: "Conflict", status: 409, detail: "The working copy has changed.", - code: "DOCUMENT_VERSION_CONFLICT", + code: "VERSION_CONFLICT", retryable: false, }); expect(error).toMatchObject({ name: "StudioGatewayError", status: 409, - code: "DOCUMENT_VERSION_CONFLICT", + code: "VERSION_CONFLICT", retryable: false, }); expect(isStudioGatewayError(error)).toBe(true);