import { expect, test, type Page } from "@playwright/test"; import { portFor } from "yt-dlp-transcript-common/lib/ports.mjs"; // Real two-origin federation. Origin B is a genuine static server sending // Access-Control-Allow-Origin (see globalSetup); the hub (baseURL) reads it over // the network, so these tests exercise the browser's REAL CORS enforcement and // the production service worker — the things route mocks can't. const B_PORT = portFor("ORIGIN_B_PORT"); const ORIGIN_B = `http://localhost:${B_PORT}`; async function addArchive(page: Page, url: string) { await page.getByLabel("Archive URL").fill(url); await page.getByRole("button", { name: "Add", exact: true }).click(); } test.describe("real two-origin federation (CORS + service worker)", () => { test("reads a cross-origin archive over real CORS and shelves it", async ({ page, }) => { await page.goto("/"); await expect( page.getByRole("heading", { level: 1, name: /searchable at once\./ }), ).toBeVisible(); await addArchive(page, ORIGIN_B); // The spine's title came from Origin B's /site.json, fetched cross-origin — // it only renders if the real CORS read succeeded. await expect( page.getByTestId("shelf-spine").filter({ hasText: "Origin B Archive" }), ).toBeVisible(); }); test("searches Origin B's transcripts across origins", async ({ page }) => { await page.goto("/"); await addArchive(page, ORIGIN_B); await expect( page.getByTestId("shelf-spine").filter({ hasText: "Origin B Archive" }), ).toBeVisible(); await page.getByTestId("query-builder").waitFor(); await page .locator('[data-testid^="leaf-scope-"]') .first() .selectOption({ label: "Transcripts" }); const input = page.locator('[data-testid^="leaf-query-"]').first(); await input.click(); await input.fill("hydrogen"); await input.press("Enter"); await page.waitForURL(/[?&]qt=/); // A hit for the video whose transcript cue contains "hydrogen" — this only // works if the hub fetched Origin B's summaries AND transcript pages over // CORS. Its slug is origin-qualified. const result = page.locator("[data-result-slug]").first(); await expect(result).toBeVisible({ timeout: 15_000 }); await expect(result).toHaveAttribute( "data-result-slug", new RegExp(`localhost:${B_PORT}`), ); }); test("service worker serves a cross-origin transcript shard offline", async ({ page, context, }) => { await page.goto("/"); // The prod build registers the SW; wait until it actually controls the page // (activate → clients.claim), so subsequent fetches route through it. await page.waitForFunction( () => !!navigator.serviceWorker?.controller, undefined, { timeout: 15_000 }, ); await addArchive(page, ORIGIN_B); await expect( page.getByTestId("shelf-spine").filter({ hasText: "Origin B Archive" }), ).toBeVisible(); // Run a transcript search to make the hub fetch Origin B's transcript page // cross-origin — the SW caches shard responses on first fetch. await page.getByTestId("query-builder").waitFor(); await page .locator('[data-testid^="leaf-scope-"]') .first() .selectOption({ label: "Transcripts" }); const input = page.locator('[data-testid^="leaf-query-"]').first(); await input.click(); await input.fill("hydrogen"); await input.press("Enter"); await expect(page.locator("[data-result-slug]").first()).toBeVisible({ timeout: 15_000, }); // Go offline and fetch the cross-origin shard directly: the SW must serve it // from cache (readable, CORS headers preserved) with no network. await context.setOffline(true); const shardUrl = `${ORIGIN_B}/transcripts/chan-b/page-0000.json`; const body = await page.evaluate(async (url) => { const res = await fetch(url); return { ok: res.ok, text: await res.text() }; }, shardUrl); expect(body.ok).toBe(true); expect(body.text).toContain("hydrogen"); }); });