Skip to content
L-SYSTEM

Why Playwright, and what it actually does

Preview unit: open without enrolling in the course.

Why Playwright, and what it actually does

The pain

Two things ruin UI automation suites, and they are not the things people complain about.

Timing. A classic WebDriver script issues commands over HTTP and gets an answer per command. It cannot know whether the button it just found is still attached to the DOM one millisecond later. So teams paper over the gap: sleep(2), then sleep(5) when CI is slower, then a retry loop, then a helper called clickWhenReady that nobody can explain. The suite becomes slow and still flaky — the two costs you were trading between.

Overhead. Every browser needs its own driver binary, each on its own release schedule. A Chrome update on the build agent breaks the run on a Tuesday morning for reasons unrelated to the product.

The mechanism

Playwright is a Node library from Microsoft that drives Chromium, Firefox and WebKit through a single bidirectional connection to a browser it ships and versions itself.

Two consequences matter more than the rest:

It ships the browsers. npx playwright install downloads pinned builds. The version of the browser is a line in your lockfile, not a property of the machine. A run on your laptop and a run in CI are the same run.

It knows the page. Because the connection is persistent and the protocol is rich, Playwright can inspect an element's state before acting on it. Before a click it waits for the element to be attached, visible, stable (not animating), able to receive events (not covered), and enabled. That set of checks is called actionability, and it is why a correct Playwright test contains no sleeps.

Three objects, three levels of isolation

const browser = await chromium.launch();          // one process
const context = await browser.newContext();       // one clean profile
const page    = await context.newPage();          // one tab
  • Browser — the process. Expensive: hundreds of milliseconds to start.
  • Context — an isolated profile: its own cookies, its own localStorage, its own permissions. Cheap: a few milliseconds. This is the unit of test isolation.
  • Page — a tab inside a context.

In the test runner you rarely write those three lines. The runner gives every test a fresh context and page automatically, which is why tests do not leak state into each other by default. Understanding what is underneath matters the moment you need two logged-in users in one test.

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

test('a signed-out visitor can reach the pricing page', async ({ page }) => {
  await page.goto('https://example.com');
  await page.getByRole('link', { name: 'Pricing' }).click();
  await expect(page.getByRole('heading', { name: 'Plans' })).toBeVisible();
});

Three lines, no waits, and it works on all three engines.

Library and runner are two products

playwright is the automation library. @playwright/test is a test runner built on it: fixtures, parallelism, retries, reporters, configuration. This course uses the runner throughout. When you read a Stack Overflow answer that launches a browser by hand, that is the library, and it is usually the wrong shape for a test suite.

The cost

Be honest about this in front of a client:

  • You are buying into Node. If the engagement's tooling is Java or C#, Playwright has bindings, but the ecosystem, the examples and the runner features are strongest in TypeScript. Mixing stacks has a real support cost.
  • Browsers are large. Roughly a gigabyte per install. Air-gapped or bandwidth-limited build agents need a cache strategy or a container, and that is work.
  • Auto-waiting fixes one cause of flakiness, not all of them. A suite that shares a test account across parallel workers will be flaky in Playwright exactly as it was before.
  • The framework will not save a bad locator. Everything downstream in this course depends on choosing element queries that survive a redesign. That is unit u07, and it is the highest-leverage hour in the course.
Playwright architecture: test process, one connection, three browser engines

A clean horizontal diagram in watercolour-sketch style on cream paper. On the left, a rounded box labelled "Node test process (@playwright/test)". A single thick arrow labelled "one persistent connection" runs right into a wide rounded box labelled "Browser". Inside that box, three stacked smaller boxes labelled "Context A", "Context B", "Context C", each containing one or two tiny rectangles labelled "Page". Below the browser box, three small engine badges in a row labelled "Chromium", "Firefox", "WebKit" connected upward by short dotted lines. To the far right, a faded contrasting panel labelled "the old way" showing the test process connected by three separate broken arrows to three separate driver binaries, each with a small warning triangle. Muted terracotta and sage accents, hand-drawn feel, no photographic detail.