All jobs

Write Playwright Tests for an Electron App

Yes. An agent writes Playwright tests that launch your built Electron app, check the window and an IPC round trip, run them under xvfb and open a PR.

Run this on RushIn a Project that has your repository.

What the agent does

Playwright can drive Electron itself, not just a browser: _electron.launch() starts the real app, returns the main process as an object you can evaluate in, and hands back each BrowserWindow as a page. The agent begins by finding what to launch. In electron-react-boilerplate, package.json sets main to ./release/app/dist/main/main.js, and electron.vite.config.ts writes the main bundle to release/app/dist/main, the preload to release/app/dist/preload/preload.js and the renderer to release/app/dist/renderer, so npm run build (which is electron-vite build) has to run before any test launches the app. Electron is ^44.4.0 and engines requires Node 24.

Next it reads the IPC path end to end, because that is what the tests have to prove works across processes. src/main/preload.ts exposes window.electron.ipcRenderer with sendMessage, on and once, typed to a single channel, 'ipc-example'. src/main/main.ts registers ipcMain.on('ipc-example', ...) and replies with IPC test: pong. src/renderer/index.tsx sends ['ping'] on load. The existing tests are Jest tests in src/__tests__/: App.test.tsx renders the component in jsdom and updates.test.ts mocks electron entirely, so nothing today runs the real main process, preload and renderer together. .erb/scripts/smoke-test.cjs checks startup over the remote debugging port, but asserts nothing about IPC.

The agent adds @playwright/test as a dev dependency and writes e2e/app.spec.ts. It launches with _electron.launch({ args: ['release/app/dist/main/main.js'] }), waits for firstWindow(), and asserts three things: the window opens with the title Hello Electron React! from src/renderer/index.html; the renderer loaded, by finding the heading electron-react-boilerplate that App.tsx renders; and the IPC round trip, by calling window.electron.ipcRenderer.once and sendMessage('ipc-example', ['ping']) inside the page and expecting IPC test: pong back. A fourth check uses electronApp.evaluate to read app.isPackaged from the main process, so the test fails loudly if it ever launches a packaged build by mistake.

Jest's default pattern would also pick up *.spec.ts, so the agent adds e2e to testPathIgnorePatterns in jest.config.js to keep the two runners apart, and adds an e2e script. It runs npm ci, npm run build and then xvfb-run --auto-servernum npx playwright test in its sandbox, the same xvfb-run the repository's test.yml already uses for the smoke test, until all checks pass on a clean build.

Start it with one API call

POST https://api.prix.dev/o/{org}/sessions with this body:

{
  "agent": "claude",
  "input": "Write Playwright tests that launch this Electron app with _electron.launch from @playwright/test, using the built main entry from package.json after npm run build. Check that the first window opens, the renderer loads (the App heading is visible), and an IPC round trip works: from the page, send 'ping' on the ipc-example channel through window.electron.ipcRenderer and expect the main process reply 'IPC test: pong'. Put the tests under e2e/ and keep them out of Jest's testPathIgnorePatterns. Add an e2e script and a step in the existing test workflow that runs it under xvfb-run on Linux. Run them under xvfb in the sandbox until they pass and open a pull request.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
  1. Get an API key. In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
  2. Send the request. POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
  3. Read what came back. Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

What comes back

The pull request adds e2e/app.spec.ts, a playwright.config.ts with testDir: 'e2e' and a trace kept on failure, @playwright/test in devDependencies with its lockfile entry, an "e2e": "playwright test" script, the e2e entry in jest.config.js, and a step in .github/workflows/test.yml after the existing Linux smoke test: xvfb-run --auto-servernum npm run e2e. The Electron app's source does not change.

The description quotes the Playwright summary from the sandbox run and explains each assertion and why it is there, for example that the IPC test goes through the real preload rather than calling ipcMain directly. Because the workflow change runs on the pull request, GitHub's Ubuntu runner shows the same tests passing. The session's record keeps the build output, each playwright test run and any trace from a failed attempt.

A reviewer checks the timeouts are generous enough for a cold Electron start on a shared runner, that the tests close the app in afterAll so no Electron process outlives the job, and whether to run the new step on macOS and Windows too, which the pull request leaves as a suggestion.

Run it on every IPC channel added

The tests are only as good as the channels they cover. Start this run from a GitHub trigger on pull_request.opened, with a prompt that asks for a Playwright test for any channel the pull request adds to the Channels type in preload.ts or to an ipcMain handler, and new IPC arrives with its round-trip test in the same pull request.

If you maintain several Electron apps, a single script can send one request per repository. Each runs in its own sandbox with its own display server, so Electron instances never fight over one X display, and each pull request carries the output from its own run.

The use case this job follows, with its automation and trigger: Write the missing tests.

Why run it on Rush?

Headless Electron on Linux is where these tests usually stall: no display, missing shared libraries for Chromium, sandbox flags, and an xvfb-run that has to wrap the right command. A Rush sandbox is a Linux machine the agent controls, so it installs what Electron 44 needs, runs the real build and the real app under xvfb, and finds those problems there, not in your CI after you push.

The proof is the run, not a claim. The session's record shows the build, every Playwright run and the traces of failures the agent fixed, and the pull request's workflow repeats the tests on GitHub. Your laptop never opens an Electron window, and several repositories can get their first end-to-end tests at once.

Frequently asked questions

Do I need Spectron or WebdriverIO?

No. Spectron is deprecated, and Playwright's built-in Electron support covers launching the app, evaluating in the main process and driving each window. The pull request adds only @playwright/test; no browser download is needed for Electron tests, since Playwright drives the Electron binary you already install.

Why build first instead of testing the dev server?

npm start runs electron-vite dev with a renderer dev server and watch mode, which is not what users run. Testing the output of npm run build exercises the bundled main, preload and renderer files, so a bundling mistake fails the test.

Will it test my auto-updater or native menus?

Not by default. updates.ts already has a Jest test with electron-updater mocked, and native menus are outside Playwright's reach. The pull request covers the window, the renderer and IPC, and says what is left out.

Does it work on macOS and Windows runners?

The tests are cross-platform; only Linux needs xvfb-run. The pull request adds the step for Linux, matching how the existing smoke test runs, and suggests the line to add for the macOS and Windows matrix entries.