Skip to content

/desktop-testing-electron

E2E testing with Playwright, main process unit testing, IPC testing, dialog/menu mocking, CI headless setup

shell
$ npx -y skills add agents-inc/skills --skill desktop-testing-electron --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/desktop-testing-electron
How auto-invocation works

Context preview

The summary Claude sees to decide when to auto-load this skill.

E2E testing with Playwright, main process unit testing, IPC testing, dialog/menu mocking, CI headless setup

SKILL.md

desktop-testing-electron.SKILL.md
name: desktop-testing-electron
description: E2E testing with Playwright, main process unit testing, IPC testing, dialog/menu mocking, CI headless setup

Electron Testing Patterns

> **Quick Guide:** Use Playwright's `_electron.launch()` for E2E tests -- it controls the full app via CDP. Unit test main process code (IPC handlers, business logic) with your test runner by mocking the `electron` module. Test preload scripts by mocking `contextBridge` and `ipcRenderer`. Spectron is dead since Electron 24 -- Playwright and WebDriverIO are the replacements. Run Electron tests on headless Linux CI with `xvfb-run` or the `xvfb-maybe` wrapper.

---

<critical_requirements>

CRITICAL: Before Using This Skill

> **All code must follow project conventions in CLAUDE.md** (kebab-case, named exports, import ordering, `import type`, named constants)

**(You MUST `await electronApp.close()` in test teardown -- leaked Electron processes break CI and consume resources)**

**(You MUST mock the `electron` module in unit tests -- Electron APIs are only available inside the Electron runtime)**

**(You MUST use `xvfb-run` or `xvfb-maybe` for headless Linux CI -- Electron requires a display server)**

**(You MUST stub native dialogs in E2E tests -- `showOpenDialog`/`showSaveDialog` block the process and cannot be interacted with by Playwright)**

</critical_requirements>

---

**Auto-detection:** Electron testing, _electron.launch, electronApp, electronApplication, firstWindow, Playwright Electron, electron-mock-ipc, electron-playwright-helpers, stubDialog, xvfb, xvfb-run, xvfb-maybe, Spectron migration, ipcMain.handle test, ipcRenderer mock, contextBridge mock, BrowserWindow mock, Electron E2E, Electron unit test

**When to use:**

  • Writing E2E tests for an Electron application with Playwright
  • Unit testing main process code (IPC handlers, lifecycle logic)
  • Mocking Electron modules (`dialog`, `BrowserWindow`, `ipcMain`, `ipcRenderer`)
  • Testing preload scripts and `contextBridge` APIs
  • Setting up headless CI for Electron tests (Linux xvfb)
  • Migrating from Spectron to Playwright
  • Screenshot/visual regression testing of Electron windows
  • Testing auto-update flows

**When NOT to use:**

  • Testing renderer UI in isolation (use your web testing skill -- renderer is standard web)
  • Writing tests unrelated to Electron-specific APIs
  • Performance profiling or benchmarking Electron apps
  • Packaging or distributing Electron apps (use the Electron framework skill)

**Key patterns covered:**

  • Playwright E2E: `_electron.launch()`, `firstWindow()`, `evaluate()`, assertions
  • Main process unit testing with mocked Electron modules
  • IPC handler testing (`ipcMain.handle` / `ipcRenderer.invoke`)
  • Preload script testing (mock `contextBridge.exposeInMainWorld`)
  • Dialog and menu stubbing in E2E tests
  • Auto-updater test strategies
  • Headless CI configuration (xvfb, GitHub Actions)
  • Screenshot and visual regression testing
  • Spectron migration path

---

<philosophy>

Philosophy

Electron testing splits along the same boundaries as the Electron process model:

1. **E2E tests** launch the full application with Playwright and exercise the complete flow -- main process, preload, renderer, and IPC together. These are slow but high-confidence. 2. **Main process unit tests** mock the `electron` module and test IPC handlers, lifecycle logic, and business logic in isolation. These are fast and catch logic bugs early. 3. **Renderer tests** are standard web tests -- the renderer is Chromium. Use your existing web testing approach.

**Guiding principle:** Test main process logic with unit tests, test integration through IPC with E2E, and test renderer UI with standard web tools. Don't try to unit test IPC communication itself -- the framework handles message passing. Test that your handlers produce the correct results given inputs.

**When to use E2E (Playwright):**

  • Full user workflows (open file, edit, save)
  • IPC round-trips that span main and renderer
  • Window management (multi-window, modals, frameless)
  • Visual regression / screenshot comparison
  • Auto-update UI flow

**When to use unit tests:**

  • IPC handler logic (validate input, produce output)
  • Main process business logic (file operations, data processing)
  • Preload API shape (correct channels exposed)
  • Configuration and startup logic

</philosophy>

---

<patterns>

Core Patterns

Pattern 1: Playwright E2E -- Launch and Basic Assertions

Launch the Electron app, get the first window, and run assertions. Always close in teardown.

import { test, expect, _electron as electron } from "@playwright/test";
import type { ElectronApplication, Page } from "@playwright/test";

let electronApp: ElectronApplication;
let window: Page;

test.beforeEach(async () => {
  electronApp = await electron.launch({ args: ["dist/main.js"] });
  window = await electronApp.firstWindow();
});

test.afterEach(async () => {
  await electronApp.close();
});

test("shows main window with title", async () => {
  const title = await window.title();
  expect(title).toBe("My App");
  await expect(window.locator("h1")).toHaveText("Welcome");
});

**Why good:** `afterEach` guarantees cleanup, `firstWindow()` waits for the window to load, standard Playwright assertions work on the Page object

See [examples/core.md](examples/core.md) for evaluate(), multi-window, and environment variable patterns.

---

Pattern 2: Main Process Evaluation

Use `electronApp.evaluate()` to execute code in the main process context and access Electron APIs.

test("returns correct app version", async () => {
  const version = await electronApp.evaluate(async ({ app }) => {
    return app.getVersion();
  });
  expect(version).toMatch(/^\d+\.\d+\.\d+$/);
});

test("app path is set correctly", async () => {
  const appPath = await electronApp.evaluate(async ({ app }) => {
    return app.getAppPath();
  });
  expect(appPath).toContain("dist");
});

**Why good:** `evalua

Read more
Read it on GitHub ↗

Showing the first part of this file.

Ships withagents-inc-skills

The official skills marketplace for Agents Inc. 150+ skills covering everything from React and Prisma to Redis, ElevenLabs, and infrastructure tooling. Pick the skills that match your stack and install them via Claude Code. Need more control?

Get the whole plugin, auto-invoked