Electron Visual Testing
visual-testing-desktop-electron
Load when running visual validation for Electron desktop apps. Provides Playwright Electron API patterns.
SKILL.md
Full skill instructions
Electron Visual Testing
Platform: desktop-electron
Applicable Recipes: electron-react
Primary Tools: Playwright Electron, Storybook, Percy
🔄 Tight Loop (Default)
Goal: One command to validate the main window and key changed flows with screenshots.
Start Small:
- Windows: Main window + 1–2 windows/routes touched by the story
- Sizes: Normal size (1280×800) first; add small/maximized only if layout is in scope
- Themes: Light mode first; add dark mode only if story affects theming
Run Order:
- Launch Electron app via Playwright
- Capture main window screenshot
- Navigate to changed routes, capture each
- If diffs occur: determine intended vs unintended, update snapshots or fix UI
Expand Only When:
- Story explicitly covers multiple window sizes
- Story involves multi-window interactions
- Epic validation requires full window state matrix
⚡ Playwright Electron API
Electron bundles Chromium, ensuring consistent rendering. Playwright provides first-class support.
Launching the App
import { _electron as electron } from 'playwright';
const electronApp = await electron.launch({
args: ['path/to/your/app']
});
// Get the first window
const window = await electronApp.firstWindow();
// Wait for app to load
await window.waitForLoadState('domcontentloaded');
Taking Screenshots
// Full window screenshot
await window.screenshot({ path: 'screenshots/main-window.png' });
// Element screenshot
const header = window.locator('[data-testid="header"]');
await header.screenshot({ path: 'screenshots/header.png' });
// Visual assertion (for CI)
await expect(window).toHaveScreenshot('main-window.png');
Window State Testing
// Normal size
await window.setViewportSize({ width: 1280, height: 800 });
await window.screenshot({ path: 'screenshots/normal.png' });
// Small window
await window.setViewportSize({ width: 800, height: 600 });
await window.screenshot({ path: 'screenshots/small.png' });
// Maximized (platform-specific)
await electronApp.evaluate(async ({ BrowserWindow }) => {
const win = BrowserWindow.getAllWindows()[0];
win.maximize();
});
await window.screenshot({ path: 'screenshots/maximized.png' });
Theme Testing
// Force dark mode
await electronApp.evaluate(async ({ nativeTheme }) => {
nativeTheme.themeSource = 'dark';
});
await window.screenshot({ path: 'screenshots/dark-mode.png' });
// Force light mode
await electronApp.evaluate(async ({ nativeTheme }) => {
nativeTheme.themeSource = 'light';
});
await window.screenshot({ path: 'screenshots/light-mode.png' });
🪟 Multi-Window Testing
If the app opens multiple windows:
// Wait for second window to open
const [secondWindow] = await Promise.all([
electronApp.waitForEvent('window'),
window.click('[data-testid="open-settings"]')
]);
// Capture secondary window
await secondWindow.screenshot({ path: 'screenshots/settings-window.png' });
// Test modal dialogs
await window.click('[data-testid="open-dialog"]');
await window.screenshot({ path: 'screenshots/dialog-open.png' });
🖥️ Cross-Platform Considerations
Electron renders consistently due to bundled Chromium, but test on:
- macOS: Primary development
- Windows: Most users
- Linux: CI environment
Platform-Specific Baselines (if needed):
screenshots/
├── main-window-darwin.png
├── main-window-win32.png
└── main-window-linux.png
// Dynamic baseline selection
const platform = process.platform;
await expect(window).toHaveScreenshot(`main-window-${platform}.png`);
🔧 Test Commands
# Run Electron visual tests
npx playwright test --project=electron
# Update baselines when changes are intentional
npx playwright test --project=electron --update-snapshots
# Run specific test file
npx playwright test tests/visual/main-window.spec.ts
✅ Validation Checklist
Verify these for each validation:
- Main window captured in normal size
- Key routes/screens captured
- Light mode tested (dark if story touches theming)
- Window resize behavior works (if in scope)
- Secondary windows/dialogs captured (if applicable)
- No console errors in main process
- No console errors in renderer process
🔗 Storybook Integration
If using Storybook for component development:
# Run Storybook for Electron renderer components
npm run storybook
# Visual regression with Chromatic
npx chromatic --project-token=xxx
Components can be tested in isolation before full app integration.
