C.W.K.
Stream
Lesson 01 of 04 · published

Install + Three Real Browsers

~14 min · playwright-setup, install, browsers

Level 0Test Curious
0 XP0/32 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete
"npm init playwright. Five minutes later you're driving Chromium from a test."

The One-Command Bootstrap

npm init playwright@latest is unusual in how much it does. It installs @playwright/test, downloads the browser binaries (Chromium, Firefox, WebKit), creates playwright.config.ts, scaffolds an e2e/ directory with an example test, adds package.json scripts, and optionally generates a GitHub Actions workflow. The whole thing is interactive — answer a few prompts (TypeScript yes, GitHub Actions yes/no, default e2e/ directory), and you're shipped.

You can also install manually: npm install -D @playwright/test, then npx playwright install to download browsers. The init flow just consolidates the boilerplate.

Three Browsers, One Test

Playwright drives three browser engines:

  • Chromium — the Chrome/Edge engine. Most market share, fastest to start, the project default.
  • Firefox — Gecko engine. Catches behavior that differs from Chromium-only code.
  • WebKit — Safari's engine. Critical if you care about Safari users or iOS Safari (the iOS browser, even "Chrome on iOS," is WebKit-only).

The same test runs against all three by default. You write the test once; Playwright runs it in three browsers and reports per-browser results. Cross-browser bugs are usually CSS-related or use a JavaScript API one engine implements differently — the kind of bug only a real browser test catches.

The Browser Binaries Are Not Trivial

The download is ~500 MB across all three browsers. Playwright caches them in ~/.cache/ms-playwright/ (Linux/macOS) or %USERPROFILE%\AppData\Local\ms-playwright (Windows). The version is pinned to the Playwright version — when you upgrade @playwright/test, you re-run npx playwright install to get matching binaries.

In CI, the binaries need to download fresh per environment unless you cache them. The official GitHub Actions setup uses a cache key on the Playwright version, so subsequent runs skip the download.

Don't apt install browsers as a substitute. Playwright requires specific patched browser builds. Using system Chromium leads to subtle differences that cause flakes you can't reproduce. Always use npx playwright install.

System Dependencies

Browsers need OS-level libraries (fonts, image codecs, accessibility frameworks). npx playwright install --with-deps installs both binaries AND the system dependencies. On macOS, the dependencies are usually pre-installed; on Linux (especially in CI containers), this flag is non-optional. On Windows, dependencies bundle with the browser.

The First Test

The example test scaffolded by init visits playwright.dev and asserts the title. That's enough to confirm the install works. Run it: npx playwright test. You'll see three results (one per browser), each in a few seconds.

Code

Init flow — interactive but quick·bash
# One-command bootstrap — installs everything, scaffolds everything
npm init playwright@latest

# Answer prompts:
#   Use TypeScript or JavaScript? → TypeScript
#   Where to put your end-to-end tests? → e2e
#   Add a GitHub Actions workflow? → true (recommended)
#   Install Playwright browsers? → true

# Run the example test
npx playwright test
Manual install — picks each browser explicitly·bash
# Manual install (if init isn't right for you)
npm install -D @playwright/test

# Download browsers
npx playwright install

# On Linux (especially CI), include system dependencies
npx playwright install --with-deps

# Or pick a single browser only (smaller download)
npx playwright install chromium
npx playwright install firefox webkit  # multiples allowed
Example test — the one `init` scaffolds·typescript
// e2e/example.spec.ts — what `init` creates for you
import { test, expect } from '@playwright/test';

test('has title', async ({ page }) => {
  await page.goto('https://playwright.dev/');

  // Expect a title "to contain" a substring.
  await expect(page).toHaveTitle(/Playwright/);
});

test('get started link', async ({ page }) => {
  await page.goto('https://playwright.dev/');

  // Click the get started link.
  await page.getByRole('link', { name: 'Get started' }).click();

  // Expects the URL to contain intro.
  await expect(page).toHaveURL(/.*intro/);
});
CI scaffold — runs in three browsers, uploads the report·yaml
# .github/workflows/playwright.yml — what init can scaffold
name: Playwright Tests
on:
  push:
    branches: [main, master]
  pull_request:
    branches: [main, master]
jobs:
  test:
    timeout-minutes: 60
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: lts/*
      - 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: ${{ !cancelled() }}
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 30

External links

Exercise

Run npm init playwright@latest in a project (a fresh directory if you don't have one handy). Accept the defaults. Run npx playwright test and watch the example tests pass in three browsers. Then break one — change the assertion toHaveTitle(/Playwright/) to toHaveTitle(/Vue/) and re-run. Read the failure: notice it tells you which browser, which line, and what the actual title was.
Hint
If the install hangs on browser download, your network may be blocking the Playwright CDN. Set PLAYWRIGHT_DOWNLOAD_HOST to a mirror, or pre-download the binaries on a network that allows it and copy the cache directory.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.