chore: initialize from frontend template 4dc033c
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
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<string, string>;
|
||||
};
|
||||
|
||||
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<ReturnType<typeof release>>;
|
||||
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<DiagnosticsPort["record"]>();
|
||||
const emit = vi.fn<TelemetryPort["emit"]>();
|
||||
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();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user