import { expect, test, type Page } from "@playwright/test"; async function setEditor(page: Page, testId: string, value: string) { await page.getByTestId(testId).locator(".cm-content").fill(value); } async function waitForReady(page: Page, timeout = 15_000) { await expect(page.locator(".run-status")).toHaveClass(/status-ready/u, { timeout, }); } test("CPython re executes and replaces with code-point-native offsets under the production CSP", async ({ page, }) => { const pageErrors: string[] = []; const consoleErrors: string[] = []; page.on("pageerror", (error) => pageErrors.push(error.message)); page.on("console", (message) => { if (message.type() === "error") consoleErrors.push(message.text()); }); const response = await page.goto("/deep/nested/regex/"); expect(response?.headers()["content-security-policy"]).toContain( "script-src 'self' 'wasm-unsafe-eval'", ); expect(response?.headers()["content-security-policy"]).not.toContain( "'unsafe-eval'", ); await waitForReady(page); await page.getByLabel("Live").uncheck(); await page.getByRole("combobox", { name: "Flavour" }).selectOption("python"); await setEditor(page, "editor-regular-expression-pattern", "(?P\\w+)"); await setEditor(page, "editor-test-text", "😀 café"); await page.getByRole("button", { name: "Run", exact: true }).click(); await waitForReady(page, 45_000); await expect(page.locator(".run-status")).toContainText( "native offsets code-point", ); const match = page.locator(".extraction-row").first(); await expect(match).toContainText("UTF-16 range: 3…7"); await expect(match).toContainText("native range: 2…6 code-point"); await page.getByRole("button", { name: "Replace", exact: true }).click(); await setEditor(page, "editor-replacement-template", "[\\g]"); await page.getByRole("button", { name: "Run", exact: true }).click(); await waitForReady(page, 45_000); await expect( page.getByTestId("editor-replacement-output").locator(".cm-content"), ).toHaveText("😀 [café]"); await page.getByRole("button", { name: "Quick reference" }).click(); await expect( page.getByRole("dialog", { name: "Quick reference" }), ).toContainText("Python 3.14 re documentation"); await page.keyboard.press("Escape"); await page.getByRole("button", { name: "Capabilities" }).click(); const capabilities = page.getByRole("dialog", { name: "Capabilities" }); await expect(capabilities).toContainText("CPython re via Pyodide"); await expect(capabilities).toContainText("CPython 3.14.2 re"); expect(pageErrors).toEqual([]); expect(consoleErrors).toEqual([]); }); test("TeaVM java.util.regex executes Java-only syntax and numeric replacement with UTF-16 offsets", async ({ page, }) => { const pageErrors: string[] = []; page.on("pageerror", (error) => pageErrors.push(error.message)); await page.goto("/deep/nested/regex/"); await waitForReady(page); await page.getByLabel("Live").uncheck(); await page.getByRole("combobox", { name: "Flavour" }).selectOption("java"); await setEditor( page, "editor-regular-expression-pattern", "(?[a-z]++)", ); await setEditor(page, "editor-test-text", "😀 abc"); await page.getByRole("button", { name: "Run", exact: true }).click(); await waitForReady(page); await expect(page.locator(".run-status")).toContainText( "native offsets utf16", ); const match = page.locator(".extraction-row").first(); await expect(match).toContainText("UTF-16 range: 3…6"); await expect(match).toContainText("native range: 3…6 utf16"); await page.getByRole("button", { name: "Replace", exact: true }).click(); await setEditor(page, "editor-replacement-template", "<$1>"); await page.getByRole("button", { name: "Run", exact: true }).click(); await waitForReady(page); await expect( page.getByTestId("editor-replacement-output").locator(".cm-content"), ).toHaveText("😀 "); await page.getByRole("button", { name: "Capabilities" }).click(); const capabilities = page.getByRole("dialog", { name: "Capabilities" }); await expect(capabilities).toContainText("TeaVM java.util.regex"); await expect(capabilities).toContainText("not OpenJDK"); expect(pageErrors).toEqual([]); }); test("serves the self-hosted Python and Java runtime assets with executable MIME types", async ({ request, }) => { const pythonModule = await request.get("./engines/python/pyodide.asm.mjs"); expect(pythonModule.ok()).toBe(true); expect(pythonModule.headers()["content-type"]).toContain("text/javascript"); const pythonWasm = await request.get("./engines/python/pyodide.asm.wasm"); expect(pythonWasm.ok()).toBe(true); expect(pythonWasm.headers()["content-type"]).toContain("application/wasm"); expect((await pythonWasm.body()).subarray(0, 4)).toEqual( Buffer.from([0x00, 0x61, 0x73, 0x6d]), ); const javaModule = await request.get("./engines/java/java-regex.mjs"); expect(javaModule.ok()).toBe(true); expect(javaModule.headers()["content-type"]).toContain("text/javascript"); });