Playwright AI Codegen in 2026: Generating Test Suites from Natural Language
Playwright's codegen --ai writes tests from plain English. I still review everything — but I type about 80% less than I used to.
Press Listen. A recorded voice reads the article, lights the current word, and keeps that word in view.
How listen mode works
The recording is a neural voice, not your browser's speech engine. The word being spoken lights up from the audio clock, including after you pause, drag the bar, or change speed. If you chose UK and only the US recording exists, you hear the US voice. Leaving the page stops playback.
In the Playwright MCP guide, you learned how to let an AI agent drive your browser through natural language. Now we go one step deeper: AI codegen — where Playwright writes the test script for you, not just executes your commands. You describe what you want in plain English, and Playwright generates idiomatic, maintainable code in your language of choice (C#, Python, TypeScript, or Java).
If Playwright MCP is like having an AI chauffeur drive your car, AI codegen is like the chauffeur writing you the driver’s manual — so you can replay the journey anytime, tweak the route, and commit it to CI/CD.
This post is the natural next step after the Selenium 2026 and Playwright MCP guides. No prior AI experience needed — just a working Playwright install.
What npx playwright codegen --ai Actually Does
Traditional playwright codegen (no --ai flag) records your clicks and keystrokes and translates them into Playwright scripts mechanically:
Click on button #checkout → await page.ClickAsync("#checkout")
Type "test@example.com" → await page.FillAsync("#email", "test@example.com")
It works, but it’s brittle. The selectors are whatever CSS path Playwright guesses at the moment of recording. Change the DOM, and the script breaks.
AI codegen (--ai flag, stable since Playwright v1.50) is fundamentally different:
flowchart TD
A["📝 Natural Language<br/>'Log in with admin credentials<br/>and verify the dashboard shows<br/>3 active projects'"] --> B["🧠 Playwright AI Codegen Engine"]
B --> C["🔍 Page Analysis<br/>(DOM tree + accessibility snapshot)"]
B --> D["🧩 Step Planner<br/>(breaks intent into actions)"]
C --> E["🎯 Intent-Based Locator Generator"]
D --> E
E --> F["📍 Locators:<br/>page.GetByRole('button', { name: 'Sign In' })<br/>page.GetByLabel('Email')<br/>page.GetByText('3 active projects')"]
D --> G["📜 Script Generator<br/>(language-specific output)"]
F --> G
G --> H["💻 Generated Script<br/>await page.GetByLabel('Email').FillAsync('admin@test.com');<br/>await page.GetByRole('button', { name: 'Sign In' }).ClickAsync();<br/>await Expect(page.GetByTestId('project-count')).ToHaveTextAsync('3');"]
The engine doesn’t just record — it understands intent. Instead of generating page.Locator("#email-17abc"), it generates page.GetByLabel("Email") — a semantic locator that survives DOM reshuffles.
Step 1: Basic AI Codegen — From Sentence to Script
Open a terminal and run:
npx playwright codegen --ai https://your-app.com/login
A Chromium window opens alongside the Playwright Inspector. In the inspector, instead of clicking around, type what you want:
Log in with:
- Email: admin@example.com
- Password: SuperSecret123!
After login, verify the page title contains "Dashboard"
Click on "Projects" in the sidebar
Verify the project list has at least 5 items
Playwright watches the page, plans the steps, and generates:
// Generated by Playwright AI Codegen — C# / NUnit
using Microsoft.Playwright.NUnit;
public class LoginFlowTests : PageTest
{
[Test]
public async Task AdminLoginAndVerifyProjects()
{
await Page.GotoAsync("https://your-app.com/login");
// Fill login form using semantic locators
await Page.GetByLabel("Email").FillAsync("admin@example.com");
await Page.GetByLabel("Password").FillAsync("SuperSecret123!");
await Page.GetByRole(AriaRole.Button, new() { Name = "Sign In" }).ClickAsync();
// Web-First assertion: auto-waits for title match
await Expect(Page).ToHaveTitleAsync(new System.Text.RegularExpressions.Regex("Dashboard"));
// Navigate to Projects
await Page.GetByRole(AriaRole.Link, new() { Name = "Projects" }).ClickAsync();
// Assert project list has at least 5 items
var projectItems = Page.GetByTestId("project-list-item");
await Expect(projectItems.First).ToBeVisibleAsync();
var count = await projectItems.CountAsync();
Assert.That(count, Is.GreaterThanOrEqualTo(5));
}
}
sequenceDiagram
participant You
participant Codegen as Playwright AI Codegen
participant Browser as Chromium Browser
participant App as Your Web App
You->>Codegen: "Log in with admin credentials,<br/>verify 3 active projects on dashboard"
Codegen->>Browser: Navigate to /login
Browser->>App: GET /login
App-->>Browser: Login page HTML
Codegen->>Codegen: Analyze DOM:<br/>- Find elements with labels "Email", "Password"<br/>- Find button with accessible name "Sign In"<br/>- Plan: Fill → Fill → Click → Assert
Codegen->>Browser: Fill "Email" field
Codegen->>Browser: Fill "Password" field
Codegen->>Browser: Click "Sign In"
Browser->>App: POST /login
App-->>Browser: Redirect to /dashboard
Codegen->>Codegen: Analyze new page:<br/>- Title contains "Dashboard"?<br/>- Find "3 active projects" text<br/>- Generate assertion
Codegen-->>You: ✅ Script generated:<br/>page.GetByLabel("Email").FillAsync(...)<br/>page.GetByRole(button).ClickAsync()<br/>Expect(page).ToHaveTitleAsync(/Dashboard/)<br/>Expect(page.GetByTestId("project-count")).ToHaveTextAsync("3")
Multi-Language Output
AI codegen supports all Playwright languages. The same natural-language input generates idiomatic code for each:
| Language | Command | Generated assertion style |
|---|---|---|
| C# / NUnit | Default on .NET projects | await Expect(Page.GetByText("Success")).ToBeVisibleAsync(); |
| Python / pytest | --ai --lang python |
expect(page.get_by_text("Success")).to_be_visible() |
| TypeScript | --ai --lang ts |
await expect(page.getByText("Success")).toBeVisible(); |
| Java / JUnit | --ai --lang java |
assertThat(page.getByText("Success")).isVisible(); |
Step 2: From Requirements Document to Full Test Suite
The real power of AI codegen emerges when you feed it a requirements document instead of one-off instructions. This is the workflow teased in the AI-Driven Test Strategy post — Phase 2 in practice.
The Requirements-to-Tests Pipeline
flowchart LR
A["📄 Requirements Doc<br/>.md / .txt / Confluence"] --> B["✂️ Split into Scenarios<br/>(AI parses 'happy path',<br/>'edge case', 'error state')"]
B --> C["🔀 For Each Scenario"]
C --> D["🎬 playwright codegen --ai"]
D --> E["📜 Generated Test File"]
C --> F["🎬 playwright codegen --ai"]
F --> G["📜 Generated Test File"]
C --> H["🎬 playwright codegen --ai"]
H --> I["📜 Generated Test File"]
E --> J["🧪 Combined Test Suite"]
G --> J
I --> J
J --> K["✅ Ready for CI/CD"]
Practical Example
Say you have this requirements snippet for an e-commerce checkout:
# Checkout Flow Requirements
## Happy Path
- User adds item to cart from product page
- User proceeds to checkout
- User enters valid shipping address
- User selects credit card payment
- User confirms order
- System displays order confirmation with order number
- System sends confirmation email
## Edge Cases
- User tries to checkout with empty cart → show "Cart is empty" message
- User enters invalid credit card → show inline validation error
- User's session expires during checkout → redirect to login, preserve cart
## Error States
- Payment gateway timeout → show "Payment processing, do not refresh" with retry
- Inventory goes out of stock between add-to-cart and checkout → show "Item unavailable" with alternatives
Feed each section separately to AI codegen for best results:
# Happy path
npx playwright codegen --ai https://your-store.com/product/123 \
--prompt "Add the item to cart, proceed to checkout, fill valid shipping
address, select credit card payment, confirm order, verify order
confirmation appears with an order number."
# Edge case: empty cart
npx playwright codegen --ai https://your-store.com/checkout \
--prompt "Navigate directly to /checkout with an empty cart. Verify
the page shows 'Cart is empty' and the checkout button is disabled."
# Edge case: invalid credit card
npx playwright codegen --ai https://your-store.com/checkout \
--prompt "Add an item to cart, go to checkout, enter credit card
number '0000-0000-0000-0000', verify an inline error appears
below the card field saying 'Invalid card number'."
# Error state: payment timeout
npx playwright codegen --ai https://your-store.com/checkout \
--prompt "Complete checkout up to payment step, then simulate a
payment gateway timeout (use the test card 4444-3333-2222-1111
which triggers a timeout on this app). Verify 'Payment processing'
message appears with a retry button."
AI codegen generates a separate test file per scenario. Combine them into a single test class, add a [Test] attribute per method, and you have a complete checkout test suite — generated from the requirements doc in under 10 minutes.
What AI Codegen Gets Right (and Wrong)
| What it nails | What needs human review |
|---|---|
Semantic locators (GetByRole, GetByLabel, GetByTestId) |
Business logic assertions (did the order really succeed?) |
| Web-First Assertions with auto-retry | Test data setup (creating test users, seeding the database) |
Error handling patterns (Try/Catch, timeout configuration) |
Test isolation (does test B depend on test A’s state?) |
| Consistent naming conventions per language | Edge cases the requirements doc didn’t mention |
using statements and imports |
Performance (did it generate 50 sequential tests when 10 parallel ones would work?) |
The human’s job shifts from writing code to reviewing code. You spend 80% less time typing and 100% more time thinking about what could go wrong.
Step 3: Refining AI-Generated Tests
AI codegen gives you an 80% solution. Here’s how to get to 95%.
Add Test Data Setup
AI codegen works against live pages. It doesn’t know how to seed your database. Add setup methods manually:
[SetUp]
public async Task Setup()
{
// AI can't generate this — you know your data model
await ApiClient.SeedAsync(new TestData
{
User = new User { Email = "admin@example.com", Role = "Admin" },
Projects = Enumerable.Range(1, 5).Select(i => new Project { Name = $"Project {i}" }).ToList()
});
await Page.GotoAsync("https://your-app.com/login");
}
Replace Hardcoded Values with Test Parameters
AI codegen generates hardcoded values. Parameterize them:
// ❌ AI-generated: hardcoded values
await Page.GetByLabel("Email").FillAsync("admin@example.com");
// ✅ After human refinement: parameterized
[TestCase("admin@example.com", "SuperSecret123!", ExpectedResult = true)]
[TestCase("user@example.com", "wrong-password", ExpectedResult = false)]
public async Task<bool> LoginFlow(string email, string password)
{
await Page.GetByLabel("Email").FillAsync(email);
await Page.GetByLabel("Password").FillAsync(password);
await Page.GetByRole(AriaRole.Button, new() { Name = "Sign In" }).ClickAsync();
return await Page.GetByText("Dashboard").IsVisibleAsync();
}
Add Visual Regression Checks
AI codegen doesn’t generate visual assertions. Add them:
// After AI-generated checkout flow completes
await Expect(Page).ToHaveScreenshotAsync("checkout-confirmation.png", new()
{
MaxDiffPixelRatio = 0.01f // Allow 1% pixel difference
});
Step 4: AI Codegen + MCP — Two Sides of the Same Coin
AI codegen and Playwright MCP (from the previous guide) solve different problems:
| AI Codegen | Playwright MCP | |
|---|---|---|
| What it does | Generates Playwright scripts you commit to your repo | Lets AI agents control the browser in real time |
| Output | .cs / .py / .ts / .java files |
Browser actions + screenshots + network traces |
| Best for | CI/CD pipelines, regression suites, repeatable tests | Exploratory testing, one-off audits, debugging |
| Determinism | Deterministic (same script, same result) | Non-deterministic (AI decides next action) |
| Human review | Review once, run forever | Review per session |
The Combined Workflow
flowchart TD
A["📄 Requirements Document"] --> B["🤖 AI Codegen<br/>Generate test scripts"]
B --> C["👤 Human Review<br/>Add setup, parameterize,<br/>add visual checks"]
C --> D["🧪 CI/CD Pipeline<br/>Run on every PR"]
D --> E{"Test failed?"}
E -->|Yes| F["🔍 Playwright MCP<br/>AI agent investigates<br/>Opens browser, inspects DOM,<br/>captures screenshots"]
F --> G["📊 Diagnostic Report<br/>Root cause + suggested fix"]
G --> C
E -->|No| H["✅ PR Approved"]
AI codegen creates the tests, MCP debugs them when they fail. Together, they form a self-improving test pipeline — the Phase 4 vision from the AI-Driven Test Strategy post.
Step 5: CI/CD Integration — Generated Tests in Your Pipeline
AI-generated tests slot into any CI/CD pipeline. Here’s a GitHub Actions example:
name: AI-Generated E2E Tests
on:
pull_request:
branches: [main]
jobs:
playwright-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0'
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium
- name: Run AI-generated test suite
run: dotnet test tests/GeneratedE2E/ --filter "Category=Smoke"
- name: Upload Playwright trace on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-trace
path: test-results/
Key point: the generated tests use GetByRole, GetByLabel, and GetByTestId — locators that are resilient to DOM changes. Your CI/CD pipeline won’t break because a CSS class was renamed.
Where Existing Posts Fit
This post completes the 2026 Playwright trilogy:
| Earlier post | What it covered | What this post adds |
|---|---|---|
| Playwright MCP + Multi-Agent (Jul 2026) | Letting AI drive the browser via MCP, multi-agent orchestration | AI writing the test scripts you commit to version control |
| Playwright .NET Framework (Sep 2024) | Manual Playwright setup: DI, Page Objects, Allure reports | AI-generated Page Objects and test classes replace manual wiring |
| AI-Driven Test Strategy (Jun 2026) | Phase 2: AI-assisted test generation with structured prompts | Phase 2 in practice: codegen --ai as the implementation |
| Selenium 2026 Beginner’s Guide (Jul 2026) | Selenium setup, BiDi, MCP server | Playwright’s AI codegen is the capability Selenium doesn’t yet match — see BiDi vs CDP for the architectural reasons why |
When to Use AI Codegen vs. Alternatives
flowchart TD
START["🤔 I need Playwright tests"] --> Q1{"Are the requirements<br/>well-documented?"}
Q1 -->|"Yes — I have a spec,<br/>PRD, or Confluence page"| AI["🤖 AI Codegen<br/>Feed requirements →<br/>generate suite →<br/>human review"]
Q1 -->|"No — I'm still<br/>figuring out the flow"| Q2{"Do I need to explore<br/>the app interactively?"}
Q2 -->|Yes| MCP["🧠 Playwright MCP<br/>AI agent drives browser,<br/>you observe + learn"]
Q2 -->|No| MANUAL["✍️ Traditional codegen<br/>Record clicks →<br/>refine selectors manually"]
AI --> REVIEW["👤 Human Review<br/>Add data setup,<br/>parameterize,<br/>visual checks"]
MCP --> DOC["📝 Document findings<br/>→ Feed to AI codegen<br/>for v2 of tests"]
MANUAL --> REVIEW
REVIEW --> CI["🧪 Commit to CI/CD"]
Sources & Further Reading
- Playwright Codegen Documentation — official guide to the test generator, including
--aimode - Playwright .NET API Reference — C# API docs for the locator and assertion patterns used throughout
- Model Context Protocol Specification — the MCP standard that enables the combined AI codegen + MCP debugging workflow in Step 4
- Angie Jones / mcp-selenium — the original Selenium MCP server for comparison with Playwright’s native
@playwright/mcp
What to Do Next
- Try basic AI codegen right now. Run
npx playwright codegen --aiagainst any public website and type “Log in, verify the page title contains Dashboard, then click the first item in the list.” Watch the semantic locators appear in real time. - Feed a real requirements doc. Take a Confluence page or PRD you already have, split it into scenarios, and feed each section to
codegen --ai. You’ll have a test suite in under 30 minutes. - Combine with MCP for debugging. When an AI-generated test fails in CI, spin up Playwright MCP to investigate the failure interactively instead of staring at a trace file.
- Compare to Selenium. Read the BiDi vs CDP comparison to understand why Playwright’s native CDP architecture enables AI codegen while Selenium’s WebDriver layer makes it harder.
- Subscribe to this blog’s feed.xml — next up: self-healing test suites that automatically fix broken locators in CI/CD using the same intent-based AI that powers codegen.
See also: Playwright vs Selenium in 2026 (Jun 2026) — the speed, reliability, and ecosystem comparison that explains why Playwright leads on AI-native features like codegen. · XPath for Test Automation (Jul 2026) — the story-mode article with §12 complex XPath & CSS for SDETs (the locator patterns AI codegen generates that you should review before merging — SVG, computed indices, ARIA chains, iframe/shadow-DOM, modern CSS :has()/:is()/:where())..
Add a thought
The writing box stays shut until the code matches. A note you save shows up under this article on this browser. It is not emailed. Posting it for everyone opens GitHub, which asks you to sign in.