Skip to main content
Sabo includes a complete Playwright E2E testing suite covering authentication, dashboard, marketing pages, blog, changelog, and legal pages. Tests run across multiple browsers and viewports to ensure cross-platform compatibility.

Overview

Playwright is a powerful end-to-end testing framework that allows you to test your application in real browsers. Sabo’s testing setup provides:
  • Cross-browser testing (Chromium, Firefox, WebKit)
  • Mobile viewport testing (Pixel 5, iPhone 12)
  • Comprehensive coverage across 16 spec files spanning authentication, dashboard, marketing, blog, changelog, and legal flows
  • Authentication helpers for testing protected routes
  • Parallel test execution for fast feedback
  • Visual debugging with Playwright UI mode
  • HTML test reports with screenshots and traces
Playwright tests run against a production build (pnpm build && pnpm start) to ensure tests match real-world behavior.
Need deeper coverage (API testing, fixtures, component testing)? Keep the official Playwright documentation open while following this guide.

Quick Start

1

Install Playwright

Playwright is already included in package.json. If you need to reinstall or update:
Playwright will download Chromium, Firefox, and WebKit browsers (~300MB total).
2

Run your first test

Start the test suite with a single command:
This command will:
  1. Build your application (pnpm build)
  2. Start a production server (pnpm start on port 3000)
  3. Run all tests across all configured browsers
  4. Generate an HTML report
Tests run in parallel by default for speed. On CI, tests run sequentially to avoid flakiness.
3

View test results

After tests complete, view the detailed HTML report:
The report includes:
  • Pass/fail status for each test
  • Screenshots of failures
  • Execution traces for debugging
  • Performance metrics
Test reports are automatically generated in playwright-report/ directory.

Test Commands

Sabo provides several npm scripts for different testing workflows:
package.json

Command Breakdown

When to use: CI/CD pipelines, pre-commit checks, final verification before deployment.
Behavior:
  • Runs all tests in headless mode (no browser UI)
  • Tests run in parallel for speed
  • Automatically builds and starts your app
  • Generates HTML report at the end
  • Exit code 0 (success) or 1 (failure) for CI integration
Output:
When to use: Developing new tests, debugging flaky tests, exploring test coverage.
Behavior:
  • Opens Playwright’s interactive test runner UI
  • Watch mode: tests re-run when files change
  • Time-travel debugging with DOM snapshots
  • Click through test steps one at a time
  • Filter tests by name, file, or status
Features:
  • See test execution in real-time
  • Inspect DOM at each step
  • View network requests and console logs
  • Record new tests by clicking in your app
  • Compare screenshots side-by-side
UI mode is the fastest way to write new tests. Use the “Record” feature to generate test code automatically.
When to use: Debugging visual issues, understanding test flow, demonstrating tests to team.
Behavior:
  • Tests run with visible browser windows
  • See exactly what Playwright sees
  • Slower than headless mode
  • Useful for debugging timing issues
Example workflow:
  1. Run pnpm test:e2e:headed
  2. Watch browser open and navigate your app
  3. Identify visual bugs or timing issues
  4. Fix and re-run specific tests
When to use: Investigating test failures, understanding complex interactions, learning Playwright.
Behavior:
  • Opens Playwright Inspector
  • Pauses at each test step
  • Step forward/backward through test
  • Explore locators and selectors
  • Modify test code on the fly
Debugging features:
  • Pick locator: Click any element to generate a selector
  • Step over/into: Control test execution
  • Console: Run Playwright commands interactively
  • Source: View test code with current line highlighted
When to use: After test run completes, reviewing failures, sharing results with team.
Behavior:
  • Opens HTML report in your default browser
  • Shows pass/fail status for all tests
  • Includes screenshots of failures
  • Execution traces for debugging
  • Test duration and retry information
Report features:
  • Filter by status (passed/failed/flaky/skipped)
  • Search tests by name
  • View screenshots and videos
  • Download trace files for offline debugging
  • Compare test results across runs

Test Configuration

Playwright configuration is defined in playwright.config.ts at the project root:
playwright.config.ts

