Decorative background gradient
Back to Blog
Playwright NextjsE2e TestingCi Cd Testing

Playwright E2E Testing in Next.js — Complete Guide

Set up Playwright for end-to-end testing in a Next.js app — auth state reuse, API mocking, visual regression, and running tests in CI.

Playwright E2E Testing in Next.js — Complete Guide

Playwright has become the standard for Next.js end-to-end testing because it handles the two hardest parts of E2E testing well: authenticated flows and flaky network conditions. Here's a full setup.

Step 1: Install and Initialize Playwright

bash

This scaffolds playwright.config.ts and a tests/ directory, and installs browser binaries for Chromium, Firefox, and WebKit.

ts

Using the production build in webServer.command — not next dev — matters because dev-mode behavior (slower compilation, different error overlays) doesn't reflect what ships.

Step 2: Write a Basic Test

ts

Step 3: Reuse Authentication Across Tests

Logging in via the UI before every test is slow and brittle. Instead, authenticate once in a setup project and save the session.

ts
ts

Every test in the chromium project now starts already signed in, with no login flow executed per test.

Step 4: Mock API Responses to Test Edge Cases

ts

Route interception lets you deterministically test loading, empty, and error states that are otherwise hard to reproduce against a real backend.

Step 5: Add Visual Regression Tests

ts

The first run generates a baseline image; subsequent runs fail if the rendered page differs beyond a configurable pixel threshold, catching visual regressions that functional assertions wouldn't notice.

Step 6: Run Playwright in CI

yaml

Uploading the HTML report as an artifact even on failure (if: always()) is what makes failing CI runs debuggable — the report includes screenshots and traces for every failed step.

Key Takeaways

Playwright's storageState mechanism removes login overhead from every test, route interception makes error and edge-case states testable without a real failing backend, and running against a production build rather than the dev server in CI is what keeps test results representative of what actually ships.

Frequently Asked Questions

Should I test against next dev or next build && next start in CI?

Use the production build (next build && next start) in CI. The dev server has different caching, bundling, and error-overlay behavior than production, so tests passing against next dev can still fail against what actually ships — Playwright's webServer config can run either, but production is the more reliable signal.

How do I avoid logging in before every single Playwright test?

Run a one-time setup project that logs in and saves the authenticated session with page.context().storageState({ path: "auth.json" }), then configure your other test projects to load that file as their starting storageState. Every test then starts already authenticated.

How do I test error states without a real failing backend?

Use page.route() to intercept the specific API call and return a mocked error response (e.g. status 500) before the page loads. This tests your app's error-handling UI deterministically, without needing to actually break a real service.

Does Playwright test multiple browsers by default?

Yes — the default Playwright config defines projects for Chromium, Firefox, and WebKit, and running npx playwright test executes your suite against all three unless you filter with --project. This catches Safari/WebKit-specific bugs that a Chrome-only test suite would miss.

Working on something similar? Take a look at my services and case studies, or book a free call to talk about your idea.

Related Articles

Caching Strategies and Cache Invalidation — The Complete Guide
CachingSystem DesignPerformance

Caching Strategies and Cache Invalidation — The Complete Guide

A practical guide to caching strategies (cache-aside, write-through, write-behind) and the cache invalidation techniques that keep them from serving stale data.

September 8, 2026Read more →
Database Indexing and Read Replicas — A Practical Guide
DatabasePostgreSQLSystem Design

Database Indexing and Read Replicas — A Practical Guide

How to choose the right database indexes, avoid the ones that quietly hurt write performance, and scale reads with replicas without introducing replication lag bugs.

September 8, 2026Read more →
Load Balancing and Stateless Service Design — A Practical Guide
System DesignLoad BalancingScalability

Load Balancing and Stateless Service Design — A Practical Guide

How load balancers distribute traffic, why stateless services are what actually makes horizontal scaling work, and how to fix the sticky-session traps that quietly reintroduce state.

September 8, 2026Read more →
Session Stores and Database Connection Pooling Explained
BackendRedisDatabase

Session Stores and Database Connection Pooling Explained

Why in-memory sessions break horizontally scaled apps, how to move session state to Redis correctly, and how connection pooling keeps your database from falling over under concurrent load.

September 8, 2026Read more →
Vertical vs Horizontal Scaling: How to Choose and Implement Each
System DesignScalabilityArchitecture

Vertical vs Horizontal Scaling: How to Choose and Implement Each

A practical comparison of vertical and horizontal scaling — what each actually fixes, where each breaks down, and the architecture changes horizontal scaling requires that most guides skip.

September 8, 2026Read more →
AI Agent Guardrails and Safety — Preventing Prompt Injection and Runaway Actions
Ai Agent SafetyPrompt Injection DefenseAgent Guardrails

AI Agent Guardrails and Safety — Preventing Prompt Injection and Runaway Actions

Build practical guardrails for AI agents — prompt injection defenses, destructive-action confirmation, iteration caps, and permission scoping.

September 7, 2026Read more →

Trending Topics