Electron App Testing Checklist: Native APIs, IPC, Auto-Updates, and Security
Electron apps have more moving parts than web apps: a main process, renderer processes, IPC communication, native OS integration, auto-update logic, and cross-platform behavior to verify. Without a systematic testing approach, important areas get missed.
This checklist covers every major testing category for Electron apps. Use it when setting up your test suite from scratch or auditing your existing coverage.
Main Process Testing
The main process is Node.js code that controls the app lifecycle, windows, and native integrations.
Window Management
- App creates main window with correct dimensions on first launch
- Window position and size persist across app restarts (stored in preferences)
- Window is centered on first launch
- App handles multiple monitors correctly (no window off-screen)
- App restores from system tray correctly
- Windows close correctly and don't leak memory
webPreferenceshascontextIsolation: trueandnodeIntegration: falsewebPreferenceshassandbox: truefor untrusted content
App Lifecycle
app.requestSingleInstanceLock()prevents multiple instances- Second instance focus-raises the existing window (not opens a new one)
- App handles
before-quitevent to save state - Windows close on macOS when Cmd+Q is pressed
- macOS: app stays in dock when last window is closed (common pattern)
- Windows/Linux: app quits when last window is closed
Deep Links (if applicable)
- Custom protocol handler is registered
- App opens from custom protocol URL
- Deep link data is passed to the renderer
- Deep link doesn't work if protocol is registered to different app
IPC Communication
Inter-process communication between main and renderer.
Handler Registration
- All
ipcMain.handle()channels are registered before windows are created - No duplicate handler registrations (causes error in Electron)
- Handlers are unregistered when no longer needed to prevent leaks
Security
- All IPC handlers validate
event.senderFrame.urlto verify sender origin - Handlers reject requests from unexpected origins
- No sensitive operations (file system access, credentials) exposed without validation
shell.openExternal()only opens HTTPS, HTTP, and mailto: — never file: or javascript:
Preload Script
contextBridge.exposeInMainWorldis used — nonodeIntegration: trueshortcut- Only necessary APIs are exposed (principle of least privilege)
- Exposed APIs validate inputs before calling
ipcRenderer.invoke
Error Handling
- IPC errors are handled gracefully in the renderer (no unhandled rejections)
- Errors return structured responses, not raw Error objects
- Renderer shows user-friendly error messages on IPC failure
File System and Native APIs
File Operations
- File paths use
path.join()— no hardcoded separators - File read/write handles
EACCES(permission denied) gracefully - File read handles
ENOENT(file not found) gracefully app.getPath('userData')used for user data, not hardcoded paths- Large files don't block the main process (use streams or worker threads)
Dialog Testing
- File open dialog filters work correctly
- Dialog cancellation is handled (canceled: true case)
- Default path in save dialogs is sensible
- Multi-file selection works if enabled
System Tray (if applicable)
- Tray icon is created on app start
- Tray icon changes state correctly (active/inactive/error)
- Right-click context menu has all expected items
- Tray left-click behavior matches platform conventions (left-click = show on Windows, menu on macOS)
- Tray is destroyed when app quits
Notifications (if applicable)
Notification.isSupported()checked before creating notifications- Notification click handler works
- Notifications don't stack when called rapidly
- Notifications respect OS Do Not Disturb settings (this is OS-handled but verify no errors)
Clipboard (if applicable)
- Text copy/paste works
- Image copy/paste works
- Large clipboard content doesn't cause performance issues
- Clipboard is cleared on sensitive data actions if required
Auto-Update Testing
autoUpdater.checkForUpdates()correctly detects available updatesupdate-not-availableevent fires correctly when up to dateupdate-availableevent fires with correct version info- Download progress events fire and have correct
percentvalues update-downloadedevent fires after download completesquitAndInstall()is called with correct parameters (isSilent, isForceRunAfter)- Update error is handled gracefully with user notification
- Update check works offline (handles network failure without crashing)
- Update server URL is correct for all platforms (latest.yml, latest-mac.yml, latest-linux.yml)
- Version comparison correctly identifies newer version
- Auto-update disabled correctly in development (
isDevcheck)
Security Testing
Context Isolation
contextIsolation: truein all BrowserWindow webPreferencesnodeIntegration: false— renderer process has no direct Node accessenableRemoteModule: false(deprecated in Electron 14, but verify if using older version)allowRunningInsecureContent: false
Content Security Policy
- CSP header set in
webContents.session.webRequest.onHeadersReceived - CSP doesn't allow
unsafe-evalorunsafe-inlineinscript-src - CSP
default-srcis restrictive
Protocol Security
- Custom protocol handler doesn't expose file system access
new-windowevents are handled (blocked or opened in default browser)- Navigation to external URLs uses
shell.openExternal(), not in-app navigation
Permissions
- Unnecessary permissions are denied via
session.setPermissionRequestHandler - Camera/microphone access requires explicit user permission
- Geolocation access is blocked unless your app needs it
Cross-Platform Testing
- Tests run on Windows, macOS, and Linux in CI
- Keyboard shortcuts use
CmdOrCtrl, notCommandorCtrlalone - Path separators use
path.join()throughout - App works at 100%, 125%, 150%, and 200% display scaling
- Linux: app runs without Electron crashes on various distros
- Windows: app doesn't require admin for normal operations
- macOS: app passes basic notarization requirements (if distributing)
Performance Testing
- App startup time is acceptable (<3s cold start)
- Main window renders before time-to-interactive on reasonable hardware
- Memory usage doesn't grow unboundedly during normal use
- IPC calls complete within acceptable latency (<100ms for non-IO operations)
- File operations don't block the UI (renderer stays responsive)
- Renderer process heap size stays reasonable over time (no memory leaks)
Renderer Process Testing
Component Testing (React/Vue/Angular)
- Components are tested independently of Electron (no
window.electronAPIdependency in logic) window.electronAPIis mocked in component tests- Error boundaries catch and display IPC failures
- Loading states are tested for async IPC operations
Update UI
- Update checking state shows indicator
- Update available shows notification with version info
- Download progress shows progress bar
- Update downloaded shows install button
- Update error shows error message with retry option
- Update banner dismissible if user wants to install later
Testing Infrastructure
Unit Tests
- Main process handlers extracted into testable functions (not inline lambdas)
- Electron APIs mocked (
electronmodule mocked in Jest) electron-mock-ipcor manual mocks used for IPC testing- 80%+ unit test coverage for main process business logic
Integration Tests
- Playwright with
@playwright/testelectronfixture - E2E tests cover critical user flows (open file, save, update check)
- E2E tests run on CI for all platforms in matrix
CI Configuration
ubuntu-latest,macos-latest,windows-latestin GitHub Actions matrixxvfb-runconfigured for Linux E2E tests- Native module rebuild step included (
electron-rebuild) - Test artifacts (screenshots, logs) uploaded on failure
Release Testing Checklist
Before each release:
- All automated tests pass on all platforms
- Manual smoke test on fresh install (no prior data)
- Manual smoke test on upgrade from previous release
- Auto-update tested: previous version → new version
- Windows: Code signing is valid (users don't see "unknown publisher")
- macOS: App is notarized (passes Gatekeeper)
- Linux: .deb, .rpm, and .AppImage all work
- Privacy policy and EULA are current
- Release notes are written
- Update server is updated with new
latest.ymlbefore release
Tools Reference
| Category | Tool |
|---|---|
| Unit testing | Jest |
| E2E testing | Playwright (@playwright/test with electron fixture) |
| Mocking Electron | jest-mock-extended, manual mocks |
| Security audit | electronegativity, npm audit |
| Build and packaging | electron-builder |
| Update testing | Mock HTTP server for latest.yml |
| Performance profiling | Chrome DevTools (built into Electron) |
| Cross-platform CI | GitHub Actions matrix strategy |
Summary
Electron testing is complex because the app has multiple processes with different testing requirements. The highest-value tests to implement first:
- IPC handler unit tests — catches the most common bugs in the main-renderer boundary
- Cross-platform CI — runs on all three platforms to catch platform-specific bugs early
- Security checks —
contextIsolation,nodeIntegration, andshell.openExternalvalidation - Auto-update unit tests — prevents shipping broken update logic
Use this checklist at the start of a new project and as a pre-release audit. Coverage gaps identified now are much cheaper to address than production issues later.