Electron App Testing Checklist: Native APIs, IPC, Auto-Updates, and Security

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
  • webPreferences has contextIsolation: true and nodeIntegration: false
  • webPreferences has sandbox: true for untrusted content

App Lifecycle

  • app.requestSingleInstanceLock() prevents multiple instances
  • Second instance focus-raises the existing window (not opens a new one)
  • App handles before-quit event 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
  • 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.url to 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.exposeInMainWorld is used — no nodeIntegration: true shortcut
  • 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 updates
  • update-not-available event fires correctly when up to date
  • update-available event fires with correct version info
  • Download progress events fire and have correct percent values
  • update-downloaded event fires after download completes
  • quitAndInstall() 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 (isDev check)

Security Testing

Context Isolation

  • contextIsolation: true in all BrowserWindow webPreferences
  • nodeIntegration: false — renderer process has no direct Node access
  • enableRemoteModule: 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-eval or unsafe-inline in script-src
  • CSP default-src is restrictive

Protocol Security

  • Custom protocol handler doesn't expose file system access
  • new-window events 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, not Command or Ctrl alone
  • 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.electronAPI dependency in logic)
  • window.electronAPI is 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 (electron module mocked in Jest)
  • electron-mock-ipc or manual mocks used for IPC testing
  • 80%+ unit test coverage for main process business logic

Integration Tests

  • Playwright with @playwright/test electron fixture
  • 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-latest in GitHub Actions matrix
  • xvfb-run configured 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.yml before 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:

  1. IPC handler unit tests — catches the most common bugs in the main-renderer boundary
  2. Cross-platform CI — runs on all three platforms to catch platform-specific bugs early
  3. Security checks — contextIsolation, nodeIntegration, and shell.openExternal validation
  4. 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.

Read more

Start now free