import { expect, test } from "bun:test"; import { generateServiceWorker } from "../src/index.ts"; function worker(fetcher: (r: any) => Promise, failStore = false) { const listeners: Record void> = {}; const saved: string[] = []; const cache = { match: async () => undefined, put: async (r: any) => { if (failStore) throw Error("quota"); saved.push(r.url); }, }; const self = { location: { origin: "https://account.example.test" }, addEventListener: (name: string, fn: (event: any) => void) => (listeners[name] = fn), skipWaiting() {}, clients: { claim: async () => {} }, }; new Function("self", "caches", "fetch", generateServiceWorker())( self, { open: async () => cache, keys: async () => [], delete: async () => true }, fetcher, ); return { saved, async fetch(path: string, mode = "cors") { let result: Promise | undefined; const req = new Request(new URL(path, self.location.origin)); Object.defineProperty(req, "mode", { value: mode }); listeners.fetch({ request: req, respondWith: (r: Promise) => (result = r), waitUntil: () => {}, }); return result; }, }; } test("handoffs and API calls bypass service worker interception", async () => { const w = worker(async () => { throw Error("must not intercept"); }); expect(await w.fetch("/organization-add?sso_code=one-time")).toBeUndefined(); expect(await w.fetch("/api/account")).toBeUndefined(); }); test("private responses and navigations never enter cache", async () => { const w = worker( async () => new Response("private", { headers: { "cache-control": "private, no-store" } }), ); expect(await (await w.fetch("/profile"))?.text()).toBe("private"); expect(w.saved).toEqual([]); const nav = worker(async () => new Response("personal page")); await nav.fetch("/profile", "navigate"); expect(nav.saved).toEqual([]); }); test("cache quota errors do not turn successful requests into network errors", async () => { const w = worker(async () => new Response("asset"), true); expect(await (await w.fetch("/app.js"))?.text()).toBe("asset"); }); test("offline without a cached fallback always returns a Response", async () => { const w = worker(async () => { throw Error("offline"); }); expect((await w.fetch("/profile", "navigate"))?.status).toBe(503); }); test("public static assets remain cacheable", async () => { const w = worker( async () => new Response("asset", { headers: { "cache-control": "public, max-age=3600" } }), ); await w.fetch("/app.js"); expect(w.saved).toHaveLength(1); });