This document provides a comprehensive guide for AI assistants to integrate Playwright MCP (Model Context Protocol) tools with Electron applications for automated testing.
- Overview
- Critical Environment Issue
- Playwright MCP Integration
- Functional Page Object Model (POM)
- Complete Implementation Guide
- Troubleshooting
- Best Practices
This guide demonstrates how to:
- Set up Playwright MCP tools for Electron testing
- Handle critical environment variable issues
- Implement functional Page Object Model patterns
- Create automated tests for Electron applications
- Debug and troubleshoot common issues
CRITICAL: The most common issue when running Electron tests in AI assistant shells is the ELECTRON_RUN_AS_NODE=1 environment variable.
Error: Process failed to launch!
When ELECTRON_RUN_AS_NODE=1 is set, Electron is forced to run as a Node.js process instead of as an Electron application, preventing proper app launch.
# Check for the problematic variable
env | grep ELECTRON_RUN_AS_NODE
# Unset it before running tests
unset ELECTRON_RUN_AS_NODE
pnpm testAI assistant shells often inherit environment variables from the host system that can interfere with Electron's normal operation. This variable is commonly set in development environments or CI/CD pipelines.
After unsetting the variable, tests should show:
✓ tests/electron.spec.ts:4:1 › navigate tabs in Electron app (1.1s)
✓ tests/simple.spec.ts:3:1 › Electron app starts (999ms)
✓ tests/simple-working.spec.ts:3:1 › simple working test (8ms)
3 passed (1.8s)
// Navigate to development server (recommended)
await mcp_playwright_playwright_navigate({
url: "http://localhost:5173",
headless: false
});
// Navigate to built files (may have CORS issues)
await mcp_playwright_playwright_navigate({
url: "file:///path/to/out/renderer/index.html",
headless: false
});// Take full page screenshot
await mcp_playwright_playwright_screenshot({
name: "electron-app-state",
savePng: true,
fullPage: true
});// Click elements
await mcp_playwright_playwright_click({
selector: "button:has-text('Reports')"
});
// Fill input fields
await mcp_playwright_playwright_fill({
selector: "input[name='username']",
value: "testuser"
});// Get visible text
const text = await mcp_playwright_playwright_get_visible_text({
random_string: "get_text"
});
// Get HTML content
const html = await mcp_playwright_playwright_get_visible_html({
maxLength: 5000
});// Get console logs
const logs = await mcp_playwright_playwright_console_logs({
type: "all"
});// Start code generation session
const session = await mcp_playwright_start_codegen_session({
options: {
outputPath: "/path/to/tests",
testNamePrefix: "ElectronTest",
includeComments: true
}
});
// Perform interactions...
// End session and generate test
await mcp_playwright_end_codegen_session({
sessionId: session.sessionId
});- URL:
http://localhost:5173 - Pros: No CORS issues, hot reload, better debugging
- Setup:
pnpm dev
- URL:
file:///path/to/out/renderer/index.html - Cons: CORS issues with JavaScript loading
- Workaround: Requires
webSecurity: falsein Electron config
// tests/pom/dashboard-page.ts
import { Page } from "@playwright/test";
export function createDashboardPage(page: Page) {
const selectors = {
homeTab: "#tab-home",
reportsTab: "#tab-reports",
settingsTab: "#tab-settings",
homeContent: "#home-content",
reportsContent: "#reports-content",
settingsContent: "#settings-content",
};
return {
selectors,
openHome: async () => page.click(selectors.homeTab),
openReports: async () => page.click(selectors.reportsTab),
openSettings: async () => page.click(selectors.settingsTab),
isHomeVisible: async () => page.isVisible(selectors.homeContent),
isReportsVisible: async () => page.isVisible(selectors.reportsContent),
isSettingsVisible: async () => page.isVisible(selectors.settingsContent),
};
}// tests/electron.spec.ts
import { _electron as electron, test, expect } from "@playwright/test";
import { createDashboardPage } from "./pom/dashboard-page";
test("navigate tabs in Electron app", async () => {
const electronApp = await electron.launch({
args: ["./out/main/index.js"],
timeout: 60000
});
const window = await electronApp.firstWindow();
await window.waitForLoadState('domcontentloaded');
const dashboard = createDashboardPage(window);
// Test navigation
await dashboard.openHome();
expect(await dashboard.isHomeVisible()).toBeTruthy();
await dashboard.openReports();
expect(await dashboard.isReportsVisible()).toBeTruthy();
await dashboard.openSettings();
expect(await dashboard.isSettingsVisible()).toBeTruthy();
await electronApp.close();
});- Reusability: Functions can be used across multiple tests
- Maintainability: UI changes only require updating the POM
- Readability: Tests read like user interactions
- Type Safety: Full TypeScript support
# Ensure ELECTRON_RUN_AS_NODE is not set
unset ELECTRON_RUN_AS_NODE
# Install dependencies
pnpm install
pnpm exec playwright install# Start Electron dev server
pnpm dev// Navigate to the app
await mcp_playwright_playwright_navigate({
url: "http://localhost:5173",
headless: false
});
// Take screenshot
await mcp_playwright_playwright_screenshot({
name: "initial-state",
savePng: true
});
// Interact with elements
await mcp_playwright_playwright_click({
selector: "button:has-text('Reports')"
});
// Verify content
const text = await mcp_playwright_playwright_get_visible_text({
random_string: "verify"
});// Start codegen session
const session = await mcp_playwright_start_codegen_session({
options: {
outputPath: "/path/to/tests",
testNamePrefix: "ElectronTest",
includeComments: true
}
});
// Perform test interactions
await mcp_playwright_playwright_click({
selector: "button:has-text('Home')"
});
// End session and generate test
await mcp_playwright_end_codegen_session({
sessionId: session.sessionId
});- Cause:
ELECTRON_RUN_AS_NODE=1is set - Solution:
unset ELECTRON_RUN_AS_NODE
- Cause: Browser security blocking local files
- Solution: Use development server (
http://localhost:5173)
- Cause: Module system incompatibilities
- Solution: Use electron-vite with proper configuration
- Cause: JavaScript files blocked by CORS
- Solution: Ensure
webSecurity: falsein Electron config
# Check versions
node --version # Should be v22.17.0 or compatible
pnpm --version # Should be v10.15.1 or compatible
# Check environment
env | grep -E "(NODE|ELECTRON|DISPLAY)" | sort
# Run simple test
pnpm test --grep "simple working test"- Always check and unset
ELECTRON_RUN_AS_NODEbefore testing - Use development server for MCP interactions
- Verify environment variables don't conflict with Electron
- Use
headless: falsefor visual debugging - Take screenshots at key interaction points
- Monitor console logs for errors
- Use code generation for complex test scenarios
- Create focused, single-responsibility functions
- Use descriptive function names
- Return promises for async operations
- Include both actions and assertions
- Start with simple tests to verify setup
- Use functional POM for complex interactions
- Include proper cleanup (close Electron app)
- Add meaningful test descriptions
- Use screenshots to verify visual state
- Check console logs for JavaScript errors
- Verify element selectors are correct
- Test interactions step by step
// 1. Setup environment
unset ELECTRON_RUN_AS_NODE
// 2. Start development server
pnpm dev
// 3. Navigate with MCP
await mcp_playwright_playwright_navigate({
url: "http://localhost:5173",
headless: false
});
// 4. Take initial screenshot
await mcp_playwright_playwright_screenshot({
name: "initial-state",
savePng: true
});
// 5. Start codegen session
const session = await mcp_playwright_start_codegen_session({
options: {
outputPath: "/path/to/tests",
testNamePrefix: "ElectronTest"
}
});
// 6. Perform test interactions
await mcp_playwright_playwright_click({
selector: "button:has-text('Reports')"
});
await mcp_playwright_playwright_click({
selector: "button:has-text('Settings')"
});
// 7. End session and generate test
await mcp_playwright_end_codegen_session({
sessionId: session.sessionId
});
// 8. Run generated tests
pnpm testThis comprehensive guide should enable any AI assistant to successfully integrate Playwright MCP tools with Electron applications for automated testing.