How to set up End-to-End (E2E) testing with Playwright
End-to-End (E2E) tests give you confidence that your collaborative features work correctly across multiple clients. This guide walks through setting up Playwright to test a Liveblocks-powered Next.js application using the local dev server, so your tests run locally or in CI, without hitting Liveblocks cloud APIs.
This guide assumes you already have a Liveblocks application set up. We'll use our Collaborative Todo List example as a reference throughout, but a similar approach works with any Liveblocks project.
Overview
The setup has two parts:
- Point your app at the local dev server instead of the Liveblocks cloud,
using the
baseUrlprop and usingpk_localdevas the public key. - Configure Playwright to start both the dev server and your app before tests run.
Step 1: Install dependencies
Add Playwright to your project:
Step 2: Configure your app for local development
The Liveblocks dev server accepts connections using the magic key pk_localdev
and runs on port 1153 by default. Pass these to your LiveblocksProvider via
environment variables so they can be overridden per environment:
Set the environment variables in your .env.local for everyday development, or
let Playwright inject them at test time (see Step 3).
The baseUrl prop redirects all Liveblocks traffic, including WebSocket
connections, to the given URL. When it is undefined, the client uses the
default Liveblocks cloud endpoint, so production builds are unaffected.
Step 3: Create a Playwright configuration
Create playwright.config.ts at the project root. The key idea is to use the
webServer option to start the
Liveblocks dev server and your Next.js app automatically:
A few things to note:
reuseExistingServer—Locally, this lets you leave the servers running between test runs for faster iteration. In CI, a fresh server is started each time.CIcheck—In CI, the dev server is provided by a Docker service container (see Running in CI), so we skip starting it viawebServer.- Environment variables—
NEXT_PUBLIC_LIVEBLOCKS_PUBLIC_KEYandNEXT_PUBLIC_LIVEBLOCKS_BASE_URLare injected into the Next.js build/dev process, pointing it at the local dev server.
Step 4: Write tests
Create a test file, e.g. test/todo.spec.ts. Each test navigates to a unique
room to avoid cross-test interference:
Testing multi-client collaboration
One of the most valuable things to test is that changes sync between clients. Playwright makes this straightforward—open a second page in the same browser context and point it at the same room:
Testing presence
You can also verify presence features like typing indicators:
Step 5: Run the tests
Playwright will automatically start the Liveblocks dev server and your Next.js app, run all tests, then shut everything down.
Running in CI
In CI environments like GitHub Actions, use the
Liveblocks dev server Docker image
as a service container instead of starting it via npx:
Key points:
NEXT_PUBLIC_env vars—These are set at the job level so they're available during bothnpm run build(where Next.js inlines them) and test execution.- Build before test—In CI, the Playwright config uses
next start(notnext dev), so the app must be built first. - Artifact upload—On failure, the Playwright HTML report is uploaded so you can debug test failures.
Complete example
The Next.js Todo List example in the Liveblocks repository includes a full Playwright test suite and a CI workflow built using this guide. You can use it as a starting point:
test/todo.spec.ts: Test file with 11 tests covering CRUD, toggle, multi-client sync, and typing indicators.playwright.config.ts: Playwright configuration for local dev server and Next.js web server setup..github/workflows/e2e-todo-list.yml: CI workflow with GitHub Actions pipeline using the dev server Docker image.
Tips
- Unique room IDs per test: The dev server persists storage to disk, so using unique room IDs prevents state from leaking between tests.
- Retries: Collaborative tests involve WebSocket connections and async
syncing. Adding a few retries in CI (
retries: 2or more) helps absorb occasional timing-related flakiness. - Traces: Setting
trace: "on-first-retry"captures a Playwright trace on the first retry, which is invaluable for debugging. reuseExistingServer: During local development, keep the dev server running separately (npx liveblocks dev) for faster test iteration.