Files
pleno-vue/tests/unit/frontend-maintenance.spec.js
T

128 lines
4.4 KiB
JavaScript

// @vitest-environment jsdom
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import {
__resetFrontendMaintenanceForTests,
forceFrontendUpdateAndClearLocal,
invalidateFrontendCachesAfterError,
} from "@/services/frontendMaintenance.js";
const installBrowserMaintenanceMocks = ({ indexedDatabaseNames = [] } = {}) => {
const deletedCaches = [];
const deletedIndexedDatabases = [];
const update = vi.fn(async () => true);
const unregister = vi.fn(async () => true);
const getRegistrations = vi.fn(async () => [{ update, unregister }]);
const caches = {
keys: vi.fn(async () => ["pleno-api-cache", "pleno-website-cache"]),
delete: vi.fn(async (cacheName) => {
deletedCaches.push(cacheName);
return true;
}),
};
const indexedDB = {
databases: vi.fn(async () => indexedDatabaseNames.map((name) => ({ name }))),
deleteDatabase: vi.fn((databaseName) => {
deletedIndexedDatabases.push(databaseName);
const request = {};
queueMicrotask(() => request.onsuccess?.());
return request;
}),
};
Object.defineProperty(window, "caches", {
configurable: true,
value: caches,
});
Object.defineProperty(navigator, "serviceWorker", {
configurable: true,
value: { getRegistrations },
});
Object.defineProperty(window, "indexedDB", {
configurable: true,
value: indexedDB,
});
return { caches, deletedCaches, deletedIndexedDatabases, getRegistrations, indexedDB, unregister, update };
};
describe("frontend maintenance", () => {
beforeEach(() => {
__resetFrontendMaintenanceForTests();
});
afterEach(() => {
__resetFrontendMaintenanceForTests();
vi.restoreAllMocks();
Reflect.deleteProperty(window, "caches");
Reflect.deleteProperty(window, "indexedDB");
Reflect.deleteProperty(navigator, "serviceWorker");
});
it("invalidates browser caches and asks service workers to update after frontend errors", async () => {
const mocks = installBrowserMaintenanceMocks();
const result = await invalidateFrontendCachesAfterError({ now: 1000 });
expect(result).toEqual({
skipped: false,
cacheNames: ["pleno-api-cache", "pleno-website-cache"],
serviceWorkerRegistrations: 1,
});
expect(mocks.deletedCaches).toEqual(["pleno-api-cache", "pleno-website-cache"]);
expect(mocks.update).toHaveBeenCalledTimes(1);
});
it("throttles repeated error cache invalidation", async () => {
const mocks = installBrowserMaintenanceMocks();
await invalidateFrontendCachesAfterError({ now: 1000 });
const result = await invalidateFrontendCachesAfterError({ now: 1500 });
expect(result.skipped).toBe(true);
expect(mocks.caches.keys).toHaveBeenCalledTimes(1);
expect(mocks.update).toHaveBeenCalledTimes(1);
});
it("clears all local state, unregisters service workers, clears caches, deletes IndexedDB, and reloads", async () => {
const mocks = installBrowserMaintenanceMocks({
indexedDatabaseNames: ["workbox-expiration", "truckwash-offline"],
});
const reload = vi.fn();
localStorage.setItem("token", "secret-token");
localStorage.setItem("draft", "local-value");
sessionStorage.setItem("draft", "value");
const result = await forceFrontendUpdateAndClearLocal({ reload });
expect(result.cacheNames).toEqual(["pleno-api-cache", "pleno-website-cache"]);
expect(result.indexedDatabaseNames).toEqual(["workbox-expiration", "truckwash-offline"]);
expect(mocks.unregister).toHaveBeenCalledTimes(1);
expect(mocks.deletedCaches).toEqual(["pleno-api-cache", "pleno-website-cache"]);
expect(mocks.deletedIndexedDatabases).toEqual(["workbox-expiration", "truckwash-offline"]);
expect(localStorage.getItem("token")).toBeNull();
expect(localStorage.getItem("draft")).toBeNull();
expect(sessionStorage.getItem("draft")).toBeNull();
expect(reload).toHaveBeenCalledTimes(1);
});
it("falls back to known IndexedDB names when database enumeration is unavailable", async () => {
const mocks = installBrowserMaintenanceMocks();
delete mocks.indexedDB.databases;
const result = await forceFrontendUpdateAndClearLocal({ reload: vi.fn() });
expect(result.indexedDatabaseNames).toEqual([
"workbox-expiration",
"workbox-background-sync",
"pleno",
"truckwash",
]);
expect(mocks.deletedIndexedDatabases).toEqual([
"workbox-expiration",
"workbox-background-sync",
"pleno",
"truckwash",
]);
});
});