Files
clean-architecture-frontend…/tests/unit/runtime-adapters.test.js

152 lines
4.4 KiB
JavaScript

import { describe, expect, it, vi } from "vitest";
import {
createRuntimeAdapters,
createRuntimeHttpClient,
} from "../../src/bootstrap/runtime-adapters.js";
import { TEST_HTTP_CONTRACT } from "../helpers/http-contract-fixture.js";
const runtime = {
config: {
APP_ENV: "local",
API_BASE_URL: "http://localhost:8080",
TELEMETRY_ENABLED: false,
AUTH_MODE: "demo",
REQUEST_TIMEOUT_MS: 4321,
MAX_RETRY_ATTEMPTS: 0,
RELEASE_MANIFEST_URL: "/release-manifest.json",
},
};
const release = /** @type {const} */ ({
schemaVersion: 1,
appVersion: "0.1.0",
buildId: "build-a",
commitSha: "abc123",
configSchemaVersion: "1",
apiContractVersion: "1",
assetManifestHash: "hash-a",
releaseId: "release-a",
builtAt: "2026-07-25T00:00:00Z",
routeChunks: { "route-home": "assets/home.js" },
});
describe("runtime adapter composition", () => {
it("constructs the local demo seam and infrastructure adapters", async () => {
const adapters = await createRuntimeAdapters({
runtime:
/** @type {Parameters<typeof createRuntimeAdapters>[0]["runtime"]} */ (
runtime
),
release,
host: {},
});
expect(adapters.outputPorts.session.getState()).toBe("unauthenticated");
await expect(adapters.outputPorts.releaseInfo.getCurrent()).resolves.toMatchObject({
releaseId: "release-a",
});
expect(adapters.infrastructure.queryClient).toBeDefined();
expect(adapters).not.toHaveProperty("http");
expect(adapters).not.toHaveProperty("storage");
});
it("fails closed when an external auth owner was not installed", async () => {
const adapters = await createRuntimeAdapters({
runtime:
/** @type {Parameters<typeof createRuntimeAdapters>[0]["runtime"]} */ ({
config: { ...runtime.config, AUTH_MODE: "external" },
}),
release,
host: {},
});
expect(adapters.outputPorts.session.getState()).toBe("integration-failed");
});
it("refetches the active release manifest with no-store semantics", async () => {
const activeRelease = {
...release,
buildId: "build-b",
releaseId: "release-b",
routeChunks: { "route-home": "assets/home-b.js" },
};
const fetcher = vi.fn(async () => Response.json(activeRelease));
const adapters = await createRuntimeAdapters({
runtime:
/** @type {Parameters<typeof createRuntimeAdapters>[0]["runtime"]} */ (
runtime
),
release,
fetcher,
host: {},
});
await expect(adapters.outputPorts.releaseInfo.refresh()).resolves.toMatchObject({
buildId: "build-b",
releaseId: "release-b",
});
expect(fetcher).toHaveBeenCalledWith("/release-manifest.json", {
cache: "no-store",
headers: { Accept: "application/json" },
});
});
it("injects runtime timeout and max-attempt policy into HTTP execution", async () => {
const scheduled =
/** @type {Array<{callback: () => void, milliseconds: number}>} */ ([]);
const scheduler = {
setTimeout: vi.fn((callback, milliseconds) => {
scheduled.push({ callback, milliseconds });
return scheduled.length;
}),
clearTimeout: vi.fn(),
};
const fetcher = vi.fn(async () =>
Response.json(
{
success: false,
error: { code: "TEMPORARY" },
meta: { requestId: "request-1", traceId: "trace-1" },
},
{ status: 503 },
),
);
const authSession =
(await createRuntimeAdapters({
runtime:
/** @type {Parameters<typeof createRuntimeAdapters>[0]["runtime"]} */ (
runtime
),
release,
host: {},
})).outputPorts.session;
const client = createRuntimeHttpClient(
{
runtime:
/** @type {Parameters<typeof createRuntimeHttpClient>[0]["runtime"]} */ (
runtime
),
authSession:
/** @type {import("../../src/application/ports/auth-session-port.js").AuthSessionPort} */ (
authSession
),
fetcher,
clock: { now: () => 0, sleep: async () => {} },
scheduler,
},
TEST_HTTP_CONTRACT,
);
await client.execute({
operationId: "LIST_ENTITIES",
routeId: "TEST_ROUTE",
});
expect(fetcher).toHaveBeenCalledOnce();
expect(scheduler.setTimeout).toHaveBeenCalledWith(
expect.any(Function),
4321,
);
expect(scheduler.clearTimeout).toHaveBeenCalledOnce();
});
});