"Codegen drafts. Headed mode watches. page.pause lets you sit inside the test."
Codegen — Record a Draft
npx playwright codegen http://localhost:3000 opens two windows: a real browser pointed at the URL, and an Inspector side panel that emits code as you click. The flow is: click through the user journey you want to test; copy the generated code into a spec file; clean it up.
'Clean it up' is mandatory. The generated code is verbose, picks decent-but-not-great selectors (it'll grab a CSS class when role + name would survive better), and lacks assertions until you record them via the Inspector's 'Assert visibility' / 'Assert text' buttons. Treat codegen as a draft generator: it gets you 70% of the way, and the last 30% is the part that makes the test maintainable.
Headed Mode — Watch It Happen
Default test runs are headless — no visible browser. --headed shows the browser window so you can watch the test drive it in real time. Pair with --project=chromium to avoid three windows simultaneously, and --slowMo=500 to slow each action to 500 ms so you can actually see what's happening.
Headed mode is for debugging single tests, not for routine runs. It's slow (no parallelism, manual observation), but invaluable when a test fails in a way the trace viewer doesn't make obvious.
--debug — The Step-Through Mode
npx playwright test --debug opens the Playwright Inspector — a UI that pauses BEFORE the test runs, lets you step through actions one at a time, shows the locator under the cursor, and lets you experiment with new selectors in a REPL. The most efficient debug loop Playwright offers.
Inside the test, you can also await page.pause() at any line. The test pauses, Inspector opens, you step through from that point. The pause-and-inspect pattern is the modern equivalent of console.log.
page.pause is for live experimentation. Three tools, three jobs — don't try to use one for all of them.The Inspector's Hidden Powers
The Inspector (opens with codegen and --debug) has features that aren't obvious from the toolbar:
- 'Pick locator' — hover any element in the browser, see the best Playwright selector for it.
- 'Explore' — type a locator (
page.getByRole('button')) and see which elements match in real time, highlighted in the browser. - 'Assert' buttons — Inspector generates
expect(...).toBeVisible()/toHaveText()from your interaction.
The Headed-Mode Failure Pattern
When a test fails mysteriously, headed mode + slowMo + page.pause is the diagnostic. Add await page.pause() right before the failing line, run with --debug, step through, see where reality diverged from your assumption. Once you understand, remove the pause and fix the test (or the code).