From 4049be59071068953e6760fde60a93f023d68a33 Mon Sep 17 00:00:00 2001 From: Seydi Charyyev Date: Mon, 10 Aug 2026 10:42:36 +0500 Subject: [PATCH] test(desktop): make the Playwright e2e suite runnable on Windows Two separate defects stopped the desktop e2e suite on a stock Windows box. The webServer command hardcoded `python3`. On Windows that name is normally the Microsoft Store app-execution alias, which prints an install hint and exits 9009 even when a real interpreter is installed as `python`. Playwright reports only "Process from config.webServer was not able to start. Exit code: 9009", so no test runs at all. Both Playwright configs now probe for an interpreter that actually answers. Linux and macOS still try `python3` first, so the command they run is unchanged. The code-block copy test compared the clipboard to a LF string. Chromium returns CRLF when it reads text/plain off the Windows clipboard, so the assertion could not hold there. The app is not at fault: it writes `code` into the text/plain blob verbatim. The test now compares logical lines. Signed-off-by: Seydi Charyyev --- desktop/playwright.config.ts | 9 ++---- desktop/playwright.perf.config.ts | 9 ++---- desktop/tests/e2e/messaging.spec.ts | 11 ++++++- desktop/tests/helpers/staticWebServer.ts | 40 ++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 13 deletions(-) create mode 100644 desktop/tests/helpers/staticWebServer.ts diff --git a/desktop/playwright.config.ts b/desktop/playwright.config.ts index c1ea0e061b..45c67bff61 100644 --- a/desktop/playwright.config.ts +++ b/desktop/playwright.config.ts @@ -1,5 +1,7 @@ import { defineConfig, devices } from "@playwright/test"; +import { staticWebServer } from "./tests/helpers/staticWebServer"; + export default defineConfig({ testDir: "./tests/e2e", timeout: 30_000, @@ -174,10 +176,5 @@ export default defineConfig({ }, }, ], - webServer: { - command: "python3 -m http.server 4173 -d dist", - cwd: ".", - reuseExistingServer: !process.env.CI, - url: "http://127.0.0.1:4173", - }, + webServer: staticWebServer({ reuseExistingServer: !process.env.CI }), }); diff --git a/desktop/playwright.perf.config.ts b/desktop/playwright.perf.config.ts index 6fde2c28f8..2356d805d3 100644 --- a/desktop/playwright.perf.config.ts +++ b/desktop/playwright.perf.config.ts @@ -1,5 +1,7 @@ import { defineConfig, devices } from "@playwright/test"; +import { staticWebServer } from "./tests/helpers/staticWebServer"; + export default defineConfig({ testDir: "./tests/e2e", timeout: 60_000, @@ -14,10 +16,5 @@ export default defineConfig({ use: { ...devices["Desktop Chrome"] }, }, ], - webServer: { - command: "python3 -m http.server 4173 -d dist", - cwd: ".", - reuseExistingServer: true, - url: "http://127.0.0.1:4173", - }, + webServer: staticWebServer({ reuseExistingServer: true }), }); diff --git a/desktop/tests/e2e/messaging.spec.ts b/desktop/tests/e2e/messaging.spec.ts index a0808e4a6a..56aa94283d 100644 --- a/desktop/tests/e2e/messaging.spec.ts +++ b/desktop/tests/e2e/messaging.spec.ts @@ -993,8 +993,17 @@ test("copy a rendered code block and paste it back as code", async ({ await codeBlock.hover(); await expect(copyButton).toHaveCSS("opacity", "1"); await copyButton.click(); + // Chromium hands back CRLF when it reads text/plain off the Windows + // clipboard, so compare logical lines rather than the platform separator. + // The app writes LF: `copyCodeBlockToClipboard` puts `code` in the blob + // verbatim. await expect - .poll(() => page.evaluate(() => navigator.clipboard.readText())) + .poll(async () => + (await page.evaluate(() => navigator.clipboard.readText())).replace( + /\r\n/g, + "\n", + ), + ) .toBe(code); await input.click(); diff --git a/desktop/tests/helpers/staticWebServer.ts b/desktop/tests/helpers/staticWebServer.ts new file mode 100644 index 0000000000..e588f6fd96 --- /dev/null +++ b/desktop/tests/helpers/staticWebServer.ts @@ -0,0 +1,40 @@ +import { spawnSync } from "node:child_process"; + +const PORT = 4173; + +/** + * `python3` is the right name on Linux and macOS. On Windows it is normally + * the Microsoft Store app-execution alias, which prints an install hint and + * exits 9009 even when a real interpreter is installed as `python`. Playwright + * then reports only `Process from config.webServer was not able to start. + * Exit code: 9009`, so the suite cannot be run at all on a stock Windows box. + * + * Probe the candidates rather than guessing. `-c ""` is a no-op that a real + * interpreter accepts and the alias stub rejects. + */ +function resolvePythonCommand() { + const candidates = + process.platform === "win32" + ? ["python", "python3"] + : ["python3", "python"]; + + for (const candidate of candidates) { + const probe = spawnSync(candidate, ["-c", ""], { stdio: "ignore" }); + if (!probe.error && probe.status === 0) { + return candidate; + } + } + + // Nothing answered. Keep the historical name so the failure still points at + // the missing interpreter instead of at this helper. + return "python3"; +} + +export function staticWebServer(options: { reuseExistingServer: boolean }) { + return { + command: `${resolvePythonCommand()} -m http.server ${PORT} -d dist`, + cwd: ".", + reuseExistingServer: options.reuseExistingServer, + url: `http://127.0.0.1:${PORT}`, + }; +}