Configuration Options Explained

All test files must be inside the tests/ directory. Playwright looks for files ending in .spec.ts or .test.ts.Sabo’s test structure:
Enables parallel test execution across multiple worker processes. Dramatically speeds up test runs.Impact:
  • Without parallel: 85 tests in ~8 minutes
  • With parallel (5 workers): 85 tests in ~1.5 minutes
Tests must be independent (no shared state) for parallel execution to work correctly.
Automatically retry failed tests on CI environments. Local failures don’t retry (faster feedback).Why retry on CI:
  • Network latency
  • Resource constraints
  • Timing issues in CI environments
Best practice: Fix flaky tests instead of relying on retries. Use retries as a temporary safety net.
  • Local: Uses all CPU cores (undefined = auto)
  • CI: Sequential execution (1 worker) for stability
Override workers:
Allows relative URLs in tests:
Playwright automatically:
  1. Builds your app (pnpm build)
  2. Starts production server (pnpm start)
  3. Waits for server to be ready (checks url)
  4. Runs tests
  5. Shuts down server after tests complete
reuseExistingServer:
  • Local: Reuses running server (faster during development)
  • CI: Always starts fresh server (ensures clean state)
Keep your dev server running (pnpm dev) during test development. Set reuseExistingServer: true to avoid rebuilding.

Test Structure

Sabo’s tests are organized by feature area in tests/e2e/:

Test File Anatomy

Here’s a typical test file structure:
tests/e2e/marketing/contact.spec.ts

Test Patterns

Use cases:
  • Navigate to a common page
  • Set up authentication
  • Clear browser state
  • Inject test data
Playwright provides multiple ways to find elements:
Best practices:
  1. Prefer getByRole for accessibility
  2. Use data-testid for dynamic content
  3. Avoid brittle selectors (CSS classes that may change)
  4. Use regex for flexible text matching
Playwright’s assertions are auto-waiting: they retry until the condition is met or timeout occurs (default 30s).

Writing Your First Test

Let’s write a test for a new feature page step by step.
1

Create test file

Create a new file in the appropriate directory:
Name your test file after the feature or page you’re testing, ending with .spec.ts.
2

Import Playwright

tests/e2e/features/new-feature.spec.ts
3

Write your first test

tests/e2e/features/new-feature.spec.ts
4

Run your test

If your test passes, you’ll see a green checkmark. If it fails, Playwright will show exactly which assertion failed and why.
5

Add more test cases


Testing Protected Routes

Many pages in your app require authentication. Sabo provides an auth helper to set up authenticated sessions in tests.

Authentication Helper

The auth helper is located at tests/e2e/helpers/auth.ts:
tests/e2e/helpers/auth.ts
The helper logs a warning by default as a reminder to configure test credentials. Once .env.test is set up and you have confirmed the helper works, delete or comment out the console.warn line to keep test output clean.

Using the Auth Helper

tests/e2e/dashboard/dashboard.spec.ts
In the repository, tests that require authentication are marked with test.skip until setupAuthenticatedUser() is configured. Once your test credentials are in place, remove the skips to exercise the protected flows.
Want to reuse Playwright’s built-in authentication storage? See the official Playwright authentication guide. If you need to understand how Supabase sessions are issued in Sabo before writing tests, review Auth with Supabase.

Setting Up Test Credentials

Create a test user in your Supabase dashboard, then add credentials to .env.test:
.env.test
Never commit .env.test to version control. Add it to .gitignore. Use a dedicated test user, not a real user account.
Playwright doesn’t automatically load .env.test. Either export these variables in your shell before running tests or run commands through the dotenv CLI: pnpm exec dotenv -e .env.test -- pnpm test:e2e. This ensures helpers like setupAuthenticatedUser() can read the credentials.

Common Test Patterns

Testing Forms

Testing Navigation

Testing Responsive Design

Testing Conditional Rendering

Testing Async Operations


Debugging Tests

