name: electron-driver description: E2E Testing & Automation for Electron Apps (Playwright) model: sonnet version: 0.1.0 source: fork checksum: e44a4288375c0d42cb602a811d60898e45f8ec8dc3eac176f5890244b7f1afc6 updated_at: 2026-02-06T15:19:11+08:00 layer: domain
Electron Driver Skill
The standard tool for End-to-End (E2E) Verification of Electron Applications.
Use this skill when you need to:
- Verify UI functionality (clicking buttons, checking text, form submission).
- Run automated regression tests on a packaged or local Electron app.
- Drive the application to reproduce bugs or set up state.
- Inspect the DOM and console of a running Electron process.
Supports two robust modes: Launch (Clean E2E Test) and Attach (Live Debugging).
- Launch: Start a new Electron instance with a controlled environment.
- Attach: Connect to an existing process via CDP (requires
--remote-debugging-port). - Inspect: Smartly find the main window (ignoring DevTools).
- Interact: Click, type, and verify using modern Playwright Locators.
Integration with e2e and tdd
electron-driver is the Electron-specific execution backend in the testing stack:
$tddvalidates core logic and IPC units first.$e2edefines end-user journey scenarios.$electron-driverexecutes those scenarios against real Electron runtime windows/processes.
Use this skill when $e2e detects Electron context or when desktop-runtime debugging is required.
Prerequisites
- Playwright:
npm install playwright-core(locally preferred) ornpm install -g playwright-core. - Electron Executable:
- For Launch: Path to the Electron executable (e.g.,
node_modules/.bin/electronor the packaged app). - For Attach: The target app MUST be running with
--remote-debugging-port=<port>.
- For Launch: Path to the Electron executable (e.g.,
Strategy Selection
| Mode | Use Case | Pros | Cons |
|---|---|---|---|
| Launch | Automated tests, reproducible tasks | Clean env, no port conflicts, auto-close | Slower start, loses current app state |
| Attach | Debugging current session, "Drive my app" | Preserves state, instant feedback | Complex setup (ports), fragile |
Usage
1. Launch Mode (Recommended)
Create a script that launches the app.
File: test-driver.cjs (Use .cjs to avoid ESM/CJS issues)
const { _electron: electron } = require('playwright-core');
(async () => {
// Launch the app
// args: pointing to main.js or the packaged app executable
const app = await electron.launch({
args: ['.'], // Or path to executable
env: { ...process.env, NODE_ENV: 'development' }
});
try {
// Smart Window Find (ignoring DevTools)
const page = await app.firstWindow();
if (page.url().startsWith('devtools://')) {
// Loop to find real window if first one is devtools
// (Logic typically handled by waiting for first non-devtools window)
}
console.log(`Title: ${await page.title()}`);
// --- ACTION LOGIC ---
// Modern Locator API
await page.getByRole('button', { name: 'Login' }).click();
await expect(page.getByText('Welcome')).toBeVisible(); // requires @playwright/test runner or stand-alone expect
// Simple wait (if not using expect)
await page.locator('.status').waitFor();
// --------------------
} catch (err) {
console.error(err);
} finally {
// Close app
await app.close();
}
})();
2. Attach Mode (Debugging)
Pre-check: Ensure app is running with --remote-debugging-port=9222 (or check console for actual port).
File: attach-driver.cjs
const { chromium } = require('playwright-core');
(async () => {
try {
// Connect to CDP
const browser = await chromium.connectOverCDP('http://localhost:9222');
// Find the right page (Filter out DevTools)
const context = browser.contexts()[0];
const pages = context.pages();
const page = pages.find(p => !p.url().startsWith('devtools://'));
if (!page) throw new Error('No valid app window found');
// --- ACTION LOGIC ---
await page.locator('#submit-btn').click();
// --------------------
await browser.close(); // Disconnects (does not kill app)
} catch (e) {
console.error(e);
}
})();
Playwright Modern Cheatsheet
- Locators (Preferred):
page.getByRole('button', { name: 'Save' })page.getByText('Hello World')page.getByPlaceholder('Email')page.locator('.css-class')
- Actions:
await locator.click()await locator.fill('text')
- Waiting:
- ❌
await page.waitForSelector(...)(Old) - ✅
await locator.waitFor()(Explicit) - ✅
await locator.click()(Auto-waits)
- ❌
Troubleshooting
- ESM Error:
SyntaxError: Cannot use import statement...-> Save file as.mjsor change project type. Recommendation: Always save temp scripts as.cjsand userequire. - DevTools Window: If the script interacts with the inspector instead of the app, check the window filtering logic.
- Port Conflict: If 9222 is busy, try a different port in Launch args or Attach URL.