import { expect, test, type Page } from "@playwright/test"; import { TextReader, Uint8ArrayReader, Uint8ArrayWriter, ZipWriter, } from "@zip.js/zip.js"; const ORIGIN = "http://127.0.0.1:4173"; async function localOnly(page: Page) { const external: string[] = []; await page.route("**/*", async (route) => { const url = new URL(route.request().url()); if (url.origin !== ORIGIN) { external.push(url.href); await route.abort(); } else await route.continue(); }); return external; } async function epubFixture(): Promise { const writer = new ZipWriter(new Uint8ArrayWriter()); await writer.add("mimetype", new TextReader("application/epub+zip"), { level: 0, }); await writer.add( "META-INF/container.xml", new TextReader( ``, ), ); await writer.add( "EPUB/package.opf", new TextReader( `urn:browser:testBrowser FixtureenLocal Author`, ), ); await writer.add( "EPUB/nav.xhtml", new TextReader( ``, ), ); await writer.add( "EPUB/title.xhtml", new TextReader( `Cover`, ), ); await writer.add( "EPUB/chapter.xhtml", new TextReader( `A safe chapter

Hello from EPUB

`, ), ); await writer.add( "EPUB/cover.png", new Uint8ArrayReader( Buffer.from( "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=", "base64", ), ), ); return Buffer.from(await writer.close()); } test("runs from a nested path without external requests", async ({ page }) => { const errors: string[] = []; page.on("pageerror", (error) => errors.push(error.message)); page.on("console", (message) => { if (message.type() === "error") errors.push(message.text()); }); const external = await localOnly(page); await page.goto("/deep/nested/epub/"); await expect(page.getByRole("heading", { name: "EPUB Tools" })).toBeVisible(); expect(external).toEqual([]); expect(errors).toEqual([]); }); test("serves the release identity and hardened headers", async ({ request, }) => { const index = await request.get("/deep/nested/epub/"); expect(index.ok()).toBe(true); expect(index.headers()["content-security-policy"]).toContain( "default-src 'self'", ); expect(await index.text()).not.toMatch(/\b(?:src|href)=["']\//u); const manifest = await request.get("/deep/nested/epub/toolbox-app.json"); await expect(manifest.json()).resolves.toMatchObject({ id: "de.add-ideas.epub-tools", version: "0.2.0", entry: "./", }); }); test("adapts Markdown locally and reports the resulting EPUB workspace", async ({ page, }) => { const external = await localOnly(page); await page.goto("/deep/nested/epub/"); await page.getByLabel("Choose publication").setInputFiles({ name: "local-notes.md", mimeType: "text/markdown", buffer: Buffer.from("# Local notes\n\nA **private** chapter."), }); await expect( page.getByText("Local notes", { exact: true }).first(), ).toBeVisible({ timeout: 30_000, }); await expect(page.getByText("MARKDOWN → EPUB workspace")).toBeVisible(); await expect( page .frameLocator("iframe[title^='Safe EPUB preview']") .getByRole("heading", { name: "Local notes" }), ).toBeVisible(); await page.getByRole("button", { name: "Validation" }).click(); await expect(page.getByText(/was converted locally into/iu)).toBeVisible(); expect(external).toEqual([]); }); test("opens, sanitizes, edits, rebuilds, and reopens a real EPUB", async ({ page, }) => { const external = await localOnly(page); await page.goto("/deep/nested/epub/"); await page.getByRole("button", { name: "Personalize" }).click(); await page.getByRole("button", { name: "Dark" }).click(); await page.getByLabel("Choose publication").setInputFiles({ name: "fixture.epub", mimeType: "application/epub+zip", buffer: await epubFixture(), }); await expect( page.getByText("Browser Fixture", { exact: true }).first(), ).toBeVisible({ timeout: 30_000 }); const reader = page.frameLocator("iframe[title^='Safe EPUB preview']"); const titleImage = reader.locator("svg image"); await expect(titleImage).toBeVisible(); expect( await titleImage.evaluate((element) => element.getAttributeNS("http://www.w3.org/1999/xlink", "href"), ), ).toMatch(/^blob:/u); await expect(reader.locator("html")).toHaveAttribute( "data-epub-reader-theme", "dark", ); await expect .poll(() => reader.locator("body").evaluate((element) => { const style = getComputedStyle(element); return [style.backgroundColor, style.color]; }), ) .toEqual(["rgb(23, 29, 45)", "rgb(237, 241, 251)"]); await page.getByRole("button", { name: /A safe chapter/u }).click(); await expect( reader.getByRole("heading", { name: "Hello from EPUB" }), ).toBeVisible(); await expect(reader.locator("script")).toHaveCount(0); await page.getByRole("button", { name: "Metadata" }).click(); await page.getByLabel("Title").fill("Updated in browser"); await page.getByRole("button", { name: "Export & rebuild" }).click(); const downloadPromise = page.waitForEvent("download"); await page.getByRole("button", { name: "Create updated EPUB" }).click(); const download = await downloadPromise; const path = await download.path(); expect(path).toBeTruthy(); await page.getByLabel("Open another").setInputFiles(path!); await expect( page.getByText("Updated in browser", { exact: true }).first(), ).toBeVisible({ timeout: 30_000 }); expect(external).toEqual([]); });