Level 3 · Senior Automation · Practice 01

Cross-Browser Sharded Runs

Run the same Playwright suite across Chromium, Firefox, and WebKit in parallel — then read the HTML report.

1 Goal

By the end of this exercise you will have a Playwright project with three browser projects (Chromium, Firefox, WebKit) configured in playwright.config.ts, a small test suite of four UI checks against playwright.dev and example.com, and the ability to run the suite in two parallel shards. You will open the HTML report and identify which browser produced which trace.

Why this matters: sharding is how senior automation engineers keep CI pipelines under ten minutes as the suite grows. A 400-test suite across three browsers would take 30+ minutes serially. Split into four shards, it finishes in under eight.

2 Install the tool

Playwright requires Node.js 18 or later. Both are free and open source.

  1. Install Node.js 20 LTS. Pick your operating system.

    Download the LTS installer from nodejs.org (choose the Windows Installer .msi). Run it and accept the defaults. Close and reopen any terminal after install.

    Either download the .pkg from nodejs.org, or use Homebrew:

    brew install node@20

    Use nvm so you can switch Node versions per project:

    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
    source ~/.bashrc
    nvm install 20
    nvm use 20
  2. Verify Node and npm. Open a fresh terminal and run:
    node --version
    npm --version

    You should see v20.x.x (or higher) and 10.x.x. If either command says "not found", the installer did not update your PATH — close and reopen your terminal or log out and back in.

  3. Create the project folder and install Playwright. Pick any folder for bootcamp exercises; we will call ours bootcamp-playwright.
    mkdir bootcamp-playwright
    cd bootcamp-playwright
    npm init playwright@latest -- --quiet --browser=chromium --browser=firefox --browser=webkit --install-deps
    mkdir bootcamp-playwright
    cd bootcamp-playwright
    npm init playwright@latest -- --quiet --browser=chromium --browser=firefox --browser=webkit --install-deps

    Accept TypeScript when prompted. The installer downloads browser binaries (~350 MB) — this takes a few minutes on first run.

  4. Verify Playwright. From inside bootcamp-playwright:
    npx playwright --version

    Expect something like Version 1.49.0. If you get "command not found", ensure you are inside the project folder — Playwright is a local dependency, not a global one.

3 Project setup

Delete the generator's example tests so you start clean. Your folder should look like this:

bootcamp-playwright/
  package.json
  playwright.config.ts
  tests/
    smoke.spec.ts
  .gitignore

Remove tests-examples/ and the default tests/example.spec.ts file if they exist:

Remove-Item -Recurse -Force tests-examples -ErrorAction SilentlyContinue
Remove-Item tests\example.spec.ts -ErrorAction SilentlyContinue
rm -rf tests-examples
rm -f tests/example.spec.ts

Now replace playwright.config.ts with the three-project configuration below.

4 Write the script

File: playwright.config.ts

import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 2 : undefined,
  reporter: [['html', { open: 'never' }], ['list']],

  use: {
    baseURL: 'https://playwright.dev',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
  },

  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'] },
    },
    {
      name: 'webkit',
      use: { ...devices['Desktop Safari'] },
    },
  ],
});

File: tests/smoke.spec.ts

import { test, expect } from '@playwright/test';

test.describe('Playwright docs smoke', () => {
  test('homepage has Playwright in title', async ({ page }) => {
    await page.goto('/');
    await expect(page).toHaveTitle(/Playwright/);
  });

  test('get-started link navigates to docs', async ({ page }) => {
    await page.goto('/');
    await page.getByRole('link', { name: 'Get started' }).first().click();
    await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible();
  });
});

test.describe('example.com smoke', () => {
  test('example.com loads with expected heading', async ({ page }) => {
    await page.goto('https://example.com');
    await expect(page.getByRole('heading', { name: 'Example Domain' })).toBeVisible();
  });

  test('example.com has more-information link', async ({ page }) => {
    await page.goto('https://example.com');
    const link = page.getByRole('link', { name: 'More information...' });
    await expect(link).toBeVisible();
    await expect(link).toHaveAttribute('href', /iana\.org/);
  });
});

File: package.json — add these scripts to the existing "scripts" object:

{
  "scripts": {
    "test": "playwright test",
    "test:shard1": "playwright test --shard=1/2",
    "test:shard2": "playwright test --shard=2/2",
    "test:chromium": "playwright test --project=chromium",
    "report": "playwright show-report"
  }
}
What --shard=1/2 means: Playwright splits all test files across N shards. Shard 1/2 runs the first half; shard 2/2 runs the second. In CI you run each shard on a different machine, then merge reports. We simulate two machines by opening two terminals on one box.

5 Run & verify

First, sanity-check all three browsers on one machine with no sharding:

npx playwright test

Expected output (tail):

Running 12 tests using 4 workers

  12 passed (18.3s)

To open last HTML report run:

  npx playwright show-report

Twelve tests = 4 tests × 3 browser projects. Open the report:

npm run report

A browser window opens at http://localhost:9323. Each row shows the test name and browser project. Click a row to see the full trace.

Now shard the run. Open two terminals in the same folder.

Terminal 1:

npx playwright test --shard=1/2

Terminal 2 (start immediately):

npx playwright test --shard=2/2

Each terminal runs six tests (half of twelve). Wall-clock time roughly halves compared with the single-terminal run.

Note: both shards write to the same playwright-report/ folder by default, so the second shard overwrites the first's HTML report when run locally. In CI you pass PLAYWRIGHT_HTML_REPORT=reports/shard-1 (etc.) per shard and use npx playwright merge-reports to combine them. That is covered in the challenge below.

6 Troubleshooting

browserType.launch: Executable doesn't exist at …

You ran tests before the browser binaries finished downloading, or the download was interrupted. Re-run:

npx playwright install

On Linux you may also need system dependencies:

npx playwright install-deps
Error: Timed out 30000ms waiting for expect(locator).toBeVisible()

The page structure changed or the network is slow. Three things to check:

  1. Run headed to see what the browser sees: npx playwright test --headed --project=chromium
  2. Open the trace for the failing test from the HTML report — Playwright records a DOM snapshot at every action.
  3. If the link text moved (Playwright docs do update), change the getByRole('link', { name: 'Get started' }) selector to match what you see on the page.
Error: Sharding requires a value like --shard=1/3, got "1"

You forgot the denominator. The flag must be --shard=N/M where N is the current shard (1-indexed) and M is the total number of shards. Example: --shard=2/4 is the second of four shards.

WebKit tests pass locally but fail in GitHub Actions on Ubuntu

Ubuntu runners need the WebKit system libraries. Add this to your workflow's install step:

- run: npx playwright install --with-deps webkit

Or install all three browsers with their dependencies:

- run: npx playwright install --with-deps

7 Challenge

Extend the setup

  1. Merge sharded reports. Run both shards with PLAYWRIGHT_BLOB_REPORT_OUTPUT_DIR=blob-report-1 (and -2) and a --reporter=blob flag, then run npx playwright merge-reports --reporter=html blob-report-1 blob-report-2 to produce a single combined HTML report. Confirm the merged report shows all twelve tests across three browsers.
  2. Add a fourth project — mobile Safari. Add a project entry using devices['iPhone 14']. Re-run and verify the test count jumps from 12 to 16.