fix(test): share developer toast handling with Electron browser runs

The standalone Electron browser runner bypassed the browser fixture, allowing developer errors to cover Settings. Use the same non-pointer dismissal in both runners while retaining their console logs.
This commit is contained in:
Mohamed Boudra
2026-10-19 19:22:28 +02:00
parent ef885ddc8b
commit 2c909a3011
4 changed files with 15 additions and 11 deletions
+1 -1
View File
@@ -193,7 +193,7 @@ Test suites in this repo are heavy. Running them in bulk freezes the machine, es
- Playwright specs that exercise only the daemon import `daemonTest` from the shared fixtures so they do not create a browser context or page.
- Helpers that create projects or workspaces own those records until cleanup. Their clients remove the daemon project on close, and an automatic fixture fails any test that still leaks a project record. Deleting only the temporary directory is not cleanup. Agent helpers pass the intended `workspaceId` through to agent creation; they never infer ownership from `cwd`.
- Tests whose subject is daemon-global state, such as an empty history or daemon restart, start a dedicated host explicitly. Filenames and directories describe product behavior, never execution order or isolation mechanics.
- Global setup accepts Metro as ready only when `/status` returns `packager-status:running`, then fetches the document's scripts so the cold bundle compilation finishes before Playwright's per-test timeout starts. A generic TCP listener is not sufficient readiness evidence. The browser suite uses direct local daemon connections and does not start a relay. Automated Metro launches set `EXPO_UNSTABLE_HEADLESS=1` so Expo does not download the native DevTools shell into temporary test homes; its read-only cache breaks teardown. Browser fixtures dispatch Expo's developer-toast close action while retaining console logs. A pointer click moves hover away from the tested control and stalls behind app modal backdrops.
- Global setup accepts Metro as ready only when `/status` returns `packager-status:running`, then fetches the document's scripts so the cold bundle compilation finishes before Playwright's per-test timeout starts. A generic TCP listener is not sufficient readiness evidence. The browser suite uses direct local daemon connections and does not start a relay. Automated Metro launches set `EXPO_UNSTABLE_HEADLESS=1` so Expo does not download the native DevTools shell into temporary test homes; its read-only cache breaks teardown. Browser fixtures and the standalone Electron browser runner share the developer-toast dismissal helper while retaining console logs. A pointer click moves hover away from the tested control and stalls behind app modal backdrops.
- The app Playwright harness boots on Windows as well as POSIX. Spawn Node entrypoints through `process.execPath`, not `npx` or `node_modules/.bin` shims: Node refuses to spawn `.cmd` or `.bat` without `shell: true`, and shell mode concatenates argv without escaping and sends kill signals to `cmd.exe` instead of the real child.
- Teardown kills the process tree, because a Windows signal reaches only the direct child and leaves forked workers holding the listening port.
- The `asdf`-backed local Elixir relay stays POSIX-only, so the `relay-deployment` Playwright project is unavailable on Windows.
+10
View File
@@ -0,0 +1,10 @@
/** @param {import('@playwright/test').Page} page */
export async function installDeveloperToastDismissal(page) {
// Developer chrome must not cover app actions or move the test's pointer/focus.
// Console errors remain in the runner's logs.
const dismiss = page.locator("#error-toast").getByRole("button", { name: "", exact: true });
await page.addLocatorHandler(dismiss, () => dismiss.dispatchEvent("click"), {
// A new logged error can replace the toast before the old one disappears.
noWaitAfter: true,
});
}
+2 -10
View File
@@ -1,4 +1,5 @@
import { test as base, expect, type Page } from "@playwright/test";
import { installDeveloperToastDismissal } from "./developer-ui.mjs";
import { startOutdatedDaemon, type OutdatedDaemon } from "./helpers/daemon-update";
import { startE2EWorker } from "./helpers/e2e-worker";
import { getE2EDaemonPort } from "./helpers/daemon-port";
@@ -130,16 +131,7 @@ const test = daemonTest.extend<{
await ws.close({ code: 1008, reason: "Blocked connection to localhost:6767 during e2e." });
});
// Expo's development LogBox toast overlaps bottom actions on compact screens.
// Dispatch the developer UI's close action without moving the pointer or
// clicking through an app modal. Console errors still go into the test log.
const dismissDevToast = page
.locator("#error-toast")
.getByRole("button", { name: "", exact: true });
await page.addLocatorHandler(dismissDevToast, () => dismissDevToast.dispatchEvent("click"), {
// Another logged error can replace the toast before it disappears.
noWaitAfter: true,
});
await installDeveloperToastDismissal(page);
const entries: string[] = [];
@@ -12,6 +12,7 @@ import { fileURLToPath } from "node:url";
import { experimental_createMCPClient } from "ai";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
import { chromium } from "playwright";
import { installDeveloperToastDismissal } from "../../app/e2e/support/developer-ui.mjs";
import { runAppearanceFontSizeRegression } from "./appearance-font-size.electron.mjs";
import { runSettingsMemoryRegression } from "./settings-memory.electron.mjs";
@@ -1188,6 +1189,7 @@ async function main() {
browser = await chromium.connectOverCDP(`http://127.0.0.1:${cdpPort}`);
const page = await waitForAppPage(browser, expoPort);
await installDeveloperToastDismissal(page);
const status = await waitForDesktopStatus(page);
const checkPluginLinks = () =>