Files
pleno-vue/tests/unit/release-bootstrap.spec.js
T

240 lines
8.5 KiB
JavaScript

// @vitest-environment jsdom
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import {
RELEASE_RUNTIME_GLOBAL_KEY,
RELEASE_SOURCE_OVERRIDE_STORAGE_KEY,
bootstrapReleaseApp,
fetchReleaseRuntime,
loadRemoteReleaseEntry,
resolveReleaseSourceMode,
runtimeApiUrl,
shouldLoadRemoteRelease,
} from "@/services/releaseBootstrap.js";
import { DEFAULT_STABLE_API_URL } from "@/config.js";
describe("release bootstrap", () => {
beforeEach(() => {
localStorage.clear();
delete window[RELEASE_RUNTIME_GLOBAL_KEY];
});
afterEach(() => {
localStorage.clear();
delete window[RELEASE_RUNTIME_GLOBAL_KEY];
document.head.innerHTML = "";
vi.restoreAllMocks();
});
it("includes selected release channel in the runtime request", () => {
localStorage.setItem("release_channel_selected_slug", "Canary Preview!");
expect(runtimeApiUrl("https://api.truckwash.io")).toBe(
"https://api-v2.truckwash.io/canary-preview/api/release/runtime?release_channel=canary-preview"
);
});
it("routes stable runtime requests through the public master API prefix", () => {
localStorage.setItem("release_channel_selected_slug", "stable");
expect(runtimeApiUrl("https://api.truckwash.io")).toBe(
"https://api-v2.truckwash.io/master/api/release/runtime?release_channel=stable"
);
});
it("uses api-v2 master as the production default API", () => {
expect(DEFAULT_STABLE_API_URL).toBe("https://api-v2.truckwash.io/master/api");
expect(runtimeApiUrl(DEFAULT_STABLE_API_URL)).toBe("https://api-v2.truckwash.io/master/api/release/runtime");
});
it("resolves local dev API runtime requests against the current origin", () => {
expect(runtimeApiUrl("/api")).toBe(`${window.location.origin}/api/release/runtime`);
});
it("attaches release trace, channel, and frontend headers to runtime requests", async () => {
localStorage.setItem("release_trace_id", "trace-runtime");
localStorage.setItem("release_channel_selected_slug", "Internal");
const fetchFn = vi.fn(async () => ({
ok: true,
json: async () => ({ data: { channel: { slug: "internal" } } }),
}));
await fetchReleaseRuntime({ fetchFn, apiBaseUrl: "https://api.truckwash.io" });
const [url, options] = fetchFn.mock.calls[0];
expect(url).toBe("https://api-v2.truckwash.io/internal/api/release/runtime?release_channel=internal");
expect(options.headers).toMatchObject({
"X-Release-Trace": "trace-runtime",
"X-Release-Channel": "internal",
"X-Frontend-Version": expect.any(String),
});
});
it("loads the local app for the default channel", async () => {
const loadLocalApp = vi.fn(async () => ({ local: true }));
const fetchFn = vi.fn(async () => ({
ok: true,
json: async () => ({
data: {
channel: { slug: "stable", default_channel: true },
availability: { configured: true },
},
}),
}));
await bootstrapReleaseApp({ loadLocalApp, fetchFn, sourceMode: "deployment" });
expect(loadLocalApp).toHaveBeenCalledTimes(1);
expect(window[RELEASE_RUNTIME_GLOBAL_KEY].channel.slug).toBe("stable");
expect(window[RELEASE_RUNTIME_GLOBAL_KEY].source).toBe("deployment");
});
it("loads the local app without runtime or release entry requests in local source mode", async () => {
localStorage.setItem("release_channel_selected_slug", "internal");
const loadLocalApp = vi.fn(async () => ({ local: true }));
const fetchFn = vi.fn();
await bootstrapReleaseApp({ loadLocalApp, fetchFn, sourceMode: "local" });
expect(fetchFn).not.toHaveBeenCalled();
expect(loadLocalApp).toHaveBeenCalledTimes(1);
expect(window[RELEASE_RUNTIME_GLOBAL_KEY]).toMatchObject({
source: "local",
requested_source: "local",
channel: { slug: "stable", default_channel: true },
api_base_url: "/api",
urls: { api_base_url: "/api" },
availability: { configured: true, missing: [], status: "ready" },
});
});
it("allows storage to steer auto source mode without overriding explicit build source mode", () => {
localStorage.setItem(RELEASE_SOURCE_OVERRIDE_STORAGE_KEY, "deployment");
expect(resolveReleaseSourceMode("auto")).toBe("deployment");
expect(resolveReleaseSourceMode("local")).toBe("local");
expect(resolveReleaseSourceMode("local", { allowStorageOverride: true })).toBe("deployment");
});
it("loads the local unavailable app state when selected release runtime returns invalid JSON", async () => {
vi.spyOn(console, "warn").mockImplementation(() => {});
localStorage.setItem("release_channel_selected_slug", "internal");
const loadLocalApp = vi.fn(async () => ({ local: true }));
const fetchFn = vi.fn(async () => ({
ok: true,
text: async () => "<br /><b>Warning</b>Composer autoload warning",
}));
await bootstrapReleaseApp({ loadLocalApp, fetchFn, sourceMode: "deployment" });
expect(loadLocalApp).toHaveBeenCalledTimes(1);
expect(window[RELEASE_RUNTIME_GLOBAL_KEY]).toMatchObject({
channel: { slug: "internal", default_channel: false },
availability: {
configured: false,
missing: ["release_runtime"],
status: "unconfigured",
},
source: "local",
requested_source: "deployment",
});
expect(shouldLoadRemoteRelease(null)).toBe(false);
});
it("loads a non-default release entry without changing the browser URL", async () => {
const runtime = {
channel: { slug: "canary", default_channel: false },
availability: { configured: true },
urls: {
frontend_base_url: "https://api-v2.truckwash.io/canary/frontend",
api_base_url: "https://api-v2.truckwash.io/canary/api",
},
};
const fetchFn = vi
.fn()
.mockResolvedValueOnce({
ok: true,
json: async () => ({ data: runtime }),
})
.mockResolvedValueOnce({
ok: true,
json: async () => ({
entry: "assets/index-canary.js",
css: ["assets/index-canary.css"],
}),
});
const importModule = vi.fn(async (url) => ({ url }));
const originalHref = window.location.href;
await bootstrapReleaseApp({
loadLocalApp: vi.fn(),
fetchFn,
importModule,
documentRef: document,
sourceMode: "deployment",
});
expect(shouldLoadRemoteRelease(runtime)).toBe(true);
expect(importModule).toHaveBeenCalledWith("https://api-v2.truckwash.io/canary/frontend/assets/index-canary.js");
expect(document.querySelector("link")?.href).toBe(
"https://api-v2.truckwash.io/canary/frontend/assets/index-canary.css"
);
expect(window.location.href).toBe(originalHref);
});
it("falls back to the local app with unavailable runtime when the release entry fails", async () => {
vi.spyOn(console, "error").mockImplementation(() => {});
const loadLocalApp = vi.fn(async () => ({ local: true }));
const runtime = {
channel: { slug: "canary", default_channel: false },
availability: { configured: true },
frontend_base_url: "https://api-v2.truckwash.io/canary/frontend",
};
const fetchFn = vi
.fn()
.mockResolvedValueOnce({
ok: true,
json: async () => ({ data: runtime }),
})
.mockResolvedValueOnce({
ok: false,
status: 404,
});
await bootstrapReleaseApp({
loadLocalApp,
fetchFn,
importModule: vi.fn(),
documentRef: document,
sourceMode: "deployment",
});
expect(loadLocalApp).toHaveBeenCalledTimes(1);
expect(window[RELEASE_RUNTIME_GLOBAL_KEY].source).toBe("local");
expect(window[RELEASE_RUNTIME_GLOBAL_KEY].requested_source).toBe("deployment");
expect(window[RELEASE_RUNTIME_GLOBAL_KEY].availability).toMatchObject({
configured: false,
missing: ["frontend_entry"],
status: "unconfigured",
});
});
it("injects release entry CSS only once", async () => {
const fetchFn = vi.fn(async () => ({
ok: true,
json: async () => ({
entry: "assets/index-canary.js",
css: ["assets/index-canary.css"],
}),
}));
const importModule = vi.fn(async () => ({}));
const runtime = {
frontend_base_url: "https://api-v2.truckwash.io/canary/frontend",
};
await loadRemoteReleaseEntry({ runtime, fetchFn, importModule, documentRef: document });
await loadRemoteReleaseEntry({ runtime, fetchFn, importModule, documentRef: document });
expect(document.querySelectorAll("link[data-release-entry-css]")).toHaveLength(1);
});
});