Skip to main content

Recording with Codegen

Playwright ships a recorder. You click through the flow in a real browser and it writes the test for you, with locators that follow the recommended priority. This is the Recording step of the JMeter track, with one difference: the recorded output is a starting point you will clean up, not the finished test.

Why Record?​

  • It gives you correct locators for free. The recorder prefers roles, labels and placeholders over CSS.
  • It captures the flow faster than typing it.
  • It teaches you the API. Watching what the recorder emits is the fastest way to learn getByRole and friends.

What it does not do: structure your test, name it well, add meaningful assertions, or handle test data. That is your job after recording.


Before You Start​

  1. Have the flow written down from Section 2: steps and pass condition
  2. Know the test account you will use
  3. Have the project from Section 1 open in VS Code

Option A: Record from the Command Line​

Steps:

  1. Start the recorder with the URL of the app:

    npx playwright codegen https://www.saucedemo.com/

    Two windows open: a browser and the Playwright Inspector with the generated code.

  2. In the browser, perform the flow as a real user. Every click and keystroke appears in the Inspector as code.

  3. Add assertions from the Inspector toolbar. Hover the toolbar to see the buttons:

    • Assert visibility: click it, then click an element, to generate toBeVisible()
    • Assert text: generates toContainText()
    • Assert value: generates toHaveValue() for inputs
    • Assert snapshot: generates toMatchAriaSnapshot() for a chunk of the page structure
  4. Use Pick locator any time you want to see what locator Playwright would generate for an element without recording an action.

  5. Click Copy in the Inspector, or save straight to a file:

    npx playwright codegen https://www.saucedemo.com/ -o tests/login.spec.ts

Useful flags:

FlagUse it when
--viewport-size="1280,720"The app is responsive and you want a fixed size
--device="iPhone 13"Recording a mobile flow
--save-storage=auth.jsonYou want to log in once and save the session (see Section 9)
--load-storage=auth.jsonStart the recorder already logged in
--test-id-attribute=data-testThe app uses a test id attribute other than data-testid
--target=pythonYou want Python instead of TypeScript output

Note: By default the recorder generates a toBeVisible() assertion after each navigation. That is a good starting point but not a real pass condition. Replace it with what the flow is actually supposed to prove.


Option B: Record from VS Code​

Steps:

  1. Open the Testing sidebar
  2. In the Playwright section, click Record new. VS Code creates a new spec file and opens a browser
  3. Perform the flow. Code is written into the file as you go
  4. Use the toolbar in the browser to add assertions, same buttons as Option A
  5. Close the browser or click Cancel to stop
  6. Rename the file and the test

The same sidebar has Record at cursor (append steps into an existing test at the cursor position) and Pick locator.

Tip: Recording at cursor is the fastest way to extend an existing test: put the cursor at the end of the test, press Record at cursor, do the extra steps, stop.


What the Recorder Produces​

A raw recording of the sample login flow looks like this:

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

test('test', async ({ page }) => {
await page.goto('https://www.saucedemo.com/');
await page.getByPlaceholder('Username').click();
await page.getByPlaceholder('Username').fill('standard_user');
await page.getByPlaceholder('Password').click();
await page.getByPlaceholder('Password').fill('secret_sauce');
await page.getByRole('button', { name: 'Login' }).click();
await expect(page.getByText('Products')).toBeVisible();
});

It works, but it is raw, the same way a fresh Blazemeter .jmx is raw:

  • The test is named test
  • Every field has a pointless click() before fill()
  • The URL and credentials are hardcoded
  • The assertion checks a word, not the pass condition

Clean Up the Recording​

Do these in order. Each one is a small edit.

  1. Name the test after the flow and its expected result: valid user lands on the products page
  2. Delete the click() before every fill(). fill() focuses the field itself
  3. Replace the hardcoded URL with page.goto('/') and set baseURL in the config (Section 8)
  4. Move credentials into tests/data/users.json (Section 6)
  5. Replace the assertion with the real pass condition, usually the URL plus the page title:
    await expect(page).toHaveURL(/inventory\.html/);
    await expect(page.getByTestId('title')).toHaveText('Products');
  6. Group related tests with test.describe and move shared navigation into beforeEach

After cleanup the same test is the one in playwright/sample/tests/login.spec.ts.


Tips​

  • Record once, then write by hand. After the first couple of recordings you will find it faster to type tests directly using the recorder only to pick locators.

  • Do not record logins over and over. Save the session once with --save-storage and load it. Section 9 turns this into an automatic setup step.

  • Record with the right viewport. A responsive app shows different buttons on mobile widths. Record at the size you will test at.

  • Recorder output is not the final test. Treat it like the raw .jmx: it needs correlation-style cleanup before it goes into the suite.