refactor: 리펙토링
This commit is contained in:
@@ -4,6 +4,8 @@ import {
|
||||
createRuntimeAdapters,
|
||||
createRuntimeHttpClient,
|
||||
} from "../../src/bootstrap/runtime-adapters.ts";
|
||||
import { QUERY_REGISTRY } from "../../src/features/installed-feature-contracts.ts";
|
||||
import { REFERENCE_FEATURE_ID } from "../../src/features/reference-feature/contracts/reference-feature-contract.ts";
|
||||
import { TEST_HTTP_CONTRACT } from "../helpers/http-contract-fixture.ts";
|
||||
|
||||
type Runtime = Parameters<typeof createRuntimeAdapters>[0]["runtime"];
|
||||
@@ -18,9 +20,15 @@ const runtime: Runtime = {
|
||||
REQUEST_TIMEOUT_MS: 4321,
|
||||
MAX_RETRY_ATTEMPTS: 0,
|
||||
RELEASE_MANIFEST_URL: "/release-manifest.json",
|
||||
CONFIG_SCHEMA_VERSION: "1",
|
||||
API_CONTRACT_VERSION: "1",
|
||||
CONFIG_SCHEMA_VERSION: "2.0",
|
||||
CAPABILITY_OVERRIDES: {
|
||||
REALTIME: "DEFAULT",
|
||||
WEB_WORKER: "DEFAULT",
|
||||
SERVICE_WORKER: "DEFAULT",
|
||||
OFFLINE_COMMANDS: "DEFAULT",
|
||||
},
|
||||
},
|
||||
configSchema: "V2",
|
||||
build: {
|
||||
buildId: "build-a",
|
||||
commitSha: "abc123",
|
||||
@@ -30,12 +38,16 @@ const runtime: Runtime = {
|
||||
validationDurationMs: 0,
|
||||
};
|
||||
const release: Release = {
|
||||
schemaVersion: 1,
|
||||
schemaVersion: 2,
|
||||
appVersion: "0.1.0",
|
||||
buildId: "build-a",
|
||||
commitSha: "abc123",
|
||||
configSchemaVersion: "1",
|
||||
apiContractVersion: "1",
|
||||
configSchemaVersion: "2.0",
|
||||
contractSet: {
|
||||
setAlgorithm: "CA_CONTRACT_SET_V1",
|
||||
setDigest: `sha256:${"0".repeat(64)}`,
|
||||
packages: [],
|
||||
},
|
||||
assetManifestHash: "hash-a",
|
||||
releaseId: "release-a",
|
||||
builtAt: "2026-07-25T00:00:00Z",
|
||||
@@ -67,6 +79,67 @@ describe("runtime adapter composition", () => {
|
||||
adapters.infrastructure.dispose();
|
||||
});
|
||||
|
||||
it("executes installed feature HTTP through the composed contract registry", async () => {
|
||||
const fetcher = vi.fn(async () =>
|
||||
Response.json([{ id: "reference-1", name: "Direct contract payload" }]),
|
||||
);
|
||||
const adapters = await createRuntimeAdapters({
|
||||
runtime,
|
||||
release,
|
||||
host: {},
|
||||
fetcher,
|
||||
});
|
||||
await adapters.outputPorts.session.beginSignIn();
|
||||
await vi.waitFor(() =>
|
||||
expect(adapters.infrastructure.serverStateScope.getPhase()).toBe("READY"),
|
||||
);
|
||||
|
||||
await expect(
|
||||
adapters.featureInputs[REFERENCE_FEATURE_ID].listResources({ limit: 20 }),
|
||||
).resolves.toEqual({
|
||||
ok: true,
|
||||
value: [
|
||||
{
|
||||
resourceId: "reference-1",
|
||||
title: "Direct contract payload",
|
||||
createdAt: null,
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(fetcher).toHaveBeenCalledWith(
|
||||
"http://localhost:8080/api/reference-resources?limit=20",
|
||||
expect.objectContaining({
|
||||
method: "GET",
|
||||
redirect: "error",
|
||||
cache: "no-store",
|
||||
}),
|
||||
);
|
||||
adapters.infrastructure.dispose();
|
||||
});
|
||||
|
||||
it("replaces the QueryClient and coordinator for each session generation", async () => {
|
||||
const adapters = await createRuntimeAdapters({ runtime, release, host: {} });
|
||||
const previousClient = adapters.infrastructure.queryClient;
|
||||
const previousCoordinator = adapters.infrastructure.queryInvalidation;
|
||||
const invalidatePrevious = vi.spyOn(previousClient, "invalidateQueries");
|
||||
|
||||
await adapters.outputPorts.session.beginSignIn();
|
||||
|
||||
await vi.waitFor(() =>
|
||||
expect(adapters.infrastructure.queryClient).not.toBe(previousClient),
|
||||
);
|
||||
expect(adapters.infrastructure.queryInvalidation).not.toBe(
|
||||
previousCoordinator,
|
||||
);
|
||||
|
||||
const topic = Object.values(QUERY_REGISTRY)[0]?.invalidationTopic;
|
||||
if (!topic) throw new Error("expected an installed invalidation topic");
|
||||
await previousCoordinator.invalidate([topic]);
|
||||
expect(invalidatePrevious).not.toHaveBeenCalled();
|
||||
|
||||
adapters.infrastructure.dispose();
|
||||
});
|
||||
|
||||
it("does not fail boot when Web Storage capability getters throw", async () => {
|
||||
const host: Record<string, unknown> = {};
|
||||
Object.defineProperties(host, {
|
||||
@@ -108,6 +181,73 @@ describe("runtime adapter composition", () => {
|
||||
expect(adapters.outputPorts.session.getState()).toBe("integration-failed");
|
||||
});
|
||||
|
||||
it("reports the static selection when no capability override disables it", async () => {
|
||||
const adapters = await createRuntimeAdapters({ runtime, release, host: {} });
|
||||
|
||||
const snapshot = adapters.outputPorts.runtimeCapabilities.getSnapshot();
|
||||
|
||||
expect(snapshot.map((status) => status.capabilityId)).toEqual([
|
||||
"REALTIME",
|
||||
"WEB_WORKER",
|
||||
"SERVICE_WORKER",
|
||||
"OFFLINE_COMMANDS",
|
||||
]);
|
||||
expect(snapshot.every((status) => status.override === "DEFAULT")).toBe(true);
|
||||
});
|
||||
|
||||
it("carries a disabling override into the capability snapshot", async () => {
|
||||
const adapters = await createRuntimeAdapters({
|
||||
runtime: {
|
||||
...runtime,
|
||||
config: {
|
||||
...runtime.config,
|
||||
CAPABILITY_OVERRIDES: {
|
||||
...runtime.config.CAPABILITY_OVERRIDES,
|
||||
SERVICE_WORKER: "DISABLED",
|
||||
},
|
||||
},
|
||||
},
|
||||
release,
|
||||
host: {},
|
||||
});
|
||||
|
||||
const serviceWorker = adapters.outputPorts.runtimeCapabilities
|
||||
.getSnapshot()
|
||||
.find((status) => status.capabilityId === "SERVICE_WORKER");
|
||||
|
||||
expect(serviceWorker?.override).toBe("DISABLED");
|
||||
expect(serviceWorker?.active).toBe(0);
|
||||
});
|
||||
|
||||
it("states contract identity as a digest for a V2 release manifest", async () => {
|
||||
const adapters = await createRuntimeAdapters({ runtime, release, host: {} });
|
||||
|
||||
const current = await adapters.outputPorts.releaseInfo.getCurrent();
|
||||
|
||||
expect(current.contractSetDigest).toBe(release.contractSet?.setDigest);
|
||||
expect(current.apiContractVersion).toBeUndefined();
|
||||
expect(current).not.toHaveProperty("contractSet");
|
||||
});
|
||||
|
||||
it("states contract identity as the legacy scalar for a V1 release manifest", async () => {
|
||||
const adapters = await createRuntimeAdapters({
|
||||
runtime,
|
||||
release: {
|
||||
...release,
|
||||
schemaVersion: 1,
|
||||
contractSet: null,
|
||||
legacyApiContractVersion: "1.4",
|
||||
},
|
||||
host: {},
|
||||
});
|
||||
|
||||
const current = await adapters.outputPorts.releaseInfo.getCurrent();
|
||||
|
||||
expect(current.apiContractVersion).toBe("1.4");
|
||||
expect(current.contractSetDigest).toBeUndefined();
|
||||
expect(current).not.toHaveProperty("legacyApiContractVersion");
|
||||
});
|
||||
|
||||
it("refetches the active release manifest with no-store semantics", async () => {
|
||||
const activeRelease = {
|
||||
...release,
|
||||
@@ -115,7 +255,11 @@ describe("runtime adapter composition", () => {
|
||||
releaseId: "release-b",
|
||||
routeChunks: { "route-home": "assets/home-b.js" },
|
||||
};
|
||||
const fetcher = vi.fn(async () => Response.json(activeRelease));
|
||||
const fetcher = vi.fn(async () =>
|
||||
new Response(JSON.stringify(activeRelease), {
|
||||
headers: { "content-type": "application/json" },
|
||||
}),
|
||||
);
|
||||
const adapters = await createRuntimeAdapters({
|
||||
runtime,
|
||||
release,
|
||||
@@ -127,10 +271,17 @@ describe("runtime adapter composition", () => {
|
||||
buildId: "build-b",
|
||||
releaseId: "release-b",
|
||||
});
|
||||
expect(fetcher).toHaveBeenCalledWith("/release-manifest.json", {
|
||||
cache: "no-store",
|
||||
headers: { Accept: "application/json" },
|
||||
});
|
||||
expect(fetcher).toHaveBeenCalledWith(
|
||||
"/release-manifest.json",
|
||||
expect.objectContaining({
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
credentials: "same-origin",
|
||||
redirect: "error",
|
||||
referrerPolicy: "no-referrer",
|
||||
headers: { Accept: "application/json" },
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("injects runtime timeout and max-attempt policy into HTTP execution", async () => {
|
||||
|
||||
Reference in New Issue
Block a user