Claude
Skills
Sign in
Back

playwright-electron-config

Included with Lifetime
$97 forever

Configure Playwright for comprehensive Electron application testing including E2E tests, visual regression, accessibility audits, and cross-platform test matrices

Code Reviewelectrontestingplaywrighte2eautomation

What this skill does


# playwright-electron-config

Configure Playwright for comprehensive Electron application testing. This skill sets up the complete testing infrastructure including E2E tests, visual regression testing, accessibility audits, and cross-platform test matrices with CI/CD integration.

## Capabilities

- Configure Playwright for Electron with `_electron` fixture
- Generate page object models for Electron windows
- Set up visual regression testing with snapshots
- Configure accessibility testing with axe-core
- Create cross-platform test matrices for CI
- Mock Electron APIs (dialog, shell, clipboard)
- Test IPC communication between main and renderer
- Generate test coverage reports

## Input Schema

```json
{
  "type": "object",
  "properties": {
    "projectPath": {
      "type": "string",
      "description": "Path to the Electron project root"
    },
    "testDir": {
      "type": "string",
      "default": "tests/e2e"
    },
    "features": {
      "type": "array",
      "items": {
        "enum": [
          "visualRegression",
          "accessibility",
          "coverage",
          "performance",
          "ipcTesting",
          "multiWindow",
          "systemDialogMocks"
        ]
      },
      "default": ["visualRegression", "accessibility", "ipcTesting"]
    },
    "platforms": {
      "type": "array",
      "items": { "enum": ["windows", "macos", "linux"] },
      "default": ["windows", "macos", "linux"]
    },
    "pageObjects": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "selectors": { "type": "object" }
        }
      },
      "description": "Page objects to generate"
    },
    "ciIntegration": {
      "type": "object",
      "properties": {
        "provider": { "enum": ["github-actions", "azure-devops", "circleci", "gitlab"] },
        "parallelization": { "type": "boolean", "default": true },
        "sharding": { "type": "number", "description": "Number of shards" }
      }
    }
  },
  "required": ["projectPath"]
}
```

## Output Schema

```json
{
  "type": "object",
  "properties": {
    "success": { "type": "boolean" },
    "files": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "path": { "type": "string" },
          "type": { "enum": ["config", "fixture", "pageObject", "test", "helper", "ci"] }
        }
      }
    },
    "commands": {
      "type": "object",
      "properties": {
        "runTests": { "type": "string" },
        "updateSnapshots": { "type": "string" },
        "showReport": { "type": "string" }
      }
    },
    "ciWorkflow": {
      "type": "string",
      "description": "Path to generated CI workflow file"
    }
  },
  "required": ["success", "files"]
}
```

## Generated File Structure

```
tests/
  e2e/
    playwright.config.ts     # Main Playwright config
    fixtures/
      electron-app.ts        # Electron fixture
      test-utils.ts          # Test utilities
    page-objects/
      MainWindow.ts          # Page object models
      SettingsDialog.ts
    specs/
      app.spec.ts            # Application tests
      ipc.spec.ts            # IPC tests
      visual.spec.ts         # Visual regression
      a11y.spec.ts           # Accessibility tests
    mocks/
      electron-api-mocks.ts  # Electron API mocks
      ipc-mocks.ts           # IPC mocks
    snapshots/               # Visual snapshots
    reports/                 # Test reports
```

## Code Templates

### Playwright Configuration for Electron

```typescript
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests/e2e/specs',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  reporter: [
    ['html', { outputFolder: 'tests/e2e/reports' }],
    ['json', { outputFile: 'tests/e2e/reports/results.json' }],
  ],
  use: {
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
  },
  projects: [
    {
      name: 'electron',
      testMatch: '**/*.spec.ts',
    },
  ],
});
```

### Electron Test Fixture

```typescript
// fixtures/electron-app.ts
import { test as base, ElectronApplication, Page } from '@playwright/test';
import { _electron as electron } from 'playwright';
import path from 'path';

export type TestFixtures = {
  electronApp: ElectronApplication;
  mainWindow: Page;
};

export const test = base.extend<TestFixtures>({
  electronApp: async ({}, use) => {
    // Launch Electron app
    const electronApp = await electron.launch({
      args: [path.join(__dirname, '../../dist/main/main.js')],
      env: {
        ...process.env,
        NODE_ENV: 'test',
      },
    });

    // Use the app in tests
    await use(electronApp);

    // Cleanup
    await electronApp.close();
  },

  mainWindow: async ({ electronApp }, use) => {
    // Wait for first window
    const window = await electronApp.firstWindow();

    // Wait for app to be ready
    await window.waitForLoadState('domcontentloaded');

    await use(window);
  },
});

export { expect } from '@playwright/test';
```

### Page Object Model

```typescript
// page-objects/MainWindow.ts
import { Page, Locator } from '@playwright/test';

export class MainWindow {
  readonly page: Page;
  readonly titleBar: Locator;
  readonly sidebar: Locator;
  readonly mainContent: Locator;
  readonly statusBar: Locator;

  constructor(page: Page) {
    this.page = page;
    this.titleBar = page.locator('[data-testid="title-bar"]');
    this.sidebar = page.locator('[data-testid="sidebar"]');
    this.mainContent = page.locator('[data-testid="main-content"]');
    this.statusBar = page.locator('[data-testid="status-bar"]');
  }

  async getTitle(): Promise<string> {
    return this.page.title();
  }

  async openSettings(): Promise<void> {
    await this.page.click('[data-testid="settings-button"]');
    await this.page.waitForSelector('[data-testid="settings-dialog"]');
  }

  async navigateTo(section: string): Promise<void> {
    await this.sidebar.locator(`[data-section="${section}"]`).click();
    await this.page.waitForLoadState('networkidle');
  }

  async screenshot(name: string): Promise<Buffer> {
    return this.page.screenshot({ path: `tests/e2e/snapshots/${name}.png` });
  }
}
```

### IPC Testing

```typescript
// specs/ipc.spec.ts
import { test, expect } from '../fixtures/electron-app';

test.describe('IPC Communication', () => {
  test('should send message to main process', async ({ electronApp, mainWindow }) => {
    // Evaluate in main process
    const result = await electronApp.evaluate(async ({ ipcMain }) => {
      return new Promise((resolve) => {
        ipcMain.once('test-channel', (event, data) => {
          resolve(data);
        });
      });
    });

    // Send from renderer
    await mainWindow.evaluate(() => {
      window.electronAPI.send('test-channel', { message: 'hello' });
    });

    // Verify
    expect(result).toEqual({ message: 'hello' });
  });

  test('should receive response from main process', async ({ mainWindow }) => {
    const response = await mainWindow.evaluate(async () => {
      return window.electronAPI.invoke('get-app-version');
    });

    expect(response).toMatch(/^\d+\.\d+\.\d+$/);
  });
});
```

### Visual Regression Testing

```typescript
// specs/visual.spec.ts
import { test, expect } from '../fixtures/electron-app';
import { MainWindow } from '../page-objects/MainWindow';

test.describe('Visual Regression', () => {
  test('main window matches snapshot', async ({ mainWindow }) => {
    const page = new MainWindow(mainWindow);

    // Wait for animations to complete
    await mainWindow.waitForTimeout(500);

    await expect(mainWindow).toHaveScreenshot('main-window.png', {
      maxDiffPixels: 100,
    });
  });

  test('dark mode matches snapshot', async ({ electronApp, mainWindow }) => {
    /

Related in Code Review