import { describe, expect, it, vi } from "vitest"; import { createApplication } from "../../src/application/create-application.ts"; import { createAnonymousSessionAdapter } from "../../src/adapters/auth/external-session-adapter.ts"; import type { StoragePort } from "../../src/application/ports/storage-port.ts"; import type { DiagnosticsPort } from "../../src/application/ports/diagnostics-port.ts"; import type { TelemetryPort } from "../../src/application/ports/telemetry-port.ts"; import { createRuntimeCapabilitiesStub } from "../helpers/runtime-capabilities-stub.ts"; type ReleaseFixture = { buildId: string; releaseId: string; configSchemaVersion: string; apiContractVersion: string; assetManifestHash: string; routeChunks: Record; }; function release(buildId: string, releaseId: string): ReleaseFixture { return { buildId, releaseId, configSchemaVersion: "1", apiContractVersion: "1", assetManifestHash: `${buildId}-assets`, routeChunks: { "route-home": `assets/${buildId}-home.js` }, }; } function memoryStorage(): StoragePort { let value: unknown; return { read: () => ({ ok: true, value }), write: (_name, next) => { value = next; return { ok: true }; }, remove: () => ({ ok: true }), }; } function applicationWith(options: { storage?: StoragePort; refresh?: () => Promise>; reload?: () => void; diagnostics?: DiagnosticsPort; telemetry?: TelemetryPort; }) { const current = release("build-a", "release-a"); return createApplication({ session: createAnonymousSessionAdapter(), preferences: options.storage ?? memoryStorage(), diagnostics: options.diagnostics ?? { record: () => {} }, telemetry: options.telemetry ?? { emit: () => {} }, runtimeCapabilities: createRuntimeCapabilitiesStub(), releaseInfo: { getCurrent: async () => current, refresh: options.refresh ?? (async () => release("build-b", "release-b")), }, navigation: { reload: options.reload ?? (() => {}) }, }); } describe("production chunk recovery application input", () => { it("reloads exactly once for one active build/release pair", async () => { const reload = vi.fn(); const record = vi.fn(); const emit = vi.fn(); const application = applicationWith({ reload, diagnostics: { record }, telemetry: { emit }, }); const input = { chunkId: "route-home", failureKind: "CHUNK_LOAD_FAILURE" as const, }; await expect(application.recovery.recoverChunk(input)).resolves.toEqual({ action: "reload-once", releasePair: "build-a/release-a->build-b/release-b", }); expect(record).toHaveBeenCalledWith({ level: "warn", eventId: "release.mismatch.detected", context: { build_id: "build-a", active_release_id: "release-b", mismatch_kind: "BUILD_MISMATCH", }, }); expect(emit).toHaveBeenCalledWith("release.mismatch.detected", { build_id: "build-a", active_release_id: "release-b", mismatch_kind: "BUILD_MISMATCH", }); await expect(application.recovery.recoverChunk(input)).resolves.toEqual({ action: "support", reason: "reload-already-attempted", }); expect(reload).toHaveBeenCalledOnce(); }); it.each([ [ { refresh: async () => { throw new Error("offline"); }, }, "manifest-unavailable", ], [ { refresh: async () => ({ ...release("build-b", "release-b"), routeChunks: {}, }), }, "active-chunk-unknown", ], [ { storage: { read: () => ({ ok: false as const, error: { kind: "STORAGE_UNAVAILABLE" as const, code: "STORAGE_UNAVAILABLE", retryable: false, operationId: "STORAGE", attemptCount: 1, userMessageKey: "error.storage_unavailable", action: "none" as const, }, }), write: () => ({ ok: true as const }), remove: () => ({ ok: true as const }), }, }, "guard-read-failed", ], ])("fails closed for recovery dependency case %#", async (options, reason) => { const reload = vi.fn(); const application = applicationWith({ ...options, reload }); await expect( application.recovery.recoverChunk({ chunkId: "route-home", failureKind: "CHUNK_LOAD_FAILURE", }), ).resolves.toEqual({ action: "support", reason }); expect(reload).not.toHaveBeenCalled(); }); });