Skip to content

Instantly share code, notes, and snippets.

@fnumatic
Created September 11, 2025 17:24
Show Gist options
  • Select an option

  • Save fnumatic/5c1def49ef222784288d3aaa6b2f9613 to your computer and use it in GitHub Desktop.

Select an option

Save fnumatic/5c1def49ef222784288d3aaa6b2f9613 to your computer and use it in GitHub Desktop.

Playwright MCP Integration with Electron Projects

This document provides a comprehensive guide for AI assistants to integrate Playwright MCP (Model Context Protocol) tools with Electron applications for automated testing.

Table of Contents

  1. Overview
  2. Critical Environment Issue
  3. Playwright MCP Integration
  4. Functional Page Object Model (POM)
  5. Complete Implementation Guide
  6. Troubleshooting
  7. Best Practices

Overview

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 Environment Issue

🚨 The ELECTRON_RUN_AS_NODE Problem

CRITICAL: The most common issue when running Electron tests in AI assistant shells is the ELECTRON_RUN_AS_NODE=1 environment variable.

Symptoms

Error: Process failed to launch!

Root Cause

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.

Solution

# Check for the problematic variable
env | grep ELECTRON_RUN_AS_NODE

# Unset it before running tests
unset ELECTRON_RUN_AS_NODE
pnpm test

Why This Happens

AI 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.

Verification

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)

Playwright MCP Integration

Core MCP Tools for Electron Testing

1. Navigation

// 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
});

2. Screenshots

// Take full page screenshot
await mcp_playwright_playwright_screenshot({
  name: "electron-app-state",
  savePng: true,
  fullPage: true
});

3. Element Interaction

// 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"
});

4. Content Verification

// 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
});

5. Console Monitoring

// Get console logs
const logs = await mcp_playwright_playwright_console_logs({
  type: "all"
});

6. Test Code Generation

// 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
});

Development Server vs Built Files

Development Server (Recommended)

  • URL: http://localhost:5173
  • Pros: No CORS issues, hot reload, better debugging
  • Setup: pnpm dev

Built Files

  • URL: file:///path/to/out/renderer/index.html
  • Cons: CORS issues with JavaScript loading
  • Workaround: Requires webSecurity: false in Electron config

Functional Page Object Model (POM)

Implementation Pattern

1. Create POM Functions

// 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),
  };
}

2. Use in Tests

// 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();
});

Benefits of Functional POM

  • 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

Complete Implementation Guide

Step 1: Environment Setup

# Ensure ELECTRON_RUN_AS_NODE is not set
unset ELECTRON_RUN_AS_NODE

# Install dependencies
pnpm install
pnpm exec playwright install

Step 2: Start Development Server

# Start Electron dev server
pnpm dev

Step 3: Test with MCP Tools

// 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"
});

Step 4: Generate Test Code

// 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
});

Troubleshooting

Common Issues

1. "Process failed to launch!"

  • Cause: ELECTRON_RUN_AS_NODE=1 is set
  • Solution: unset ELECTRON_RUN_AS_NODE

2. CORS Errors with file:// URLs

  • Cause: Browser security blocking local files
  • Solution: Use development server (http://localhost:5173)

3. ES Modules/CommonJS Conflicts

  • Cause: Module system incompatibilities
  • Solution: Use electron-vite with proper configuration

4. React App Not Loading

  • Cause: JavaScript files blocked by CORS
  • Solution: Ensure webSecurity: false in Electron config

Environment Verification

# 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"

Best Practices

1. Environment Management

  • Always check and unset ELECTRON_RUN_AS_NODE before testing
  • Use development server for MCP interactions
  • Verify environment variables don't conflict with Electron

2. MCP Tool Usage

  • Use headless: false for visual debugging
  • Take screenshots at key interaction points
  • Monitor console logs for errors
  • Use code generation for complex test scenarios

3. POM Design

  • Create focused, single-responsibility functions
  • Use descriptive function names
  • Return promises for async operations
  • Include both actions and assertions

4. Test Structure

  • Start with simple tests to verify setup
  • Use functional POM for complex interactions
  • Include proper cleanup (close Electron app)
  • Add meaningful test descriptions

5. Debugging

  • Use screenshots to verify visual state
  • Check console logs for JavaScript errors
  • Verify element selectors are correct
  • Test interactions step by step

Example Complete Test Flow

// 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 test

This comprehensive guide should enable any AI assistant to successfully integrate Playwright MCP tools with Electron applications for automated testing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment