148 lines
4.3 KiB
JavaScript
148 lines
4.3 KiB
JavaScript
import { describe, expect, it, vi } from "vitest";
|
|
|
|
import {
|
|
createRuntimeAdapters,
|
|
createRuntimeHttpClient,
|
|
} from "../../src/bootstrap/runtime-adapters.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,
|
|
});
|
|
|
|
await client.execute({
|
|
operationId: "LIST_SAMPLE_RESOURCES",
|
|
routeId: "SAMPLE_RESOURCE_LIST",
|
|
});
|
|
|
|
expect(fetcher).toHaveBeenCalledOnce();
|
|
expect(scheduler.setTimeout).toHaveBeenCalledWith(
|
|
expect.any(Function),
|
|
4321,
|
|
);
|
|
expect(scheduler.clearTimeout).toHaveBeenCalledOnce();
|
|
});
|
|
});
|