What is Playwright?
Playwright is a modern automation and testing framework built by Microsoft. It allows you to write end-to-end (E2E) tests for your web apps that run across multiple browsers and devices — including Chromium, Firefox, and WebKit, both desktop and mobile.
At its core, Playwright is designed for speed, reliability, and real-world testing.
Unlike older tools that rely on flaky DOM polling, Playwright takes a “web-first assertions” approach — it automatically waits for elements to become visible before interacting with them.
How Playwright Works
Playwright consists of two key parts:
- Node Controller (Test Runner) — This is where your test scripts live.
- Browser Instance — A new instance that Playwright launches for each test run.
They communicate through a WebSocket connection, allowing real-time, bi-directional messaging.
This architecture makes Playwright faster and more efficient than many other frameworks.
When you run a test, the Node controller sends commands (like click
, fill
, or goto
) to the browser.
The browser executes those commands and returns the results.
Let's visualize this communication:
- The Node Controller instructs the browser: "Click the 'Submit' button."
- The Browser responds: "Click registered. Initiating an API call to /api/login."
The Node Controller, if configured with page.route(), can intercept that request and fulfill it with a mocked response, making the test fast and independent of backend services.
Why Playwright
From my experience, it comes down to a few critical features that eliminate common testing headaches:
- Parallel Execution: Run your test suites significantly faster by executing tests concurrently.
- No More Flaky Tests: Playwright's built-in smart assertions wait for elements to be ready, visible, and stable. Instead of adding arbitrary setTimeout calls everywhere.
Codegen — Write Tests Without Writing Them
One of my favorite features is Playwright Codegen.
You can open your app, interact with it, and Playwright will automatically generate the corresponding test code for you. Just one command and you can start interaction with the website and genetate test code.
npx playwright codegen
Understanding Fixtures
In testing, a fixture is a predefined state or environment that ensures your tests are consistent and repeatable. Think of it as a "setup" that gives the same answer every time it's requested.
Playwright uses fixtures extensively. Here are a few powerful examples:
Image Upload Fixture: Create a reusable fixture that provides a test image file, so every test that needs to upload a file doesn't have to manage the file path separately.
API Interception Fixture: Intercept costly third-party API calls and return a predefined, reliable JSON response. This makes your tests fast, deterministic, and free from external service outages.
Integrating Playwright with Next.js
Step 1 : Installation
install Playwright in your Next.js project:
npm install -D @playwright/test
npx playwright init
The init command sets up the default configuration and creates the tests/ directory.
Step 2: Configuration
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './e2e', // Folder where your tests live
timeout: 30000, // Test will fail if it exceeds 30 seconds
retries: 1, // Retry failed tests once for CI stability
workers: 4, // Run tests in parallel with 4 workers
use: {
baseURL: 'http://localhost:3000', // Your Next.js dev server URL
viewport: { width: 1280, height: 720 },
// Record video only when retrying a failed test
},
// Define your browser and device matrix
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
{ name: 'webkit', use: { ...devices['Desktop Safari'] } },
// Uncomment to add mobile testing
// { name: 'Mobile Chrome', use: { ...devices['Pixel 5'] } },
],
});
Step 3: Writing Your First Test
create a test inside e2e/home.spec.ts. Playwright's page fixture provides a clean, isolated browser context for each test.
import { test, expect } from '@playwright/test';
test('homepage has correct title and welcome message', async ({ page }) => {
// Navigate to the homepage
await page.goto('/');
// Assert that the page title contains "Next.js"
await expect(page).toHaveTitle(/Next.js/);
// Use a locator to find an element and assert its text
const welcomeMessage = page.getByRole('heading', { name: 'Welcome to Our App' });
await expect(welcomeMessage).toBeVisible();
});
Running Tests in Different Modes
You can run Playwright tests with different flags and modes:
- Headed mode (UI): Opens the Playwright UI to visualize test runs.
npx playwright test --ui
- Headless mode: Runs quietly without opening a browser window.
`
npx playwright test
- Specify browser:
npx playwright test --project=chromium
npx playwright test --project=firefox
You can add these command in your package.json file based on your requirement.
⚠️ Note on Mocking: MSW with Playwright vs Jest
If you're coming from Jest and are used to mocking API calls with MSW (Mock Service Worker), there's a crucial architectural difference:
- In Jest: Your tests run in a Node.js environment, and MSW operates at the Node level
- In Playwright: API calls happen in the actual browser context, while the test runner operates in Node.js
This means your existing MSW handlers won't automatically work with Playwright.
To use MSW with Playwright, you need to:
- Start MSW within the browser context (web worker)
- Ensure your mock service worker is registered and active in the page
Alternative: Playwright provides built-in API mocking via page.route()
which is often simpler for E2E tests.
Try It Yourself
If you want to see Playwright running in a real-world project
check out this demo repo:
AI Studio (GitHub)
Top comments (0)