import { expect, test } from "@playwright/test"; test("loads from a deep path and keeps the last valid projection while source is invalid", async ({ page, }) => { const pageErrors: string[] = []; page.on("pageerror", (error) => pageErrors.push(error.message)); await page.goto("/deep/nested/svg/"); await expect(page).toHaveTitle("SVG Tools"); await expect( page.getByText("Source synchronized", { exact: true }), ).toBeVisible(); await expect( page.getByRole("tree", { name: "SVG element structure" }), ).toBeVisible(); await expect(page.getByTitle("Sanitized SVG preview")).toHaveAttribute( "sandbox", "allow-scripts", ); const treeItems = page.getByRole("treeitem"); const initialTreeCount = await treeItems.count(); expect(initialTreeCount).toBeGreaterThan(1); await page .frameLocator('iframe[title="Sanitized SVG preview"]') .locator("#sun") .click(); await expect(page.locator('[data-node-key="id:sun"]')).toHaveAttribute( "aria-selected", "true", ); const source = page.locator(".cm-content"); await source.click(); await page.keyboard.press("Control+A"); // insertText bypasses CodeMirror's helpful XML close-tag completion so this // exercise really leaves the canonical source in an incomplete state. await page.keyboard.insertText(''); await expect(page.getByText("Source invalid", { exact: true })).toBeVisible(); await expect( page.getByText("Showing the last valid canvas revision."), ).toBeVisible(); expect(await treeItems.count()).toBe(initialTreeCount); await expect(page.getByRole("treeitem").first()).toBeVisible(); await expect( page.getByRole("button", { name: "Download SVG" }).last(), ).toBeDisabled(); await source.click(); await page.keyboard.press("Control+z"); await expect( page.getByText("Source synchronized", { exact: true }), ).toBeVisible(); expect(pageErrors).toEqual([]); }); test("synchronizes tree selection, source patches, undo and redo", async ({ page, }) => { await page.goto("/deep/nested/svg/"); await expect( page.getByText("Source synchronized", { exact: true }), ).toBeVisible(); await page.getByPlaceholder("Filter elements…").fill("path"); const pathRow = page.getByRole("treeitem").filter({ hasText: "path" }).last(); await pathRow.click(); await expect(pathRow).toHaveAttribute("aria-selected", "true"); await page.getByRole("button", { name: "Element" }).click(); const fill = page.getByLabel("Fill", { exact: true }); await fill.fill("#123456"); await fill.press("Enter"); await expect(page.locator(".cm-content")).toContainText('fill="#123456"'); await page.getByRole("button", { name: "Undo" }).click(); await expect(page.locator(".cm-content")).not.toContainText('fill="#123456"'); await page.getByRole("button", { name: "Redo" }).click(); await expect(page.locator(".cm-content")).toContainText('fill="#123456"'); }); test("duplicates and deletes ID-free nodes while protecting referenced IDs", async ({ page, }) => { await page.goto("/deep/nested/svg/"); await page.getByPlaceholder("Filter elements…").fill("stop"); await page.getByRole("treeitem").filter({ hasText: "stop" }).first().click(); await page.getByRole("button", { name: "Element" }).click(); await page.getByRole("button", { name: "Duplicate element" }).click(); await expect(page.locator(".cm-content")).toContainText( /stop-color="#725cff"[\s\S]*stop-color="#725cff"/u, ); await page.getByRole("button", { name: "Delete element" }).click(); await expect(page.locator(".cm-content")).not.toContainText( /stop-color="#725cff"[\s\S]*stop-color="#725cff"/u, ); await page.getByPlaceholder("Filter elements…").fill("sun"); await page.getByRole("treeitem").filter({ hasText: "sun" }).click(); await page.getByRole("button", { name: "Duplicate element" }).click(); await expect(page.locator(".workbench-footer")).toContainText( /Duplicate is refused/u, ); }); test("connects to a valid same-origin Toolbox catalogue from the nested build", async ({ page, }) => { await page.goto("/deep/nested/svg/?toolbox=%2Ftoolbox.catalog.json"); await expect( page.getByText("Source synchronized", { exact: true }), ).toBeVisible(); await expect(page.locator(".toolbox-shell")).toHaveAttribute( "data-toolbox-context", "connected", ); await page.getByRole("button", { name: "Apps" }).click(); const switcher = page.getByRole("navigation", { name: "Toolbox applications", }); await expect(switcher).toBeVisible(); await expect( switcher.getByRole("link", { name: "SVG Tools" }), ).toHaveAttribute("aria-current", "page"); }); test("opens hostile SVG locally without executing scripts or fetching external URLs", async ({ page, }) => { const forbiddenRequests: string[] = []; let executed = false; page.on("request", (request) => { if (request.url().includes("invalid.example")) forbiddenRequests.push(request.url()); }); await page.exposeFunction("svgToolsExecuted", () => { executed = true; }); await page.goto("/deep/nested/svg/"); const hostile = ` `; await page.locator('input[type="file"]').evaluate((element, contents) => { const transfer = new DataTransfer(); transfer.items.add( new File([contents], "hostile.svg", { type: "image/svg+xml" }), ); (element as HTMLInputElement).files = transfer.files; element.dispatchEvent(new Event("change", { bubbles: true })); }, hostile); await expect( page.getByText("Source synchronized", { exact: true }), ).toBeVisible(); await expect( page.getByText(/blocked-script|event-handler|unsafe-url/).first(), ).toBeVisible(); const frame = page.frameLocator('iframe[title="Sanitized SVG preview"]'); await expect(frame.locator("script")).toHaveCount(0); await expect(frame.locator("image")).not.toHaveAttribute( "href", /invalid\.example/u, ); expect(executed).toBe(false); expect(forbiddenRequests).toEqual([]); });