---
title: Electron App Testing with Playwright
description: Run Playwright tests against your Electron app in the cloud. Connect
  Playwright to your Electron app running on remote Windows and macOS machines.
source_url:
  html: https://testingbot.com/support/app-automate/electron/playwright
  md: https://testingbot.com/support/app-automate/electron/playwright/index.md
---
# Electron App Testing with Playwright

[Electron](https://electronjs.org/) apps embed a Chromium engine, which means [Playwright](https://playwright.dev/) can automate them through the Chrome DevTools Protocol (CDP). TestingBot starts your Electron app on a remote Windows or macOS machine and gives you a WebSocket endpoint that Playwright connects to with `chromium.connectOverCDP()`.

Your Playwright test code runs on your own machine or CI server, while the Electron app itself runs in the TestingBot cloud, on these platforms:

- Windows 11
- Windows 10
- macOS Tahoe
- macOS Sequoia
- macOS Sonoma
- macOS Ventura
- macOS Monterey

All Electron versions from version 16 to the most recent version are supported. If you prefer WebDriver (Selenium) over Playwright, please see [Electron testing with WebDriver](https://testingbot.com/support/app-automate/electron).

TestingBot has created a [demo Electron app](https://github.com/testingbot/testingbot-electron-demo-app), which acts as a simple calculator, to showcase automated Electron app testing. The examples below run against this demo app.

## Prepare your Electron app

TestingBot needs to be able to download your Electron app as a `zip` file. You can host this zip file yourself, for example on AWS S3 or GitHub Releases, or upload it to [TestingBot Storage](https://testingbot.com/support/api#upload), which returns a `tb://` URL you can use instead.

Next to the URL of the zip file, you also need to know the path of the actual Electron binary inside the zip file. This is the `binary_location` parameter, so TestingBot knows which file to launch. For the demo app on macOS this is:

    testingbot-electron-demo-app.app/Contents/MacOS/testingbot-electron-demo-app

On Windows, it is simply the executable in the zip file:

    testingbot-electron-demo-app.exe

See [App management](https://testingbot.com/support/app-automate/electron#capability-app) on the WebDriver Electron page for more details about uploading your app.

## Run your first test

Install `playwright-core`, connect with `chromium.connectOverCDP()` and pass the Electron parameters in the WebSocket URL. Once connected, your Electron app's window is available as the first page of the first browser context.

The `browserVersion` parameter must be the major Electron version your app was built with. The demo app was built with Electron 31, so the examples below use `browserVersion=31`.

    npm i playwright-core

[macOS](https://testingbot.com#)[Windows](https://testingbot.com#)

    const { chromium } = require('playwright-core');
    
    const app = 'https://github.com/testingbot/testingbot-electron-demo-app/releases/download/v1.0.0/testingbot-electron-demo-app-darwin-arm64-1.0.0.zip';
    const binaryLocation = 'testingbot-electron-demo-app.app/Contents/MacOS/testingbot-electron-demo-app';
    
    const wsEndpoint = 'wss://cloud.testingbot.com'
      + '?key=api_key&secret=api_secret'
      + '&browserName=electron'
      + '&browserVersion=31'
      + '&platform=TAHOE'
      + `&app=${encodeURIComponent(app)}`
      + `&binary_location=${encodeURIComponent(binaryLocation)}`
      + `&name=${encodeURIComponent('My First Electron Test')}`;
    
    (async () => {
      // Starting the remote machine and downloading your app can take a while
      const browser = await chromium.connectOverCDP(wsEndpoint, { timeout: 300000 });
    
      const context = browser.contexts()[0];
      const page = context.pages()[0]; // the Electron app window
    
      // Calculate 3 + 4 in the demo calculator app
      await page.click('#btn-3');
      await page.click('#btn-plus');
      await page.click('#btn-4');
      await page.click('#btn-equal');
    
      const result = await page.textContent('#calc-display');
      console.log(`3 + 4 = ${result}`);
    
      await browser.close();
    })();

    const { chromium } = require('playwright-core');
    
    const app = 'https://github.com/testingbot/testingbot-electron-demo-app/releases/download/v1.0.0/testingbot-electron-demo-app-win32-x64-1.0.0.zip';
    const binaryLocation = 'testingbot-electron-demo-app.exe';
    
    const wsEndpoint = 'wss://cloud.testingbot.com'
      + '?key=api_key&secret=api_secret'
      + '&browserName=electron'
      + '&browserVersion=31'
      + '&platform=WIN10'
      + `&app=${encodeURIComponent(app)}`
      + `&binary_location=${encodeURIComponent(binaryLocation)}`
      + `&name=${encodeURIComponent('My First Electron Test')}`;
    
    (async () => {
      // Starting the remote machine and downloading your app can take a while
      const browser = await chromium.connectOverCDP(wsEndpoint, { timeout: 300000 });
    
      const context = browser.contexts()[0];
      const page = context.pages()[0]; // the Electron app window
    
      // Calculate 3 + 4 in the demo calculator app
      await page.click('#btn-3');
      await page.click('#btn-plus');
      await page.click('#btn-4');
      await page.click('#btn-equal');
    
      const result = await page.textContent('#calc-display');
      console.log(`3 + 4 = ${result}`);
    
      await browser.close();
    })();

Make sure to use `chromium.connectOverCDP()` and the `wss://cloud.testingbot.com` endpoint for Electron tests. The `wss://cloud.testingbot.com/playwright` endpoint used for [Playwright browser testing](https://testingbot.com/support/web-automate/playwright) does not support Electron apps.

## Playwright Test

You can use the same connection with [Playwright Test](https://testingbot.com/support/web-automate/playwright/playwright-test), Playwright's own test runner. Connect in a `beforeAll` hook or fixture and run your suite with `npx playwright test`.

    const { test, expect, chromium } = require('@playwright/test');
    
    const app = 'https://github.com/testingbot/testingbot-electron-demo-app/releases/download/v1.0.0/testingbot-electron-demo-app-darwin-arm64-1.0.0.zip';
    const binaryLocation = 'testingbot-electron-demo-app.app/Contents/MacOS/testingbot-electron-demo-app';
    
    const wsEndpoint = 'wss://cloud.testingbot.com'
      + '?key=api_key&secret=api_secret'
      + '&browserName=electron'
      + '&browserVersion=31'
      + '&platform=TAHOE'
      + `&app=${encodeURIComponent(app)}`
      + `&binary_location=${encodeURIComponent(binaryLocation)}`
      + `&name=${encodeURIComponent('Electron Playwright Test')}`;
    
    test('calculator adds two numbers', async () => {
      test.setTimeout(600000); // remote machine startup can take a few minutes
      const browser = await chromium.connectOverCDP(wsEndpoint, { timeout: 300000 });
    
      const page = browser.contexts()[0].pages()[0];
    
      await page.click('#btn-3');
      await page.click('#btn-plus');
      await page.click('#btn-4');
      await page.click('#btn-equal');
    
      await expect(page.locator('#calc-display')).toHaveText('7');
    
      await browser.close();
    });

## Python

Playwright for Python offers the same `connect_over_cdp()` API, so you can test your Electron app from Python as well.

    pip install playwright

    from urllib.parse import quote
    from playwright.sync_api import sync_playwright
    
    app = "https://github.com/testingbot/testingbot-electron-demo-app/releases/download/v1.0.0/testingbot-electron-demo-app-darwin-arm64-1.0.0.zip"
    binary_location = "testingbot-electron-demo-app.app/Contents/MacOS/testingbot-electron-demo-app"
    
    ws_endpoint = (
        "wss://cloud.testingbot.com"
        "?key=api_key&secret=api_secret"
        "&browserName=electron"
        "&browserVersion=31"
        "&platform=TAHOE"
        f"&app={quote(app, safe='')}"
        f"&binary_location={quote(binary_location, safe='')}"
        "&name=Electron%20Playwright%20Python"
    )
    
    with sync_playwright() as p:
        # Starting the remote machine and downloading your app can take a while
        browser = p.chromium.connect_over_cdp(ws_endpoint, timeout=300000)
    
        page = browser.contexts[0].pages[0] # the Electron app window
    
        page.click("#btn-3")
        page.click("#btn-plus")
        page.click("#btn-4")
        page.click("#btn-equal")
    
        result = page.text_content("#calc-display")
        print(f"3 + 4 = {result}")
    
        browser.close()

## Connection parameters

All parameters are passed as query parameters in the WebSocket URL. Make sure to URL-encode the values, especially the `app` URL and `binary_location` path.

 Parameter | Description || `key` and `secret` | Your TestingBot [API credentials](https://testingbot.com/members/user/edit). |
| `browserName` | Must be `electron`. |
| `browserVersion` | The major Electron version your app was built with, for example `42`. TestingBot uses this to match the correct Chromium version. |
| `platform` | The operating system to run your app on, for example `TAHOE`, `SEQUOIA`, `WIN10` or `WIN11`. |
| `app` | URL of the zip file containing your Electron app, or a `tb://` URL from [TestingBot Storage](https://testingbot.com/support/api#upload). |
| `binary_location` | Path of the Electron binary inside the zip file. |
| `name` | Optional name for the test, shown in the [TestingBot dashboard](https://testingbot.com/members). |
| `build` | Optional build identifier to group multiple tests together. |

## Mark tests as passed or failed

Playwright does not report test success or failure to TestingBot by itself. You can use the `testingbot_executor` custom command from within your test to mark the session as passed or failed in the TestingBot dashboard.

    try {
      await expect(page.locator('#calc-display')).toHaveText('7');
      // Mark the test as passed on TestingBot
      await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({
        action: 'setSessionStatus',
        arguments: { passed: true, reason: 'Calculator sum matched' }
      })}`);
    } catch (err) {
      // Mark the test as failed on TestingBot
      await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({
        action: 'setSessionStatus',
        arguments: { passed: false, reason: 'Calculator sum did not match' }
      })}`);
      throw err;
    }

## Supported Playwright features

Playwright talks to your Electron app through the Chrome DevTools Protocol, which supports everything that operates on browser contexts and pages:

- Locators, clicking, typing and all other page interactions
- Assertions with `expect()`
- Screenshots
- Evaluating JavaScript in the renderer process with `page.evaluate()`
- Network inspection of requests made by your app's windows

Because your app runs on a remote machine, the Electron-specific APIs from Playwright's local `_electron.launch()` mode are not available. This means no `electronApp.evaluate()` access to the Electron main process, such as `app` or `BrowserWindow` modules. If you need to assert on main process behavior, expose that state to the renderer process, for example via IPC, and read it with `page.evaluate()`.

## Test Results

Every Electron Playwright test appears in the TestingBot member dashboard. For each test you get access to a video recording, log files and additional meta-data.

These results are also available through the TestingBot [REST-API](https://testingbot.com/support/api) or by using one of the [TestingBot CI/CD plugins](https://testingbot.com/support/integrations/ci-cd).

### Looking for more help?

Have questions or need more information? Reach out via email or Slack.

[Email us](https://testingbot.com/contact/new)[Slack Join our Slack](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw)