The Playwright Inspector provides step-by-step debugging:
Features:
  • Step through: Execute one action at a time
  • Pick locator: Click elements to generate selectors
  • Console: Run Playwright commands interactively
  • Screenshots: Capture state at each step
Common debugging commands:
Add console output to understand test flow:
View output:
Console logs appear in terminal output.
Capture screenshots at specific points:
Screenshots are automatically captured on test failures. Find them in test-results/ directory.
Control which tests run during debugging:
Remove test.only() before committing! CI will fail if test.only() is detected (forbidOnly: true in config).
Trace files provide complete test execution history:
Trace viewer features:
  • Timeline of all actions
  • Screenshots at each step
  • Network requests and responses
  • Console logs and errors
  • DOM snapshots (time-travel debugging)
Manual trace capture:

Best Practices

For more examples straight from the Playwright team, refer to the official Best Practices guide. It complements the patterns outlined below.
Each test should be completely isolated and not depend on other tests.Bad:
Good:
Test names should clearly describe what is being tested.Bad:
Good:
Pattern: “should [expected behavior] when [condition]”
Use selectors that reflect how users interact with your app.Priority order:
  1. Role-based (best for accessibility)
  2. Label-based (for form inputs)
  3. Test IDs (for dynamic content)
  4. Text content (for static text)
Avoid:
  • CSS classes that may change: .btn-primary-v2-new
  • Complex CSS selectors: div > ul > li:nth-child(3)
  • XPath selectors (hard to maintain)
Fast tests provide quick feedback and encourage frequent testing.Tips:
  • Use baseURL to avoid full URLs
  • Reuse authenticated sessions when possible
  • Mock external API calls (if needed)
  • Run tests in parallel (fullyParallel: true)
  • Use page.waitForLoadState("domcontentloaded") instead of arbitrary timeouts
Bad:
Good:
Remove test data after tests to ensure isolation.
Playwright automatically clears browser cookies, local storage, and session storage between tests. You only need to clean up server-side data.

CI/CD Integration

Playwright tests can run automatically in your CI/CD pipeline.
For provider-specific examples (GitHub Actions, GitLab, Jenkins, Azure), refer to Playwright’s CI guide; the workflow below shows how we configure GitHub Actions for Sabo.

GitHub Actions Example

.github/workflows/playwright.yml

Vercel Integration

Run tests before deployment:
vercel.json
Running E2E tests on every deployment can slow down your pipeline. Consider running them only on main branch or scheduled runs.

Troubleshooting

Cause: Browser crashed or was closed unexpectedly.Fix:
  1. Check for memory issues (tests using too much RAM)
  2. Reduce parallel workers: pnpm exec playwright test --workers=1
  3. Update Playwright: pnpm update @playwright/test
  4. Check for infinite loops or long-running operations
Cause: Race conditions, timing issues, or network dependencies.Fix:
  1. Avoid page.waitForTimeout() - use specific waits instead
  2. Use auto-waiting assertions (await expect(...))
  3. Wait for network to be idle: await page.waitForLoadState("networkidle")
  4. Increase timeout for slow operations: { timeout: 60000 }
  5. Mock external API calls to remove network dependency
Cause: Element is hidden, covered, or not yet rendered.Fix:
  1. Wait for element to be visible first:
  2. Scroll element into view:
  3. Check for overlays or modals covering the element
  4. Use force: true (last resort):
Cause: Missing test credentials or incorrect Supabase configuration.Fix:
  1. Verify .env.test exists with correct credentials
  2. Check test user exists in Supabase dashboard
  3. Ensure NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY are set
  4. Verify cookie domain matches (localhost for local tests)
  5. Check Supabase session is not expired
Cause: Different environment, timing, or dependencies.Fix:
  1. Run tests sequentially on CI: workers: 1 in config
  2. Enable retries on CI: retries: 2 in config
  3. Check environment variables are set in CI
  4. Increase timeouts for slower CI environments
  5. Use webServer.reuseExistingServer: !process.env.CI to ensure fresh server
Cause: Network issues, permissions, or disk space.Fix:
Check disk space:
Playwright browsers require ~1GB of disk space.