Playwright interview question
How does Playwright run tests in parallel, and how would you scale a suite across CI machines?
Short answer
Playwright runs test files in parallel worker processes; fullyParallel also splits tests within a file. Each worker has its own browser and each test a fresh context. Scale out with --shard=x/n in a CI matrix, the blob reporter and merge-reports. Tests must be independent with isolated data.
Answer
Playwright Test parallelises with worker processes. By default, test files are distributed across workers and tests inside a file run in order in the same worker. Setting fullyParallel: true (or test.describe.configure({ mode: 'parallel' }) for one file) lets individual tests from the same file run in different workers. Each worker launches its own browser, and every test gets a fresh browser context, so tests are isolated at the browser level. To go beyond one machine, shard the suite across CI jobs and merge the reports. The hard part is not configuration; it is making tests independent, especially their data.
Configuration
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
fullyParallel: true,
workers: process.env.CI ? 4 : undefined, // undefined = half the logical CPU cores
retries: process.env.CI ? 2 : 0,
forbidOnly: !!process.env.CI,
reporter: process.env.CI ? 'blob' : 'html',
});
workerscan be a number or a percentage string such as'50%'. More workers than the machine can handle makes tests slower and flakier, not faster; measure.workers: 1disables parallelism (for debugging).test.describe.configure({ mode: 'serial' })makes a group run in order and skips the rest after a failure. Use sparingly: it signals tests that depend on each other.
Worker identity and data isolation
Parallel tests collide when they share server-side state: the same user’s cart, the same unique email, a global settings toggle. Strategies:
- Create data per test through the API in a fixture, with unique values.
- Allocate per-worker accounts using
testInfo.parallelIndex(stable 0..workers-1, reused when a worker restarts) orworkerIndex(unique per worker process). - Tests that change global settings go into a separate project that runs with
workers: 1, or behind a dependency.
test('profile update', async ({ page }, testInfo) => {
const email = `qa+${testInfo.parallelIndex}-${Date.now()}@example.com`;
// ...
});
Note that when a test fails, its worker is torn down and a new one started for the remaining tests, which re-runs worker-scoped fixtures.
Sharding across machines
npx playwright test --shard=1/4
npx playwright test --shard=2/4
# ...
GitHub Actions example:
jobs:
e2e:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shardIndex: [1, 2, 3, 4]
shardTotal: [4]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 22 }
- run: npm ci
- run: npx playwright install --with-deps
- run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: blob-report-${{ matrix.shardIndex }}
path: blob-report
retention-days: 1
merge-reports:
if: ${{ !cancelled() }}
needs: [e2e]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 22 }
- run: npm ci
- uses: actions/download-artifact@v4
with: { path: all-blob-reports, pattern: blob-report-*, merge-multiple: true }
- run: npx playwright merge-reports --reporter html ./all-blob-reports
- uses: actions/upload-artifact@v4
with: { name: html-report, path: playwright-report }
Sharding splits by test when fullyParallel is on, and by file otherwise, so with large uneven files, shards can be unbalanced. Splitting big files or enabling fullyParallel evens them out.
Making it actually faster
- Find the slowest tests in the report; often a few UI setups dominate. Move setup to API calls and reuse auth via
storageState. - Run only affected tests on PRs (
--only-changedin recent versions compares against a git ref) and the full suite on main or nightly. - Balance cost: four shards with four workers each is sixteen browsers hitting your test environment. Make sure the environment can take the load, or you will create flakiness.
What interviewers look for
- Accurate model: workers, file-level versus test-level parallelism, per-test contexts.
- Sharding with a CI matrix and merging blob reports.
- Data isolation strategies,
parallelIndex/workerIndex, and limited use of serial mode. - Pragmatism about worker counts and environment capacity.
A strong answer covers
- Worker processes; files in parallel by default, fullyParallel for tests within a file
- Each worker has its own browser; tests get isolated contexts
- Sharding across machines with --shard and a CI matrix
- Merges reports with the blob reporter and merge-reports
- Data isolation and shared-state problems; serial mode as an exception