skip to content

Live Surfaces

The windows you open while the browser is still under your control rather than after the run: a watching test UI, a paused inspector, and a recorder that writes code as you click.

on this pageshow

explore

questions

10

What does `npx playwright codegen <url>` open, and what does it produce?

level: juniorimportance: must knowfreq 72%

answer

  1. Two windows open, not one
  2. Browser plus Inspector recorder
  3. Actions become locator calls live
  4. A flag saves it to a file
  5. Output is a draft, not a suite

basics

~20 s

Playwright's codegen command opens a browser plus a recorder window, transcribes every click, keystroke and navigation into runnable test code as you go, and hands back a first draft you copy or save with -o.

solid answer

~40 s

`npx playwright codegen https://tracker.example.com` launches two windows: a browser Playwright drives, and the Playwright Inspector recorder that shows generated code updating live as you use the site. A click becomes `locator.click()`, typing becomes a single `fill()` with the final value, a dropdown becomes `selectOption()`. If you pass a URL the first emitted line is `await page.goto(...)`. The recorder's language dropdown switches the output binding, its toolbar buttons insert `expect()` assertions where you press them, and `-o tests/track.spec.ts` saves the script to a file instead of leaving you to copy it. Default output is a `playwright-test` block using the `page` fixture. Treat what comes out as a draft: it is one flat function of literal values, with assertions only where you added them.

code

bash · 4 lines
bash
npx playwright codegen https://tracker.example.com/orders/42

# pick the engine and save straight to a spec file
npx playwright codegen -b webkit -o tests/track-order.spec.ts https://tracker.example.com

go deeper

for a junior

Remember the shape: a browser window plus a recorder window, code appearing as you click, and -o to save it. Be able to run the command against a URL from memory.

for a middle

Explain what the recorder converts each interaction into, why typing collapses into one fill call, and that the session is configured by CLI flags rather than by your test project's config.

for a senior

Show judgement about the output: name concretely what a recording lacks, which generated lines you would rewrite first, and how you keep a recorded draft from landing in the suite unreviewed.

for a principal

Frame where recording belongs in your team's workflow — as an exploration and learning aid that shortens the first draft, not as an input path into the suite that bypasses review.

`codegen` is Playwright's recorder: you drive a real browser by hand and it writes the equivalent test code for you, action by action. ## What the command starts `npx playwright codegen https://tracker.example.com/orders/42` opens **two** windows: - a **browser window** under Playwright's control (Chromium by default; `-b firefox` or `-b webkit` pick another engine, `--channel chrome` a branded build); - the **Playwright Inspector** recorder window, which shows the generated script growing line by line, with a language dropdown, a **Copy** button, a **Clear** button and buttons that insert assertions. The URL argument is optional. Pass one and the first generated line is `await page.goto('...')`; omit it and the recorder opens `about:blank` and records the navigation you type into the address bar. The browsers have to be installed first (`npx playwright install`), and no test project is required — codegen is a standalone CLI you can run in an empty directory. ## What the recorder turns into code Codegen records intent, not raw input events: - a click becomes `await locator.click()`; - typing into a field becomes **one** `fill()` call carrying the final value, not one call per keystroke; - choosing in a `<select>` becomes `selectOption()`; - a checkbox becomes `check()` or `uncheck()`; - a keyboard shortcut becomes `press('Enter')`; - choosing a file becomes `setInputFiles()`; - opening a popup or new tab yields a second `page` object taken from the popup event; - the toolbar's assert buttons insert `expect(locator).toBeVisible()`, `toContainText()` or `toHaveValue()` lines at the point you press them. | you do this in the browser | codegen writes | | --- | --- | | click the "Refresh status" button | `await page.getByRole('button', { name: 'Refresh status' }).click();` | | type into the "Delivery notes" box | `await page.getByLabel('Delivery notes').fill('Leave at door');` | | choose "Fastest" in the route select | `await page.getByLabel('Route').selectOption('Fastest');` | | press Enter in the search box | `await page.getByRole('textbox').press('Enter');` | ## Getting the code out Three routes, in rising order of convenience: 1. read it in the recorder window and press **Copy**; 2. switch the language dropdown first if your suite is not TypeScript, then copy; 3. run with `-o tests/track-order.spec.ts`, which saves the generated script to that file. ## The session is configured on the command line The recording session is driven by flags, not by a test project's `use` block, so a `baseURL` or a custom test-id attribute configured for your suite does not apply unless you pass the matching flag. The ones worth knowing: `--target` (output language), `-o` (output file), `-b` / `--channel` (engine), `--device` and `--viewport-size` (emulation), `--save-storage` and `--load-storage` (session reuse), `--test-id-attribute` (which attribute becomes `getByTestId`). ## What you get is a draft On a food-delivery order tracker, ten minutes of clicking through live status and the driver map produces a single flat `test('test', ...)` body: literal order ids, recording-order steps, no assertions beyond the ones you inserted, and a brittle CSS fallback wherever the page offered the generator nothing user-facing to anchor on. Everything a real test needs on top of that — naming, data setup, the checks that make it a test rather than a walkthrough — is yours to add. Read every generated line before you commit it.

  • Does codegen need an existing Playwright test project to run?
    No. It is a standalone CLI: `npx playwright codegen <url>` works in an empty directory as long as the browsers are installed. It does not read a `playwright.config.ts`, which is why the recording session is configured with flags such as `--device` and `--test-id-attribute` rather than from a project's `use` block.
  • How does codegen record typing — one call per keystroke or one per field?
    One per field. The recorder collapses a burst of typing into a single `fill()` carrying the final value, which is both shorter and more reliable than replaying keystrokes. Use `press()` explicitly when the key itself matters, such as Enter to submit or Escape to close the driver-map overlay.

