// A Service Worker registered with a scope narrower than the runtime's "/" wins the // pages under it, so the runtime's /~/ URLs never reach its own worker. boot() must // refuse by name instead of letting every process crash, and the old /demo/ probe // registration (which did exactly this to every demo page) must remove itself. import { test, expect } from "@playwright/test"; import { cacheTarballs } from "./tarball-cache"; // The demo app installs from its lockfile; tarballs come from the cache, not the network. test.beforeEach(async ({ context }) => cacheTarballs(context)); test("boot() refuses with ServiceWorkerShadowedError when another worker controls the page", async ({ page }) => { await page.goto("/tests/fixtures/shadow/"); await expect(page.locator("#result")).toContainText("ServiceWorkerShadowedError", { timeout: 20_000 }); await expect(page.locator("#result")).toContainText("/tests/fixtures/shadow/sw.js"); await expect(page.locator("#result")).toContainText("[ERR_NIB_SW_SHADOWED]"); }); test("a leftover /demo/ probe registration removes itself and the demo app runs", async ({ page }) => { await page.goto("/demo/fixture.html"); await page.evaluate(async () => { await navigator.serviceWorker.register("/demo/sw.js", { scope: "/demo/" }); }); await expect.poll( () => page.evaluate(async () => (await navigator.serviceWorker.getRegistrations()).map((r) => new URL(r.scope).pathname)), { timeout: 20_000 }, ).not.toContain("/demo/"); await page.goto("/demo/app.html?app=hono"); await expect(page.frameLocator("iframe").locator("#hi")).toHaveText("Hello from Hono", { timeout: 30_000 }); expect(await page.evaluate(() => new URL(navigator.serviceWorker.controller!.scriptURL).pathname)).toBe("/dist/runtime/sw.js"); });