106 lines
3.1 KiB
TypeScript
106 lines
3.1 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import type { Result } from "../../../src/contracts/result.ts";
|
|
import { createFailure, type ApiFailure } from "../../../src/contracts/errors.ts";
|
|
import {
|
|
createReferenceHttpGateway,
|
|
type ReferenceHttpBinding,
|
|
} from "../../../src/features/reference-feature/adapters/reference-http-gateway.ts";
|
|
import type { ReferenceResource } from "../../../src/features/reference-feature/domain/reference-resource.ts";
|
|
|
|
const resources = Object.freeze({
|
|
first: Object.freeze({
|
|
id: "reference-1",
|
|
displayName: "First",
|
|
createdAt: null,
|
|
}),
|
|
created: Object.freeze({
|
|
id: "reference-2",
|
|
displayName: "Created",
|
|
createdAt: "2026-07-26T00:00:00.000Z",
|
|
}),
|
|
}) satisfies Readonly<Record<string, ReferenceResource>>;
|
|
|
|
type ScriptedResult = Result<
|
|
ReferenceResource | readonly ReferenceResource[],
|
|
ApiFailure
|
|
>;
|
|
|
|
function scriptedBinding(results: ScriptedResult[]) {
|
|
const calls: Array<
|
|
readonly [operationId: string, input: unknown, context: unknown]
|
|
> = [];
|
|
let index = 0;
|
|
const execute = (async (
|
|
operationId: string,
|
|
input: unknown,
|
|
context?: unknown,
|
|
) => {
|
|
calls.push([operationId, input, context]);
|
|
const result = results[index];
|
|
index += 1;
|
|
if (!result) throw new Error("Missing scripted result");
|
|
return result;
|
|
}) as ReferenceHttpBinding["execute"];
|
|
|
|
return {
|
|
binding: Object.freeze({ execute }) satisfies ReferenceHttpBinding,
|
|
calls,
|
|
};
|
|
}
|
|
|
|
describe("reference HTTP operation gateway", () => {
|
|
it("delegates exact typed feature inputs to the capability binding", async () => {
|
|
const scripted = scriptedBinding([
|
|
{ ok: true, value: [resources.first] },
|
|
{ ok: true, value: resources.created },
|
|
{ ok: true, value: resources.first },
|
|
]);
|
|
const gateway = createReferenceHttpGateway(scripted.binding);
|
|
const signal = new AbortController().signal;
|
|
|
|
await expect(
|
|
gateway.list({ cursor: "next", limit: 20, tags: ["active"] }, { signal }),
|
|
).resolves.toEqual({ ok: true, value: [resources.first] });
|
|
await expect(
|
|
gateway.create({ name: "Created", note: "safe note" }),
|
|
).resolves.toEqual({ ok: true, value: resources.created });
|
|
await expect(
|
|
gateway.get("reference-1", { signal }),
|
|
).resolves.toEqual({ ok: true, value: resources.first });
|
|
|
|
expect(scripted.calls).toEqual([
|
|
[
|
|
"LIST_REFERENCE_RESOURCES",
|
|
{ cursor: "next", limit: 20, tags: ["active"] },
|
|
{ signal },
|
|
],
|
|
[
|
|
"CREATE_REFERENCE_RESOURCE",
|
|
{ name: "Created", note: "safe note" },
|
|
undefined,
|
|
],
|
|
[
|
|
"GET_REFERENCE_RESOURCE",
|
|
{ resourceId: "reference-1" },
|
|
{ signal },
|
|
],
|
|
]);
|
|
});
|
|
|
|
it("preserves a capability-normalized failure across the feature gateway", async () => {
|
|
const failure = createFailure(
|
|
"SCHEMA_MISMATCH",
|
|
"GET_REFERENCE_RESOURCE",
|
|
0,
|
|
);
|
|
const scripted = scriptedBinding([{ ok: false, error: failure }]);
|
|
const gateway = createReferenceHttpGateway(scripted.binding);
|
|
|
|
await expect(gateway.get("invalid")).resolves.toEqual({
|
|
ok: false,
|
|
error: failure,
|
|
});
|
|
});
|
|
});
|