test: enforce exact TechLog contract keys

This commit is contained in:
DongHyeonka
2026-08-15 18:16:21 +09:00
parent 01ed1e9300
commit 82f94423e5
2 changed files with 39 additions and 59 deletions
+26 -40
View File
@@ -9,6 +9,13 @@ import type {
StudioGateway,
} from "../../../src/features/tech-log/application/ports/studio-gateway.ts";
type Equal<Left, Right> =
(<Value>() => Value extends Left ? 1 : 2) extends
(<Value>() => Value extends Right ? 1 : 2)
? true
: false;
type Assert<Condition extends true> = 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<keyof StudioGateway, RequiredStudioGatewayOperation>
>;
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);