Playwright Cross-Browser Testing: Chromium, Firefox & WebKit
Playwright is the most capable cross-browser testing framework available in 2026. It ships with bundled Chromium, Firefox, and WebKit engines, runs the same tests across all three without modification, and executes them in parallel by default. This guide covers everything from initial setup to CI configuration and handling browser-specific behavior.
Key Takeaways
- Playwright bundles its own Chromium, Firefox, and WebKit — no separate browser installs needed
- The "projects" config defines your browser matrix; tests run against all projects automatically
- Playwright runs tests in parallel by default — a 100-test suite runs across 3 browsers in similar time to a 100-test Chrome-only suite
- WebKit on Linux emulates Safari closely enough to catch the majority of Safari-specific bugs
- Use
browserNamefixture to conditionally handle browser-specific behavior without duplicating test code
Why Playwright for Cross-Browser Testing
Before Playwright, cross-browser testing with Selenium was painful. Each browser needed its own driver binary, versions had to be kept in sync manually, and running tests in parallel required significant infrastructure work.
Playwright changed this. Microsoft's framework ships with bundled browser binaries — a specific Chromium build, a Firefox build, and a WebKit build — all pinned to versions that are tested to work together. You run npx playwright install and you have everything you need to test across all three engines on any OS.
The architecture is also fundamentally different from Selenium. Playwright uses browser-native protocols (CDP for Chromium, custom protocols for Firefox and WebKit) rather than the WebDriver protocol, which makes it faster, more reliable, and capable of things Selenium cannot do (network interception, multiple contexts, etc.).
Installation and Setup
Installing Playwright
npm init playwright@latestThis scaffolds the configuration file, installs dependencies, and downloads the browser binaries. The interactive setup lets you choose TypeScript or JavaScript, test directory, and whether to add a GitHub Actions workflow.
To install browsers manually:
npx playwright install # all browsers
npx playwright install chromium <span class="hljs-comment"># just Chromium
npx playwright install --with-deps <span class="hljs-comment"># browsers + system dependencies (needed in CI)Basic Project Structure
After init, your project contains:
playwright.config.ts # test configuration
tests/ # test files
tests-examples/ # sample tests
package.jsonConfiguring the Browser Matrix
The playwright.config.ts file is where you define which browsers to test against using the projects array.
Basic Multi-Browser Config
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
fullyParallel: true,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
],
});With this config, every test in ./tests runs three times — once per browser. Playwright reports results per-project, making it easy to see which tests fail only in WebKit.
Adding Mobile Browsers
Playwright includes pre-configured device descriptors for common mobile devices:
projects: [
// Desktop
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'webkit', use: { ...devices['Desktop Safari'] } },
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
// Mobile
{ name: 'mobile-chrome', use: { ...devices['Pixel 5'] } },
{ name: 'mobile-safari', use: { ...devices['iPhone 13'] } },
{ name: 'tablet', use: { ...devices['iPad Pro 11'] } },
],Mobile device descriptors set the viewport, user agent, touch support, and device pixel ratio automatically.
Scoping Tests to Specific Browsers
Some tests are only relevant for specific browsers. Use test.skip with a condition:
test('Safari-specific date picker behavior', async ({ page, browserName }) => {
test.skip(browserName !== 'webkit', 'Safari-specific test');
// ...
});Or configure a project to only run certain test files:
{
name: 'webkit-only',
use: { ...devices['Desktop Safari'] },
testMatch: '**/safari-*.spec.ts',
},Parallel Execution
How Playwright Parallelizes Tests
Playwright's parallelism operates at two levels:
- Worker-level parallelism: Multiple test files run concurrently in separate worker processes
- Test-level parallelism: Within a file, tests can run in parallel if you opt in
By default, each test file runs sequentially within itself but files run in parallel across workers. The fullyParallel: true config makes every test run in its own worker regardless of file.
For cross-browser testing, each project runs independently. With 3 projects and 4 workers, Playwright distributes test execution efficiently — Chromium tests don't wait for WebKit tests to finish.
Optimal Worker Configuration
export default defineConfig({
fullyParallel: true,
// In CI: limit workers to avoid resource contention
workers: process.env.CI ? 2 : '50%',
});On a local machine, using 50% of available CPUs as workers is a reasonable default. In CI, limiting to 2–4 workers prevents out-of-memory issues in containers.
Sharding for Large Test Suites
For very large test suites, Playwright supports sharding — splitting the test suite across multiple CI jobs:
# GitHub Actions matrix strategy
strategy:
matrix:
shardIndex: [1, 2, 3, 4]
shardTotal: [4]
steps:
- run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}Each shard runs one quarter of the tests. Combined with multi-browser projects, this can reduce a 1-hour test suite to 15 minutes.
Handling Browser-Specific Behavior
The browserName Fixture
The browserName fixture is available in every test and reports which browser the test is running against:
test('file upload', async ({ page, browserName }) => {
await page.goto('/upload');
if (browserName === 'webkit') {
// Safari handles file inputs differently
await page.setInputFiles('input[type=file]', 'test-file.txt');
} else {
await page.locator('input[type=file]').setInputFiles('test-file.txt');
}
});Conditional Expectations
Some visual differences between browsers are intentional and acceptable. Skip visual assertions for known differences:
test('button styling', async ({ page, browserName }) => {
await page.goto('/buttons');
const button = page.locator('.primary-button');
// Only do pixel-perfect visual comparison in Chromium
if (browserName === 'chromium') {
await expect(button).toHaveScreenshot('primary-button.png');
} else {
// For other browsers, just verify functionality
await expect(button).toBeVisible();
await button.click();
await expect(page.locator('.confirmation')).toBeVisible();
}
});Common WebKit Gotchas
WebKit (Safari) has several behaviors that differ from Chromium and Firefox:
Input events: WebKit fires input and change events differently. Some form interactions that work in Chrome need explicit page.fill() instead of typing simulation.
Date/time inputs: Safari's date picker is completely different from Chrome's. Tests that interact with native date inputs need WebKit-specific handling.
Clipboard API: WebKit restricts clipboard access more aggressively. Tests involving copy/paste often need workarounds.
Scroll behavior: scrollTo and scrollIntoView behave differently. Always test scroll-dependent features in WebKit.
CSS features: Newer CSS (e.g., aspect-ratio, some gap behaviors, newer color functions) may not work in the bundled WebKit version.
CI/CD Setup
GitHub Actions
name: Playwright Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
playwright:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test
- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30The --with-deps flag installs system dependencies (libgbm, libasound, etc.) needed by the browser engines on Ubuntu. Without it, WebKit and Firefox may fail to launch.
Caching Browser Binaries
Browser installs take 1–3 minutes. Cache them to speed up CI:
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ hashFiles('package-lock.json') }}
- name: Install Playwright browsers
run: npx playwright install --with-depsThe cache key includes the lockfile hash — when Playwright version changes (and thus browser versions change), the cache is invalidated automatically.
Viewing Test Results
Playwright generates an HTML report showing results per test, per browser, with screenshots and traces for failures. Upload it as a CI artifact and download it locally to diagnose failures:
npx playwright show-report path/to/downloaded/playwright-reportFor failed tests, the Playwright Trace Viewer shows a full timeline of the test execution with DOM snapshots, network requests, and console logs — invaluable for debugging cross-browser failures.
Playwright vs Other Cross-Browser Tools
| Feature | Playwright | Selenium | Cypress |
|---|---|---|---|
| Chromium support | ✓ | ✓ | ✓ |
| Firefox support | ✓ | ✓ | ✓ |
| WebKit support | ✓ | Limited | ✗ |
| Bundled browsers | ✓ | ✗ | ✗ |
| Parallel by default | ✓ | Manual | Manual |
| Network interception | ✓ | ✗ | ✓ |
| Multiple tabs/windows | ✓ | ✓ | Limited |
| Mobile emulation | ✓ | Limited | Limited |
Playwright's WebKit support is unique — no other framework ships with a bundled WebKit engine for non-macOS systems. This is the single biggest reason to choose Playwright for cross-browser testing.
HelpMeTest and Playwright
Writing Playwright tests still requires familiarity with the API and maintenance over time as selectors change and flows evolve. HelpMeTest takes a different approach — describe your test scenarios in plain English and HelpMeTest handles the Playwright implementation underneath, running your tests across Chromium, Firefox, and WebKit automatically.
For teams that want the reliability of Playwright's cross-browser coverage without the maintenance overhead of a Playwright test suite, HelpMeTest bridges the gap.
Conclusion
Playwright is the best tool available for cross-browser testing in 2026. Its bundled browser approach eliminates the infrastructure headaches of traditional cross-browser testing, parallel execution by default makes multi-browser runs practical, and its WebKit support is unmatched in the ecosystem.
Set up the projects configuration with Chromium, Firefox, and WebKit, wire it into your CI pipeline with the GitHub Actions workflow above, and you have comprehensive cross-browser coverage on every pull request. The investment in setup is a few hours; the payoff is catching Safari and Firefox regressions before your users do.