127 lines
4.1 KiB
TypeScript
127 lines
4.1 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import type { components } from "../../../src/features/tech-log/contracts/studio/generated.ts";
|
|
import {
|
|
isStudioGatewayError,
|
|
StudioGatewayError,
|
|
} from "../../../src/features/tech-log/application/ports/studio-gateway-error.ts";
|
|
import type {
|
|
StudioGateway,
|
|
} from "../../../src/features/tech-log/application/ports/studio-gateway.ts";
|
|
|
|
type Inline = components["schemas"]["Inline"];
|
|
type CaseRenderBlock = components["schemas"]["CaseRenderBlock"];
|
|
|
|
const inlines: Inline[] = [
|
|
{ type: "TEXT", text: "plain" },
|
|
{ type: "EMPHASIS", children: [{ type: "TEXT", text: "emphasis" }] },
|
|
{ type: "STRONG", children: [{ type: "TEXT", text: "strong" }] },
|
|
{ type: "INLINE_CODE", code: "findById" },
|
|
{ type: "LINK", label: "TechLog", href: "https://example.com" },
|
|
{ type: "STATUS", label: "검증 필요", tone: "warning" },
|
|
];
|
|
|
|
const blocks: CaseRenderBlock[] = [
|
|
{ type: "HEADING", id: "problem", level: 2, content: [] },
|
|
{ type: "PARAGRAPH", content: [] },
|
|
{ type: "BLOCKQUOTE", content: [] },
|
|
{ type: "UNORDERED_LIST", items: [] },
|
|
{ type: "ORDERED_LIST", items: [] },
|
|
{ type: "CODE_BLOCK", code: "select 1", language: "sql", label: null },
|
|
{
|
|
type: "DATA_TABLE",
|
|
id: "query-counts",
|
|
caption: "Query counts",
|
|
rowHeaderColumn: null,
|
|
columns: [{ id: "query-counts-column-1", label: "Case", alignment: "LEFT" }],
|
|
rows: [],
|
|
},
|
|
{ type: "CALLOUT", tone: "warning", label: "주의", content: [] },
|
|
{ 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;
|
|
|
|
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,
|
|
};
|
|
}
|
|
|
|
describe("TechLog Studio contracts", () => {
|
|
it("preserves every public wire discriminator exactly once", () => {
|
|
expect(inlines.map((inline) => inline.type)).toEqual([
|
|
"TEXT",
|
|
"EMPHASIS",
|
|
"STRONG",
|
|
"INLINE_CODE",
|
|
"LINK",
|
|
"STATUS",
|
|
]);
|
|
expect(blocks.map((block) => block.type)).toEqual([
|
|
"HEADING",
|
|
"PARAGRAPH",
|
|
"BLOCKQUOTE",
|
|
"UNORDERED_LIST",
|
|
"ORDERED_LIST",
|
|
"CODE_BLOCK",
|
|
"DATA_TABLE",
|
|
"CALLOUT",
|
|
"EVIDENCE_FIGURE",
|
|
]);
|
|
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",
|
|
retryable: false,
|
|
});
|
|
|
|
expect(error).toMatchObject({
|
|
name: "StudioGatewayError",
|
|
status: 409,
|
|
code: "DOCUMENT_VERSION_CONFLICT",
|
|
retryable: false,
|
|
});
|
|
expect(isStudioGatewayError(error)).toBe(true);
|
|
expect(isStudioGatewayError(new DOMException("Aborted", "AbortError"))).toBe(false);
|
|
});
|
|
});
|