It is a dashcam for a browsing session that writes code instead of video: it faithfully records what happened, and it is still on you to decide which part of the footage matters.

saying these in an interview costs you the question

  • Thinks codegen produces a finished, maintainable test
  • Believes the recorder adds waits and assertions on its own
  • Cannot name the flag that saves output to a file
  • Assumes codegen reads the project config for baseURL
  • Thinks each keystroke becomes a separate generated call
open as a page

What does npx playwright test --ui give you that a plain headed run does not?

level: juniorimportance: must knowfreq 62%

basics

~20 s

Playwright's UI mode opens a watching test explorer: pick tests, re-run them on save, and step through a recorded timeline with before and after DOM snapshots, plus a Pick locator button. A headed run only shows the browser flying past.

open as a page

How does Playwright's codegen decide which locator to emit for an element you click?

level: middleimportance: must knowfreq 58%

basics

~20 s

Playwright's recorder inspects the element and prefers user-facing anchors: the configured test-id attribute, then role with accessible name, label, placeholder or visible text. Only when none exists does it fall back to a structural CSS chain.

open as a page

In Playwright, what does the --debug flag change about how a test run executes?

level: middleimportance: must knowfreq 55%

basics

~20 s

Playwright's --debug flag is a shortcut for PWDEBUG=1. It runs the browser headed, drops the run to a single worker, sets timeouts to zero so nothing expires while you read, and opens the Playwright Inspector paused before the first action.

open as a page

How do you make `npx playwright codegen` emit pytest code instead of TypeScript?

level: middleimportance: should knowfreq 44%

basics

~10 s

Pass --target python-pytest, or switch the language dropdown in the recorder window. The default target is playwright-test, and --target only changes the binding the same recorded actions are printed in.

open as a page

Why does await page.pause() in a Playwright test require a headed browser?

level: middleimportance: should knowfreq 44%

basics

~20 s

The only way past page.pause() is a human pressing Resume in the Playwright Inspector, and the Inspector is a window. Headless there is nobody to resume it, so the call belongs in a local session and never in committed code.

open as a page

Playwright's codegen opens a clean browser every run — how do you record a flow behind sign-in?

level: seniorimportance: should knowfreq 36%

basics

~20 s

Record once with --save-storage to write the session's cookies and localStorage to a file, then relaunch codegen with --load-storage pointing at that file, so recording starts already signed in and captures only the steps you care about.

open as a page

In Playwright, what does DEBUG=pw:api show you that a headed re-run does not?

level: seniorimportance: should knowfreq 37%

basics

~20 s

Playwright's DEBUG=pw:api logging prints its own call log to stderr: every API call, the element each locator resolved to, and the reason each action retried. A headed re-run shows the final picture but never names the failing check.

open as a page

Your team debugs every Playwright failure by re-running headed with slowMo. What would you change?

level: principalimportance: should knowfreq 30%

basics

~20 s

Make UI mode the default local loop and keep headed plus slowMo for the rare interaction you must watch in real time. Slowing every action changes timing, costs wall-clock minutes per look, and leaves no record to re-examine.

open as a page

What do `--device` and `--viewport-size` change when you run Playwright's codegen?

level: middleimportance: nice to knowfreq 28%

basics

~20 s

They configure the recording session only. --device applies a named descriptor, including viewport, user agent and touch, so you record the mobile layout; --viewport-size sets just the window dimensions. Neither appears in the generated script.

open as a page