| name | playwright-electron-config |
| description | Configure Playwright for comprehensive Electron application testing including E2E tests, visual regression, accessibility audits, and cross-platform test matrices |
| allowed-tools | Read, Write, Edit, Bash, Glob, Grep |
| tags | ["electron","testing","playwright","e2e","automation"] |
| graph | {"domains":["domain:software-engineering"],"specializations":["specialization:desktop-development"],"skillAreas":["skill-area:e2e-testing","skill-area:desktop-ui-frameworks"],"roles":["role:desktop-developer","role:fullstack-engineer"],"workflows":["workflow:feature-development","workflow:release-management"],"topics":["topic:accessibility"]} |
playwright-electron-config
Configure Playwright for comprehensive Electron application testing. This skill sets up the complete testing infrastructure including E2E tests, visual regression testing, accessibility audits, and cross-platform test matrices with CI/CD integration.
Capabilities
- Configure Playwright for Electron with
_electron fixture
- Generate page object models for Electron windows
- Set up visual regression testing with snapshots
- Configure accessibility testing with axe-core
- Create cross-platform test matrices for CI
- Mock Electron APIs (dialog, shell, clipboard)
- Test IPC communication between main and renderer
- Generate test coverage reports
Input Schema
{
"type": "object",
"properties": {
"projectPath": {
"type": "string",
"description": "Path to the Electron project root"
},
"testDir": {
"type": "string",
"default": "tests/e2e"
},
"features": {
"type": "array",
"items": {
"enum": [
"visualRegression",
"accessibility",
"coverage",
"performance",
"ipcTesting",
"multiWindow"
Output Schema
{
"type": "object",
"properties": {
"success": { "type": "boolean" },
"files": {
"type": "array",
"items": {
"type": "object",
"properties": {
"path": { "type": "string" },
"type": { "enum": ["config", "fixture", "pageObject", "test", "helper", "ci"]
Generated File Structure
tests/
e2e/
playwright.config.ts # Main Playwright config
fixtures/
electron-app.ts # Electron fixture
test-utils.ts # Test utilities
page-objects/
MainWindow.ts # Page object models
SettingsDialog.ts
specs/
app.spec.ts # Application tests
ipc.spec.ts # IPC tests
visual.spec.ts # Visual regression
a11y.spec.ts # Accessibility tests
mocks/
electron-api-mocks.ts # Electron API mocks
ipc-mocks.ts # IPC mocks
snapshots/ # Visual snapshots
reports/ # Test reports
Code Templates
Playwright Configuration for Electron
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests/e2e/specs',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: [
['html', { outputFolder: 'tests/e2e/reports' }],
['json', { outputFile: 'tests/e2e/reports/results.json' }],
],
use: {
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
projects: [
{
name: 'electron',
testMatch: '**/*.spec.ts',
},
],
});
Electron Test Fixture
import { test as base, ElectronApplication, Page } from '@playwright/test';
import { _electron as electron } from 'playwright';
import path from 'path';
export type TestFixtures = {
electronApp: ElectronApplication;
mainWindow: Page;
};
export const test = base.extend<TestFixtures>({
electronApp: async ({}, use) => {
const electronApp = await electron.launch({
args: [path.join(__dirname, '../../dist/main/main.js')],
env: {
...process.env,
NODE_ENV: 'test',
},
});
await use(electronApp);
await electronApp.close();
},
mainWindow: async ({ electronApp }, use) => {
const window = electronApp.();
.();
();
},
});
{ expect } ;
Page Object Model
import { Page, Locator } from '@playwright/test';
export class MainWindow {
readonly page: Page;
readonly titleBar: Locator;
readonly sidebar: Locator;
readonly mainContent: Locator;
readonly statusBar: Locator;
constructor(page: Page) {
this.page = page;
this.titleBar = page.locator('[data-testid="title-bar"]');
this.sidebar = page.locator('[data-testid="sidebar"]');
this.mainContent = page.locator('[data-testid="main-content"]');
this.statusBar = page.locator('[data-testid="status-bar"]');
}
async getTitle(): Promise<string> {
return ..();
}
(): <> {
..();
..();
}
(: ): <> {
..().();
..();
}
(: ): <> {
..({ : });
}
}
IPC Testing
import { test, expect } from '../fixtures/electron-app';
test.describe('IPC Communication', () => {
test('should send message to main process', async ({ electronApp, mainWindow }) => {
const result = await electronApp.evaluate(async ({ ipcMain }) => {
return new Promise((resolve) => {
ipcMain.once('test-channel', (event, data) => {
resolve(data);
});
});
});
await mainWindow.evaluate(() => {
window.electronAPI.send('test-channel', { message: 'hello' });
});
expect(result).toEqual({ message: 'hello' });
});
test('should receive response from main process', async ({ mainWindow }) => {
const response = await mainWindow.evaluate(async () => {
..();
});
(response).();
});
});
Visual Regression Testing
import { test, expect } from '../fixtures/electron-app';
import { MainWindow } from '../page-objects/MainWindow';
test.describe('Visual Regression', () => {
test('main window matches snapshot', async ({ mainWindow }) => {
const page = new MainWindow(mainWindow);
await mainWindow.waitForTimeout(500);
await expect(mainWindow).toHaveScreenshot('main-window.png', {
maxDiffPixels: 100,
});
});
test('dark mode matches snapshot', async ({ electronApp, mainWindow }) => {
await mainWindow.evaluate(() => {
window.electronAPI.invoke('set-theme', 'dark');
});
await mainWindow.waitForTimeout(300);
await expect(mainWindow).toHaveScreenshot('main-window-dark.png', {
maxDiffPixels: ,
});
});
(, ({ mainWindow }) => {
page = (mainWindow);
page.();
dialog = mainWindow.();
(dialog).();
});
});
Accessibility Testing
import { test, expect } from '../fixtures/electron-app';
import AxeBuilder from '@axe-core/playwright';
test.describe('Accessibility', () => {
test('main window should have no accessibility violations', async ({ mainWindow }) => {
const accessibilityScanResults = await new AxeBuilder({ page: mainWindow })
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
.analyze();
expect(accessibilityScanResults.violations).toEqual([]);
});
test('keyboard navigation should work', async ({ mainWindow }) => {
await mainWindow.keyboard.press('Tab');
const firstFocused = await mainWindow.evaluate(() =>
document.activeElement?.getAttribute('data-testid')
);
expect(firstFocused).toBeTruthy();
focusedElement = mainWindow.();
(focusedElement).();
});
(, ({ mainWindow }) => {
button = mainWindow.();
(button).();
liveRegion = mainWindow.();
(liveRegion).();
});
});
Electron API Mocks
import { ElectronApplication } from '@playwright/test';
export async function mockDialog(
electronApp: ElectronApplication,
response: { filePaths?: string[]; canceled?: boolean }
) {
await electronApp.evaluate(
async ({ dialog }, response) => {
dialog.showOpenDialog = async () => response;
dialog.showSaveDialog = async () => ({
filePath: response.filePaths?.[0],
canceled: response.canceled ?? false,
});
},
response
);
}
export async function mockClipboard(
electronApp: ElectronApplication,
content: string
) {
await electronApp.evaluate(
async ({ clipboard }, content) => {
clipboard.readText = () => content;
clipboard.writeText = () => {};
},
content
);
}
export async function mockShell() {
: [] = [];
electronApp.( ({ shell }) => {
shell. = (url) => {
;
};
});
{ openedUrls };
}
GitHub Actions CI Workflow
name: E2E Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
shardIndex: [1, 2, 3, 4]
shardTotal: [4]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Install dependencies
run: npm ci
- name: Build Electron app
run: npm
Best Practices
- Use data-testid attributes - Stable selectors for test automation
- Wait for app ready state - Use
waitForLoadState() before interactions
- Mock external dependencies - Dialog, shell, network calls
- Run tests in isolation - Fresh app instance per test when needed
- Use visual snapshots carefully - Allow pixel tolerance for CI variations
- Test on actual platforms - Cross-platform matrix in CI
Community References
Related Skills
electron-builder-config - Build configuration
electron-mock-factory - Mock Electron APIs
visual-regression-setup - Visual testing setup
accessibility-test-runner - Accessibility audits
Related Agents
desktop-test-architect - Testing strategy
ui-automation-specialist - UI automation expertise