How to use Codegen for coding

coding入门18 分钟阅读2026/7/3

I was staring at a blank test file, dreading what came next. Our team had just shipped a new onboarding flow with seven steps, multiple form validations, and a dashboard that only appeared after completion. Manual testing was taking 45 minutes per run, and we needed automated end-to-end tests yesterday. The problem? Writing Playwright tests from scratch for all those flows felt like it would take a week.

That's when I decided to really give Playwright's Codegen a proper spin. I'd messed with it briefly before but never committed to a full workflow. Here's what I learned from using it to generate tests for that entire onboarding flow—and where it saved me versus where it wasted my time.

What Codegen Actually Is

Playwright's Codegen is a test recorder that watches you interact with a browser and writes Playwright test code in real time. It opens two windows: the browser where you perform actions, and the Playwright Inspector where the generated code appears live.

It's not a no-code tool. You still need to understand Playwright and clean up the output. But for getting the skeleton of a test down fast—especially for complex multi-step flows—it's genuinely useful.

Getting Started

The basic command is straightforward:

npx playwright codegen https://myapp.com/onboarding

This opens the browser window pointed at your URL and the Inspector panel side by side. If you don't include a URL, you get a blank browser and can navigate manually.

For my case, I wanted to target our staging environment and generate TypeScript output:

npx playwright codegen --target=typescript https://staging.myapp.com/onboarding

You can also specify the browser:

npx playwright codegen --browser=webkit https://staging.myapp.com/onboarding

The --target flag supports javascript, playwright-test, python, python-async, csharp, and java. I stick with playwright-test since that's our test runner.

Recording the Onboarding Flow

With Codegen running, I walked through our entire onboarding process. I filled in the user name, selected a plan, entered payment details, confirmed the email, and landed on the dashboard.

As I clicked and typed, Codegen generated code in real time. Here's what it produced for the first few steps:

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

test('test', async ({ page }) => {
  await page.goto('https://staging.myapp.com/onboarding');
  await page.getByLabel('Full Name').fill('Alex Rivera');
  await page.getByLabel('Email').fill('alex@test.com');
  await page.getByRole('button', { name: 'Continue' }).click();
  await page.getByLabel('Company Size').selectOption('11-50');
  await page.getByRole('button', { name: 'Next Step' }).click();
  // ... and so on for all seven steps
});

This was already a huge time saver. Typing out all those locators and interactions manually would have taken hours. But the raw output isn't production-ready—more on that below.

The Smart Locator Generation

Here's where Codegen genuinely impressed me. It doesn't just blindly grab CSS selectors or XPath. It analyzes the page and picks the most resilient locator available, following this priority:

  1. Role locators (getByRole) — best for accessibility and resilience
  2. Text locators (getByText) — good for buttons and links
  3. Test ID locators (getByTestId) — great when you control the markup
  4. Label locators (getByLabel) — ideal for form fields
  5. CSS/XPath — last resort

When I clicked our "Continue" button, Codegen generated getByRole('button', { name: 'Continue' }) instead of something brittle like page.locator('#btn-step-1-continue'). This matters because role-based locators survive redesigns and refactors much better than CSS selectors.

When multiple elements matched a locator—for instance, we had two "Continue" buttons visible at one point—Codegen improved the locator to uniquely identify the target. It added extra context like the section heading or parent container.

Adding Assertions

This was a feature I initially overlooked. Codegen isn't just for recording actions—you can record assertions too.

In the Inspector toolbar, there's an assertion icon. Click it, then click an element on the page. You get three options:

  • Assert visibility — verify the element is visible
  • Assert text — verify the element contains specific text
  • Assert value — verify a form element has a specific value

I used this to assert that the dashboard loaded correctly after onboarding:

await expect(page.getByRole('heading', { name: 'Welcome to Your Dashboard' })).toBeVisible();
await expect(page.getByText('Setup Complete')).toBeVisible();

These assertions were spot-on. I didn't have to go back and manually add them later.

Picking Locators Without Recording

Here's a trick I discovered halfway through: you can use Codegen just to pick locators without recording a full test.

  1. Hit the Record button to pause recording
  2. The Pick Locator button appears
  3. Click it, then hover over elements to see the recommended locator

This was incredibly useful when I needed to find the right locator for an element in an existing test I was debugging. Instead of guessing at selectors, I'd fire up Codegen, pick the locator, and copy it into my test.

The Cleanup Work

Here's the honest part—Codegen's output needs cleanup before it's production code. Here's what I had to fix:

1. Everything goes in one giant test. Codegen records one continuous flow. I broke it into logical test cases: "can complete step 1", "can select a plan", "can reach dashboard".

2. Test data is hardcoded. Every value I typed during recording was literal in the code. I replaced these with variables and fixtures:

// Before (raw Codegen output)
await page.getByLabel('Full Name').fill('Alex Rivera');

// After (with test data)
await page.getByLabel('Full Name').fill(testUser.fullName);

3. No waiting strategies. Codegen sometimes adds waitForTimeout calls when pages load slowly. These are fragile. I replaced them with proper waitForSelector or waitForURL calls.

4. Redundant interactions. I noticed Codegen recorded some hover actions I didn't intentionally perform—just mouse movements that happened to cross elements. I removed those.

5. The test name is always "test". Not helpful. Rename descriptively.

Generating Locators for Existing Tests

One workflow that worked better than I expected: using Codegen alongside manual test writing. I'd write the test structure myself—describe blocks, beforeEach hooks, test organization—but use Codegen just to generate the locators.

Fire it up, pick the locator, paste it in. This cut my locator-finding time by probably 70%. No more inspecting elements in DevTools, copying CSS selectors, and praying they don't break.

Practical Tips

  • Record in your target environment. Recording against localhost and running against staging often produces different locators and flows.
  • Record slowly and deliberately. Accidental clicks and hovers generate noise in the output. Take your time.
  • Use the Clear button liberally. If you mess up a recording, hit Clear in the Inspector and start over. It's faster than editing bad output.
  • Stop recording before picking locators. The Pick Locator mode only appears when recording is paused.
  • Copy code immediately. The Inspector doesn't save state. Once you close it, the code is gone. Copy to your editor after each successful recording.
  • Add data-testid attributes to your app. Codegen will prefer these when available, and they're the most stable locator strategy long-term.

Honest Assessment

Codegen is not a replacement for understanding Playwright. The generated tests are a starting point, not a finished product. If you treat the output as production-ready without cleanup, you'll end up with flaky, brittle tests that fail in CI.

That said, for my onboarding flow task, Codegen turned what would have been a week of writing tests from scratch into about a day and a half—recording took an hour, cleanup and restructuring took the rest. The locator generation alone saves enormous time, and the assertion recording is a nice bonus I now use regularly.

Where Codegen falls short: highly dynamic pages with lots of async content, canvas-based interactions, and anything requiring complex setup state. For those, you're back to writing tests manually.

The sweet spot is multi-step form flows, navigation sequences, and any UI where you need to capture a happy path quickly. Record it, clean it up, parameterize the data, and you've got a solid test in a fraction of the time.

相关 Agent

C

光标编辑器

AI驱动的代码编辑器,支持智能补全和对话。

了解更多 →