Renderer unit tests miss the Electron bugs that matter. A preload leaks ipcRenderer, a handler trusts its input, or someone sets sandbox: false to make a feature work. This loadout gives your agent Playwright's Electron support, set up properly. A fixture gives every test its own app instance and an empty userData folder, with a relaunch for persistence tests. An example suite asserts the secure webPreferences from the main process and checks that the renderer sees only the preload API. It drives an IPC feature through the UI and onto disk and back after a restart, checks the handler rejects bad input, and confirms that window.open and navigation are denied. A CI workflow runs it under xvfb on Ubuntu. The verifier runs the suite against a sandboxed Electron 44.9.0 app with @playwright/test 1.64.1. It also checks that turning the sandbox off or exposing ipcRenderer fails a test.
What's in it
- Fresh app and userData per test, with relaunch for persistence
- Security assertions: sandbox, contextIsolation, no Node in the renderer
- IPC tested end to end, including handler validation
- Runs headless on Linux CI under xvfb-run
- Verified on Electron 44.9.0 and @playwright/test 1.64.1
You'll need
- Tools:
node,npm,xvfb-run
Verification
| Check | Result | What we found |
|---|---|---|
| Listinglisting.yaml matches the schema and declares every file in the folder. | Pass | Schema valid; 8 files declared, none missing or extra
|
| Files parseJSON parses; SKILL.md and .mdc front matter is valid YAML with the fields each agent needs; code fences are closed. | Pass | All 8 files parse; front matter valid |
| AdaptersCLAUDE.md imports @AGENTS.md, GEMINI.md imports @./AGENTS.md, and both match the generator. | Pass | CLAUDE.md and GEMINI.md import AGENTS.md and are up to date
|
| Install pathsEvery file lands where each agent documents it, with no collisions, and the laid-out project is re-discovered correctly. | Pass | Correct paths for all 6 agents; layouts re-discovered
|
| MCP configmcp.json is structurally valid, converts to each agent's format, declares no literal secrets, and referenced packages exist on npm/PyPI. | Not applicable | No MCP servers in this loadout |
| Safety scanThe intake scanner finds no credentials, risky shell, hidden Unicode or prompt-injection wording, and the listing's network flag is honest. | Pass | Clean: no credentials, risky shell or hidden text
|
| ReferencesLinks and file paths between the loadout's files resolve, including for each agent's installed layout. | Pass | 2 references between files resolve for every agent |
| Size limitsFile count and sizes are within the submission limits; SKILL.md bodies stay under 500 lines. | Pass | 8 files, 10.9 KB total; largest skills/electron-e2e-test/SKILL.md 3.5 KB
|
| LicenceA recognised SPDX licence, with the licence text available. | Pass | MIT, by Agent Loadout; text in the repository LICENSE |
| Starter buildA minimal fixture project with the loadout applied installs and builds or type-checks, and the loadout's own code examples compile. | Pass | The electron-e2e-test skill's Playwright config, fixtures and five tests drive a sandboxed Electron 44.9.0 app under xvfb with @playwright/test 1.64.1: secure webPreferences, no Node in the renderer, IPC save and restart, input validation, blocked navigation. Turning the sandbox off or exposing ipcR
|
What this means: a script checked the files themselves: they parse, they install where each agent looks, any MCP config is sound, the safety scan is clean, references between files resolve, and, where a free and repeatable fixture exists, a small starter project builds with the loadout applied. No AI agent was run. Per-agent results ("tested with agent") are separate and stay untested until an agent actually runs.
Install
Choose your agent. Run the commands from your project root, or download a zip already laid out in the right folders.
Claude Code reads CLAUDE.md (imports AGENTS.md with @AGENTS.md) and skills from .claude/skills/.
curl -fsSL --create-dirs -o AGENTS.md https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/AGENTS.md curl -fsSL --create-dirs -o CLAUDE.md https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/CLAUDE.md curl -fsSL --create-dirs -o .claude/skills/electron-e2e-test/SKILL.md https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/SKILL.md curl -fsSL --create-dirs -o .claude/skills/electron-e2e-test/references/playwright.config.js https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/playwright.config.js curl -fsSL --create-dirs -o .claude/skills/electron-e2e-test/references/electron-fixture.js https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-fixture.js curl -fsSL --create-dirs -o .claude/skills/electron-e2e-test/references/app.spec.js https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/app.spec.js curl -fsSL --create-dirs -o .claude/skills/electron-e2e-test/references/electron-e2e.yml https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-e2e.yml
| File | Goes to |
|---|---|
AGENTS.md | AGENTS.md |
CLAUDE.md | CLAUDE.md |
skills/electron-e2e-test/SKILL.md | .claude/skills/electron-e2e-test/SKILL.md |
skills/electron-e2e-test/references/playwright.config.js | .claude/skills/electron-e2e-test/references/playwright.config.js |
skills/electron-e2e-test/references/electron-fixture.js | .claude/skills/electron-e2e-test/references/electron-fixture.js |
skills/electron-e2e-test/references/app.spec.js | .claude/skills/electron-e2e-test/references/app.spec.js |
skills/electron-e2e-test/references/electron-e2e.yml | .claude/skills/electron-e2e-test/references/electron-e2e.yml |
Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want.
Codex CLI reads AGENTS.md and skills from .agents/skills/.
curl -fsSL --create-dirs -o AGENTS.md https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/AGENTS.md curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/SKILL.md https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/SKILL.md curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/references/playwright.config.js https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/playwright.config.js curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/references/electron-fixture.js https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-fixture.js curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/references/app.spec.js https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/app.spec.js curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/references/electron-e2e.yml https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-e2e.yml
| File | Goes to |
|---|---|
AGENTS.md | AGENTS.md |
skills/electron-e2e-test/SKILL.md | .agents/skills/electron-e2e-test/SKILL.md |
skills/electron-e2e-test/references/playwright.config.js | .agents/skills/electron-e2e-test/references/playwright.config.js |
skills/electron-e2e-test/references/electron-fixture.js | .agents/skills/electron-e2e-test/references/electron-fixture.js |
skills/electron-e2e-test/references/app.spec.js | .agents/skills/electron-e2e-test/references/app.spec.js |
skills/electron-e2e-test/references/electron-e2e.yml | .agents/skills/electron-e2e-test/references/electron-e2e.yml |
Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want.
Cursor reads AGENTS.md + .cursor/rules/*.mdc and skills from .agents/skills/.
curl -fsSL --create-dirs -o AGENTS.md https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/AGENTS.md curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/SKILL.md https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/SKILL.md curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/references/playwright.config.js https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/playwright.config.js curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/references/electron-fixture.js https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-fixture.js curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/references/app.spec.js https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/app.spec.js curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/references/electron-e2e.yml https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-e2e.yml
| File | Goes to |
|---|---|
AGENTS.md | AGENTS.md |
skills/electron-e2e-test/SKILL.md | .agents/skills/electron-e2e-test/SKILL.md |
skills/electron-e2e-test/references/playwright.config.js | .agents/skills/electron-e2e-test/references/playwright.config.js |
skills/electron-e2e-test/references/electron-fixture.js | .agents/skills/electron-e2e-test/references/electron-fixture.js |
skills/electron-e2e-test/references/app.spec.js | .agents/skills/electron-e2e-test/references/app.spec.js |
skills/electron-e2e-test/references/electron-e2e.yml | .agents/skills/electron-e2e-test/references/electron-e2e.yml |
Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want.
Gemini CLI reads GEMINI.md (imports AGENTS.md with @./AGENTS.md) and skills from .agents/skills/.
curl -fsSL --create-dirs -o AGENTS.md https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/AGENTS.md curl -fsSL --create-dirs -o GEMINI.md https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/GEMINI.md curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/SKILL.md https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/SKILL.md curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/references/playwright.config.js https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/playwright.config.js curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/references/electron-fixture.js https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-fixture.js curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/references/app.spec.js https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/app.spec.js curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/references/electron-e2e.yml https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-e2e.yml
| File | Goes to |
|---|---|
AGENTS.md | AGENTS.md |
GEMINI.md | GEMINI.md |
skills/electron-e2e-test/SKILL.md | .agents/skills/electron-e2e-test/SKILL.md |
skills/electron-e2e-test/references/playwright.config.js | .agents/skills/electron-e2e-test/references/playwright.config.js |
skills/electron-e2e-test/references/electron-fixture.js | .agents/skills/electron-e2e-test/references/electron-fixture.js |
skills/electron-e2e-test/references/app.spec.js | .agents/skills/electron-e2e-test/references/app.spec.js |
skills/electron-e2e-test/references/electron-e2e.yml | .agents/skills/electron-e2e-test/references/electron-e2e.yml |
Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want.
Antigravity CLI reads AGENTS.md (read natively; GEMINI.md is also read) and skills from .agents/skills/.
curl -fsSL --create-dirs -o AGENTS.md https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/AGENTS.md curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/SKILL.md https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/SKILL.md curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/references/playwright.config.js https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/playwright.config.js curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/references/electron-fixture.js https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-fixture.js curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/references/app.spec.js https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/app.spec.js curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/references/electron-e2e.yml https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-e2e.yml
| File | Goes to |
|---|---|
AGENTS.md | AGENTS.md |
skills/electron-e2e-test/SKILL.md | .agents/skills/electron-e2e-test/SKILL.md |
skills/electron-e2e-test/references/playwright.config.js | .agents/skills/electron-e2e-test/references/playwright.config.js |
skills/electron-e2e-test/references/electron-fixture.js | .agents/skills/electron-e2e-test/references/electron-fixture.js |
skills/electron-e2e-test/references/app.spec.js | .agents/skills/electron-e2e-test/references/app.spec.js |
skills/electron-e2e-test/references/electron-e2e.yml | .agents/skills/electron-e2e-test/references/electron-e2e.yml |
Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want.
GitHub Copilot reads AGENTS.md and skills from .agents/skills/.
curl -fsSL --create-dirs -o AGENTS.md https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/AGENTS.md curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/SKILL.md https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/SKILL.md curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/references/playwright.config.js https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/playwright.config.js curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/references/electron-fixture.js https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-fixture.js curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/references/app.spec.js https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/app.spec.js curl -fsSL --create-dirs -o .agents/skills/electron-e2e-test/references/electron-e2e.yml https://loadout.jnw-it.com/raw/electron-playwright-e2e/1.0.0/skills/electron-e2e-test/references/electron-e2e.yml
| File | Goes to |
|---|---|
AGENTS.md | AGENTS.md |
skills/electron-e2e-test/SKILL.md | .agents/skills/electron-e2e-test/SKILL.md |
skills/electron-e2e-test/references/playwright.config.js | .agents/skills/electron-e2e-test/references/playwright.config.js |
skills/electron-e2e-test/references/electron-fixture.js | .agents/skills/electron-e2e-test/references/electron-fixture.js |
skills/electron-e2e-test/references/app.spec.js | .agents/skills/electron-e2e-test/references/app.spec.js |
skills/electron-e2e-test/references/electron-e2e.yml | .agents/skills/electron-e2e-test/references/electron-e2e.yml |
Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want.
Files
Rules AGENTS.md Rules for an Electron app whose security settings and IPC are covered by Playwright end-to-end tests. 24 lines
# AGENTS.md: Electron app tested end to end with Playwright
An Electron desktop app with a sandboxed, context-isolated renderer and a narrow preload API. End-to-end tests
use Playwright's Electron support to drive the real app. Check `package.json` for the Electron and Playwright
versions before using an API.
## Commands
- Start: `npm start`.
- End-to-end tests: `npx playwright test` (Linux without a display: `xvfb-run -a npx playwright test`).
- One test: `npx playwright test -g "rejects an empty title"`. Traces: `npx playwright show-trace test-results/.../trace.zip`.
- Done means: the suite passes and the behaviour you changed has an end-to-end test.
## Rules
- Use the `electron-e2e-test` skill for any change that crosses IPC, touches `webPreferences`, the preload or
window handlers, or adds tests.
- Keep `contextIsolation: true`, `sandbox: true` and `nodeIntegration: false`, and keep the tests that assert
them. Never weaken a security assertion to make a test pass.
- The renderer reaches main only through named preload functions. Every `ipcMain.handle` checks the sender
frame and validates its arguments, and has a test for bad input.
- Tests use the shared fixture: a fresh app and `userData` per test. No `waitForTimeout`, no CSS selectors.
- Never add `--no-sandbox`, `--disable-web-security` or `ELECTRON_RUN_AS_NODE` to scripts or CI. Adapter CLAUDE.md Imports AGENTS.md for Claude Code. 11 lines
# CLAUDE.md
@AGENTS.md
## Claude Code notes
- Skills from this loadout live in `.claude/skills/`: `electron-e2e-test`. Use them when their description matches the task.
- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.
<!-- From the Agent Loadout "Electron end-to-end tests with Playwright" v1.0.0 — https://loadout.jnw-it.com/loadouts/electron-playwright-e2e/ --> Adapter GEMINI.md Imports AGENTS.md for Gemini CLI. 11 lines
# GEMINI.md
@./AGENTS.md
## Gemini CLI notes
- Skills from this loadout live in `.agents/skills/`: `electron-e2e-test`. Use them when their description matches the task.
- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.
<!-- From the Agent Loadout "Electron end-to-end tests with Playwright" v1.0.0 — https://loadout.jnw-it.com/loadouts/electron-playwright-e2e/ --> Skill skills/electron-e2e-test/SKILL.md Setup, what every suite covers, rules and CI. 63 lines
---
name: electron-e2e-test
description: Write and run Playwright end-to-end tests that drive the real Electron app - main process, preload and renderer together - including security assertions on webPreferences, the preload API, IPC validation and blocked navigation. Use when adding a feature that crosses IPC, changing window or preload settings, or setting up Electron tests in CI.
---
# Electron end-to-end tests with Playwright
Unit tests of the renderer miss the bugs that matter in Electron: a preload that leaks `ipcRenderer`, a
handler that trusts its input, a window that someone set to `sandbox: false`. Playwright's Electron support
launches the real app and lets a test reach both sides: `page` for the renderer, `app.evaluate` for the main
process.
## Setup
- Dev dependencies, pinned: `@playwright/test` and `electron`. No browser download is needed for Electron
tests (`npx playwright install` is not required).
- `references/playwright.config.js`: one worker, traces kept on failure, one retry on CI only.
- `references/electron-fixture.js`: `test.extend` fixtures. Every test gets a fresh `userData` folder,
its own app instance (`app.current`), its first window (`page`), and `app.relaunch()` for restart tests.
The main process must honour `E2E_USER_DATA`:
```js
if (process.env.E2E_USER_DATA) app.setPath("userData", process.env.E2E_USER_DATA);
```
- Run: `npx playwright test`. On Linux without a display: `xvfb-run -a npx playwright test`.
## What every app's suite covers
`references/app.spec.js` is a complete example. Adapt these to your app:
1. Secure defaults, read from the main process:
`webContents.getLastWebPreferences()` has `contextIsolation: true`, `sandbox: true`,
`nodeIntegration: false`. A change that weakens one fails here, not in a security review.
2. The renderer sees only the preload API: `typeof window.require`, `window.process` and
`window.ipcRenderer` are `"undefined"`, and the exposed object has exactly the functions you expect.
3. Each IPC feature end to end: act in the UI, assert the UI, then assert the main-process effect (a file
in `userData`, a value from `app.evaluate`). Restart with `app.relaunch()` when persistence matters.
4. Each handler's validation: send bad input through the UI and assert the error and that nothing was written.
5. `window.open` and navigation away are denied, and there is still one window.
## Rules
- Locate by role and label (`getByRole`, `getByLabel`), never by CSS classes or XPath.
- Wait with web-first assertions (`expect(locator).toHaveText`, `expect.poll`), never `waitForTimeout`.
- One app per test via the fixture. No shared state between tests, no real home-directory data.
- Never trigger `shell.openExternal` from a test (use a URL your handler denies outright); on CI it can hang shutdown.
- Never pass `--no-sandbox`, `--disable-web-security` or similar flags to make a test pass. If the app only
starts with them, report it as a bug.
- Do not stub `ipcRenderer` or the preload in e2e tests. That is what the test is for.
- A failing test gets fixed or reported, not skipped. `test.fixme` only with a linked issue.
## CI
`references/electron-e2e.yml`: Ubuntu runner, `npm ci`, a step that downloads the Electron binary
(`node -e "require('electron')"`, verified against Electron's checksums), then
`xvfb-run -a npx playwright test`. Traces upload on failure.
## Done means
The suite passes locally or under `xvfb-run`, the new behaviour has a test from the list above, and the
summary names any security assertion you changed and why. Skill file skills/electron-e2e-test/references/playwright.config.js One worker, traces on failure, a CI-only retry. 12 lines
// Electron end-to-end tests. One worker: each test launches its own app instance.
const { defineConfig } = require("@playwright/test");
module.exports = defineConfig({
testDir: "e2e",
timeout: 30_000,
workers: 1,
retries: process.env.CI ? 1 : 0,
reporter: [["list"]],
use: { trace: "retain-on-failure" },
}); Skill file skills/electron-e2e-test/references/electron-fixture.js Per-test app, page and userData fixtures with relaunch. 42 lines
// Playwright fixtures for Electron: every test gets its own app instance and an empty userData folder.
// `relaunch()` closes and restarts the app on the same userData, for persistence tests.
const base = require("@playwright/test");
const fs = require("node:fs");
const os = require("node:os");
const path = require("node:path");
const launch = (userData) =>
base._electron.launch({
args: ["."],
env: { ...process.env, E2E_USER_DATA: userData, ELECTRON_ENABLE_LOGGING: "1" },
});
exports.test = base.test.extend({
userData: async ({}, use) => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "electron-e2e-"));
await use(dir);
fs.rmSync(dir, { recursive: true, force: true });
},
app: async ({ userData }, use) => {
const holder = { current: await launch(userData) };
holder.relaunch = async () => {
await holder.current.close();
holder.current = await launch(userData);
return holder.current;
};
await use(holder);
// Close normally, but never let a stuck app hang the run: kill it after 10 seconds.
const proc = holder.current.process();
const timer = setTimeout(() => proc.kill("SIGKILL"), 10_000);
await holder.current.close().catch(() => {});
clearTimeout(timer);
},
page: async ({ app }, use) => {
const page = await app.current.firstWindow();
await page.waitForLoadState("domcontentloaded");
await use(page);
},
});
exports.expect = base.expect; Skill file skills/electron-e2e-test/references/app.spec.js Five end-to-end tests, including security assertions. 54 lines
// Drives the real Electron app: main process, preload and renderer together.
const fs = require("node:fs");
const path = require("node:path");
const { test, expect } = require("./electron-fixture");
test("window opens with the secure web preferences", async ({ app, page }) => {
await expect(page).toHaveTitle("Notes");
const prefs = await app.current.evaluate(({ BrowserWindow }) => {
const p = BrowserWindow.getAllWindows()[0].webContents.getLastWebPreferences();
return { contextIsolation: p.contextIsolation, sandbox: p.sandbox, nodeIntegration: p.nodeIntegration };
});
expect(prefs).toEqual({ contextIsolation: true, sandbox: true, nodeIntegration: false });
});
test("the renderer has the preload API and no Node", async ({ page }) => {
const globals = await page.evaluate(() => ({
require: typeof window.require,
process: typeof window.process,
ipcRenderer: typeof window.ipcRenderer,
notes: Object.keys(window.notes).sort(),
}));
expect(globals).toEqual({ require: "undefined", process: "undefined", ipcRenderer: "undefined", notes: ["add", "list"] });
});
test("adding a note goes through IPC, is saved by main, and survives a restart", async ({ app, page, userData }) => {
await page.getByLabel("Title").fill(" Buy milk ");
await page.getByRole("button", { name: "Add note" }).click();
await expect(page.getByRole("list", { name: "Notes" }).getByRole("listitem")).toHaveText(["Buy milk"]);
const saved = JSON.parse(fs.readFileSync(path.join(userData, "notes.json"), "utf8"));
expect(saved.map((n) => n.title)).toEqual(["Buy milk"]);
const again = await (await app.relaunch()).firstWindow();
await expect(again.getByRole("listitem")).toHaveText(["Buy milk"]);
});
test("the main process rejects an empty title", async ({ page, userData }) => {
await page.getByLabel("Title").fill(" ");
await page.getByRole("button", { name: "Add note" }).click();
await expect(page.getByRole("alert")).toHaveText("Title must be 1-120 characters");
expect(fs.existsSync(path.join(userData, "notes.json"))).toBe(false);
});
test("window.open and navigation away are denied", async ({ app, page }) => {
// http:// is denied without being handed to the OS browser; https:// would go to shell.openExternal,
// which a test must never trigger (on CI it can leave xdg-open hanging and block shutdown).
expect(await page.evaluate(() => window.open("http://example.com") === null)).toBe(true);
await page.evaluate(() => {
window.location.href = "https://example.com";
});
await expect.poll(() => page.url()).toMatch(/index\.html$/);
expect(app.current.windows()).toHaveLength(1);
}); Skill file skills/electron-e2e-test/references/electron-e2e.yml GitHub workflow running the suite under xvfb. 37 lines
# .github/workflows/e2e.yml
# Electron needs a display on Linux: xvfb-run provides a virtual one. The Electron binary is
# downloaded (and checksum-verified by @electron/get) on first use, then cached.
name: Electron e2e
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
jobs:
e2e:
runs-on: ubuntu-24.04
timeout-minutes: 15
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 22
cache: npm
- uses: actions/cache@v6
with:
path: ~/.cache/electron
key: electron-${{ hashFiles('package-lock.json') }}
- run: npm ci
- run: node -e "require('electron')"
- run: xvfb-run -a npx playwright test
- uses: actions/upload-artifact@v7
if: failure()
with:
name: playwright-traces
path: test-results/
retention-days: 7 All files: source zip · Licence MIT · By Agent Loadout · First listed
Credits
Public work that inspired this loadout. The wording here is our own; follow the links for the originals.
Installing and testing
How do I install Electron end-to-end tests with Playwright in Claude Code?
From your project root, put AGENTS.md, CLAUDE.md, skills/electron-e2e-test/SKILL.md at .claude/skills/electron-e2e-test/SKILL.md, skills/electron-e2e-test/references/playwright.config.js at .claude/skills/electron-e2e-test/references/playwright.config.js, skills/electron-e2e-test/references/electron-fixture.js at .claude/skills/electron-e2e-test/references/electron-fixture.js, skills/electron-e2e-test/references/app.spec.js at .claude/skills/electron-e2e-test/references/app.spec.js, skills/electron-e2e-test/references/electron-e2e.yml at .claude/skills/electron-e2e-test/references/electron-e2e.yml. The "Claude Code" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/electron-playwright-e2e/claude-code.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.
How do I install Electron end-to-end tests with Playwright in Codex CLI?
From your project root, put AGENTS.md, skills/electron-e2e-test/SKILL.md at .agents/skills/electron-e2e-test/SKILL.md, skills/electron-e2e-test/references/playwright.config.js at .agents/skills/electron-e2e-test/references/playwright.config.js, skills/electron-e2e-test/references/electron-fixture.js at .agents/skills/electron-e2e-test/references/electron-fixture.js, skills/electron-e2e-test/references/app.spec.js at .agents/skills/electron-e2e-test/references/app.spec.js, skills/electron-e2e-test/references/electron-e2e.yml at .agents/skills/electron-e2e-test/references/electron-e2e.yml. The "Codex CLI" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/electron-playwright-e2e/codex.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.
How do I install Electron end-to-end tests with Playwright in Cursor?
From your project root, put AGENTS.md, skills/electron-e2e-test/SKILL.md at .agents/skills/electron-e2e-test/SKILL.md, skills/electron-e2e-test/references/playwright.config.js at .agents/skills/electron-e2e-test/references/playwright.config.js, skills/electron-e2e-test/references/electron-fixture.js at .agents/skills/electron-e2e-test/references/electron-fixture.js, skills/electron-e2e-test/references/app.spec.js at .agents/skills/electron-e2e-test/references/app.spec.js, skills/electron-e2e-test/references/electron-e2e.yml at .agents/skills/electron-e2e-test/references/electron-e2e.yml. The "Cursor" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/electron-playwright-e2e/cursor.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.
How do I install Electron end-to-end tests with Playwright in Gemini CLI?
From your project root, put AGENTS.md, GEMINI.md, skills/electron-e2e-test/SKILL.md at .agents/skills/electron-e2e-test/SKILL.md, skills/electron-e2e-test/references/playwright.config.js at .agents/skills/electron-e2e-test/references/playwright.config.js, skills/electron-e2e-test/references/electron-fixture.js at .agents/skills/electron-e2e-test/references/electron-fixture.js, skills/electron-e2e-test/references/app.spec.js at .agents/skills/electron-e2e-test/references/app.spec.js, skills/electron-e2e-test/references/electron-e2e.yml at .agents/skills/electron-e2e-test/references/electron-e2e.yml. The "Gemini CLI" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/electron-playwright-e2e/gemini-cli.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.
How do I install Electron end-to-end tests with Playwright in Antigravity CLI?
From your project root, put AGENTS.md, skills/electron-e2e-test/SKILL.md at .agents/skills/electron-e2e-test/SKILL.md, skills/electron-e2e-test/references/playwright.config.js at .agents/skills/electron-e2e-test/references/playwright.config.js, skills/electron-e2e-test/references/electron-fixture.js at .agents/skills/electron-e2e-test/references/electron-fixture.js, skills/electron-e2e-test/references/app.spec.js at .agents/skills/electron-e2e-test/references/app.spec.js, skills/electron-e2e-test/references/electron-e2e.yml at .agents/skills/electron-e2e-test/references/electron-e2e.yml. The "Antigravity CLI" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/electron-playwright-e2e/antigravity-cli.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.
How do I install Electron end-to-end tests with Playwright in GitHub Copilot?
From your project root, put AGENTS.md, skills/electron-e2e-test/SKILL.md at .agents/skills/electron-e2e-test/SKILL.md, skills/electron-e2e-test/references/playwright.config.js at .agents/skills/electron-e2e-test/references/playwright.config.js, skills/electron-e2e-test/references/electron-fixture.js at .agents/skills/electron-e2e-test/references/electron-fixture.js, skills/electron-e2e-test/references/app.spec.js at .agents/skills/electron-e2e-test/references/app.spec.js, skills/electron-e2e-test/references/electron-e2e.yml at .agents/skills/electron-e2e-test/references/electron-e2e.yml. The "GitHub Copilot" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/electron-playwright-e2e/copilot.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.
Has Electron end-to-end tests with Playwright been tested?
It passed the Level 1 automated install checks on 2026-10-17: the files parse, install to each agent's documented paths, and pass the safety scan. No AI agent has run it yet, so no agent pass or fail is claimed.
More for Claude Code, Codex, Cursor, Gemini CLI, Antigravity CLI and GitHub Copilot.