Does Express Work With Playwright?

Fully CompatibleLast verified: 2026-02-26

Express and Playwright work together seamlessly for testing Express applications end-to-end, with Express serving as the application under test and Playwright automating browser interactions.

Quick Facts

Compatibility
full
Setup Difficulty
Easy
Official Integration
No — community maintained
Confidence
high
Minimum Versions
Express: 4.0.0
Playwright: 1.0.0

How Express Works With Playwright

Express and Playwright complement each other perfectly in a testing workflow. Express runs your backend application, while Playwright launches a real browser instance to interact with it. Typically, you'll start an Express server in your test setup, then use Playwright to navigate to localhost and verify UI behavior, form submissions, and API integrations. This approach captures real user workflows across Chrome, Firefox, and Safari simultaneously. The developer experience is straightforward: spin up your Express app, point Playwright to http://localhost:PORT, and write tests using Playwright's fluent API. One architectural consideration is test isolation—ensure each test suite either shares a single Express instance or spawns fresh ones to prevent state leakage. For CI/CD pipelines, containerize both Express and Playwright together or ensure the Express server starts before browser tests run.

Best Use Cases

Testing server-rendered HTML applications with form validation, navigation, and session management
Verifying API endpoints through browser interactions while capturing network logs and console errors
Cross-browser compatibility testing for Express-served static assets and template rendering
E2E testing of authentication flows, redirects, and cookie handling across multiple browsers

Quick Setup

bash
npm install express playwright @playwright/test
javascript
// test.spec.js
const { test, expect } = require('@playwright/test');
const express = require('express');
const http = require('http');

let server;

test.beforeAll(async () => {
  const app = express();
  app.get('/', (req, res) => res.send('<h1>Hello</h1>'));
  server = http.createServer(app);
  await new Promise(resolve => server.listen(3000, resolve));
});

test.afterAll(async () => {
  await new Promise(resolve => server.close(resolve));
});

test('should render home page', async ({ page }) => {
  await page.goto('http://localhost:3000');
  await expect(page.locator('h1')).toContainText('Hello');
});

Known Issues & Gotchas

critical

Express server may not be fully initialized when Playwright tests start, causing connection refused errors

Fix: Use a health check endpoint or retry logic in Playwright setup. Wait for the server to emit a 'listening' event before launching tests.

warning

Port conflicts when running parallel test suites, all trying to bind to the same port

Fix: Use dynamic ports (port 0 in Node.js), environment variables, or test workers that each get a unique port allocation.

warning

Session and cookie state persisting across test cases, causing flaky tests

Fix: Clear browser context cookies between tests or use isolated browser contexts for each test case.

info

Difficulty debugging when Express logs and Playwright logs are interleaved

Fix: Use separate loggers with prefixes, or redirect Express logs to a file during test runs.

Alternatives

  • Next.js + Playwright: Full-stack framework with built-in testing support and simpler server management
  • NestJS + Cypress: TypeScript-first backend framework paired with Cypress for alternative E2E testing
  • Django + Selenium: Python alternative offering similar Express + Playwright workflow for web testing

Resources

Related Compatibility Guides

Explore more compatibility guides