← Back to Blog

Why Playwright Codegen Isn't Enough for Real Teams

TL;DR: Playwright's recorder generates working tests, but not your tests. Every recorded test needs refactoring to match your patterns, page objects, and conventions. What if it didn't?

If you've used Playwright's codegen, you know the feeling. You click through a flow, watch the code appear in real-time, and think: this is great. Then you paste it into your test suite and spend the next 30 minutes making it actually fit.

The selectors need updating. The raw locators need wrapping in page objects. Your team's helper functions aren't used. The assertions don't follow your conventions.

Codegen solves the recording problem. But it creates a refactoring problem.

The Gap Between Generated Code and Production Tests

Playwright's built-in recorder is genuinely impressive. It handles complex selectors, generates readable code, and even picks up on accessibility attributes. For learning Playwright or quick prototypes, it's excellent.

But production test suites aren't prototypes.

Real teams have:

  • Page Object Models that abstract selectors behind meaningful methods
  • Custom utilities for common patterns like login, navigation, or API setup
  • Naming conventions for tests, files, and functions
  • Shared fixtures that set up test context
  • Assertion helpers that provide better error messages

Codegen knows nothing about any of this. It generates raw Playwright API calls because that's all it can generate. It doesn't know your LoginPage class exists, that you have a fillForm() helper, or that your team wraps all clicks in a custom safeClick() method.

The Hidden Cost: Death by a Thousand Refactors

Let's do some math.

Say you record a test that produces 20 lines of code. After refactoring to match your patterns, you've touched 15 of those lines. Time spent: 10-15 minutes if you know the codebase well. More if you're newer to the team.

Now multiply that by every test you record. Five tests a day? That's an hour of refactoring. Over a sprint, you've spent a full day just reformatting generated code.

And it's not just time. It's cognitive load. Every refactor is a decision:

  • "Do we have a page object for this?"
  • "What's that helper method called again?"
  • "Should this be a soft assertion or hard?"
  • "How does the team handle waits here?"

The mental tax adds up. Recording tests should feel fast. Instead, it feels like starting over every time.

What If Recording Generated Your Code?

Imagine a Playwright recorder with custom code mapping. One where you define the rules once:

  • "When clicking a login button, use loginPage.submit()"
  • "When filling an email field, use formHelpers.fillEmail(value)"
  • "When asserting visible text, use expectVisible(locator, text)"

Then every recording follows those rules automatically. No refactoring. No decisions. Just paste and commit.

This isn't about making codegen "smarter" with AI guessing. It's about explicit mapping rules that you control. Your patterns, your methods, your conventions—encoded once and applied everywhere.

Before: Raw Codegen Output

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

test('user can submit contact form', async ({ page }) => {
  await page.goto('https://example.com/contact');
  await page.getByLabel('Email').fill('[email protected]');
  await page.getByLabel('Message').fill('Hello, I have a question.');
  await page.getByRole('button', { name: 'Send Message' }).click();
  await expect(page.getByText('Thanks for reaching out!')).toBeVisible();
});

This works. But it's not how your team writes tests.

After: Custom-Mapped Output

import { test } from '../fixtures/base';
import { ContactPage } from '../pages/ContactPage';
import { expectToast } from '../helpers/assertions';

test('user can submit contact form', async ({ page }) => {
  const contactPage = new ContactPage(page);
  
  await contactPage.navigate();
  await contactPage.fillEmail('[email protected]');
  await contactPage.fillMessage('Hello, I have a question.');
  await contactPage.submit();
  await expectToast(page, 'Thanks for reaching out!');
});

Same recording. Same clicks. But the output matches your codebase. The page object is instantiated. Your custom fixture is imported. Your assertion helper is used.

No refactoring required.

Introducing Assertive Recorder

We built Assertive Recorder to close this gap.

It's a Playwright test recorder that lets you define mapping rules for how actions and assertions translate to code. Record your tests naturally, and get output that matches your team's patterns.

Here's what makes it different:

  • Custom selector mappings — Route specific elements to your page object methods
  • Action transforms — Convert raw clicks and fills into your helper functions
  • Assertion rules — Generate your preferred assertion style automatically
  • Import management — Correct imports added based on what mappings are used
  • Team sharing — Export your rules so everyone generates consistent code

You set up the rules once. Then every team member records tests that look like a senior engineer wrote them.

When Codegen Is Enough (And When It Isn't)

To be clear: Playwright's built-in codegen is a great tool. Use it when:

  • You're learning Playwright
  • You need a quick throwaway test
  • You're exploring a new feature before writing proper tests
  • Your project doesn't have established patterns yet

But once you have page objects, shared utilities, and team conventions, raw codegen starts working against you. Every recording creates technical debt that needs immediate cleanup.

If you've ever looked at a recorded test and thought "I'll have to rewrite most of this anyway"—that's the signal. You need a recorder that understands your code.

Try It Yourself

Assertive Recorder is built for teams who already have Playwright test suites and want to accelerate test creation without sacrificing code quality.

Get Started with Assertive Recorder →

Define your mapping rules, record a test, and see the difference. Your future self (and your code reviewers) will thank you.


Have questions about custom code mapping or want to see how it handles your specific patterns? Reach out — we'd love to hear about your setup.

Ready to stop refactoring?

Generate tests that match your codebase from day one.

Get Assertive Recorder