Test Patterns for AI-Driven Browser Automation
Updated Aug 2026
A note on how to read the examples: the Playwright CLI is ref-driven. The agent takes a snapshot (a YAML accessibility summary saved to disk), reads it to find elements like textbox "Email" [ref=e3], and then acts by ref. In the examples below, assume refs come from the most recent snapshot — the comments show what the agent saw there. Every action auto-waits for actionability (same Playwright engine underneath), so you will see far fewer explicit waits than in 2025-era CLI scripts.
Pattern 1: Navigate-Act-Verify (NAV)
The fundamental test pattern. Every browser test follows this structure:
Navigate → Act → Verify
Example: Login Test
# NAVIGATE
playwright-cli open https://app.example.com/login
playwright-cli snapshot
# → textbox "Email" [ref=e3], textbox "Password" [ref=e4], button "Sign in" [ref=e5]
# ACT
playwright-cli fill e3 "user@test.com"
playwright-cli fill e4 "secret123"
playwright-cli click e5
# VERIFY
playwright-cli snapshot
# → Agent checks the YAML: heading "Dashboard" present? PASS
Agent's Role
The agent decides:
- What URL to navigate to
- Which ref to act on (resolved from the snapshot by role and accessible name)
- What text to type
- How to verify success (snapshot contents,
eval "location.href"for URL changes, element presence)
Pattern 2: Form Validation Testing
Test that forms reject invalid input correctly.
Example: Registration Form
# Test: empty form submission
playwright-cli goto https://app.example.com/register
playwright-cli snapshot
# → textbox "Email" [ref=e3], textbox "Password" [ref=e4], button "Create account" [ref=e5]
playwright-cli click e5 # Submit empty form
playwright-cli snapshot
# → Agent verifies alerts in YAML: "Email is required", "Password is required"
# Test: invalid email
playwright-cli fill e3 "not-an-email"
playwright-cli click e5
playwright-cli snapshot
# → Agent verifies: "Please enter a valid email"
# Test: weak password
playwright-cli fill e3 "valid@test.com"
playwright-cli fill e4 "123"
playwright-cli click e5
playwright-cli snapshot
# → Agent verifies: "Password must be at least 8 characters"
# Test: valid submission
playwright-cli fill e3 "valid@test.com"
playwright-cli fill e4 "StrongP@ss123"
playwright-cli click e5
playwright-cli snapshot
# → Agent verifies: "Registration successful"
Agent's Added Value
The agent can generate test cases from the form structure:
- Read the snapshot to enumerate every field, its role, and its accessible name
- Generate boundary-value tests automatically
- Verify error messages match expected UX copy
(For a whole suite of such cases, this is exactly the planner → generator hand-off from the Test Agents chapter — the agent explores, writes a Markdown plan, and generated .spec.ts files do the repetitive execution.)
Pattern 3: Multi-Page Flow
Tests that span multiple page navigations.
Example: E-Commerce Checkout
# Browse products
playwright-cli open https://shop.example.com
playwright-cli snapshot
# → link "Blue Widget" [ref=e7], price text "$29.99"
playwright-cli click e7
# Add to cart
playwright-cli snapshot
# → button "Add to cart" [ref=e12]
playwright-cli click e12
playwright-cli snapshot
# → Agent verifies: cart badge shows "1"
# Go to cart
playwright-cli goto https://shop.example.com/cart
playwright-cli snapshot
# → Agent verifies: "Blue Widget", total "$29.99"; button "Checkout" [ref=e9]
# Checkout
playwright-cli click e9
playwright-cli snapshot
# → textbox "Card number" [ref=e14], textbox "Expiry" [ref=e15],
# textbox "CVV" [ref=e16], button "Pay now" [ref=e17]
playwright-cli fill e14 "4111111111111111"
playwright-cli fill e15 "12/29"
playwright-cli fill e16 "123"
playwright-cli click e17
playwright-cli snapshot
# → Agent captures: "Order #12345"
Key Considerations
- State carries between pages (cart contents, session cookies) — a named session holds it
- Refs do not carry between pages — re-snapshot after every navigation
- Screenshot at each page for a debugging trail (files on disk; free until read)
Pattern 4: Data Extraction and Verification
Extract structured data from the page and verify against expected values.
Example: Dashboard Metrics
playwright-cli goto https://app.example.com/dashboard
playwright-cli eval "JSON.stringify({
revenue: document.querySelector('.metric-revenue').textContent,
users: document.querySelector('.metric-users').textContent,
orders: document.querySelector('.metric-orders').textContent
})"
# → {"revenue": "$45,230", "users": "1,234", "orders": "567"}
Example: Table Data
playwright-cli goto https://app.example.com/users
playwright-cli eval "JSON.stringify(
[...document.querySelectorAll('table tbody tr')].map(row => ({
name: row.cells[0].textContent,
email: row.cells[1].textContent,
role: row.cells[2].textContent
}))
)"
# → [{"name": "Alice", "email": "alice@test.com", "role": "Admin"}, ...]
eval is the escape hatch: when you need data rather than interaction, one JavaScript expression beats parsing a snapshot. (Inside eval you write ordinary DOM selectors — refs are for CLI interaction commands.)
Agent's Added Value
The agent can:
- Parse the JSON output
- Compare against expected values from a database or API
- Identify discrepancies and report them meaningfully
Pattern 5: Async Operations (Uploads, Debounce)
For operations that don't complete immediately (AJAX calls, file uploads, etc.). Actions auto-wait for their target element, which covers most cases; for long-running operations, poll observable state via eval or re-snapshot.
Example: File Upload
playwright-cli goto https://app.example.com/upload
playwright-cli snapshot
# → button "Choose file" [ref=e6]
playwright-cli upload e6 ./fixtures/report.pdf
# Poll for completion instead of a blind sleep
playwright-cli eval "document.querySelector('.upload-status')?.textContent"
# → "Uploading… 47%" → agent re-checks until:
# → "Upload complete"
Example: Search with Debounce
playwright-cli goto https://app.example.com/search
playwright-cli snapshot
# → searchbox "Search" [ref=e3]
playwright-cli fill e3 "test query"
playwright-cli snapshot
# → Agent verifies results region: "15 results found"
# (if results haven't rendered yet, the agent re-snapshots — judgment, not sleep())
Pattern 6: Multi-Session Testing
Tests that require multiple browser contexts — two users, two roles, two environments. Named sessions (-s=name) replace the tab juggling of older CLI tools: each session is an isolated browser context, and one agent orchestrates all of them.
Example: Admin Changes a Price, Customer Sees It
playwright-cli -s=admin open https://app.example.com/admin
playwright-cli -s=customer open https://app.example.com/shop
playwright-cli list # both sessions visible
# Admin updates the price
playwright-cli -s=admin snapshot # → textbox "Price" [ref=e8], button "Save" [ref=e9]
playwright-cli -s=admin fill e8 "24.99"
playwright-cli -s=admin click e9
# Customer refreshes and verifies
playwright-cli -s=customer reload
playwright-cli -s=customer snapshot
# → Agent verifies: "$24.99"
Example: Compare Two Environments
playwright-cli -s=staging open https://staging.example.com
playwright-cli -s=prod open https://production.example.com
playwright-cli -s=staging eval "document.querySelector('.version').textContent"
playwright-cli -s=prod eval "document.querySelector('.version').textContent"
# Agent compares the two outputs
Pattern 7: Negative Testing
Verify that the application correctly rejects invalid operations.
Example: Unauthorized Access
# Try to access admin page without login
playwright-cli goto https://app.example.com/admin
playwright-cli eval "location.href"
# → Agent verifies: redirected to /login (not /admin)
playwright-cli snapshot
# → Agent verifies: heading "Please log in" (not admin content)
Example: Rate Limiting
# Rapid-fire requests (ref e5 = submit button from the current snapshot)
for i in $(seq 1 10); do
playwright-cli click e5
playwright-cli eval "document.querySelector('.response')?.textContent"
done
# Agent checks if rate limiting kicked in
Pattern 8: Visual Regression (Screenshot Comparison)
Use screenshots to detect visual changes.
# Capture baseline
playwright-cli goto https://app.example.com/dashboard
playwright-cli screenshot # → path in .playwright-cli/; copy to baseline/
# ... after code change ...
# Capture current
playwright-cli goto https://app.example.com/dashboard
playwright-cli screenshot # → copy to current/
# Agent compares screenshots (via vision or a pixel-diff tool)
Note the disk-first advantage here: screenshots never enter the model context unless the agent chooses to look. A pixel-diff tool can compare hundreds of PNG pairs for zero tokens; the agent only reads the images that actually differ.
Agent's Added Value
With vision capabilities, the agent can:
- Identify specific visual differences
- Classify changes as intentional vs regression
- Describe what changed in natural language
Pattern 9: Error State Testing
Verify the application handles errors gracefully.
Example: Network Error
# Use eval to simulate offline mode
playwright-cli eval "window.navigator.__defineGetter__('onLine', () => false)"
playwright-cli click e11 # "Save" button ref from current snapshot
playwright-cli snapshot
# → Agent verifies: appropriate offline message shown
Example: Server Error
playwright-cli goto https://app.example.com/broken-page
playwright-cli snapshot
# → Agent checks: is there a user-friendly error page (not a raw 500 stack trace)?
playwright-cli screenshot
Anti-Patterns
Don't: Hard-Code Wait Times
# BAD
playwright-cli goto https://app.example.com
sleep 5 # Arbitrary wait
playwright-cli snapshot
# GOOD
playwright-cli goto https://app.example.com
playwright-cli snapshot # actions auto-wait; for slow async state,
# poll via eval or re-snapshot with judgment
Don't: Act on Refs from a Stale Snapshot
# BAD: page navigated since the last snapshot
playwright-cli click e5 # e5 belonged to the previous page
# GOOD: re-snapshot after any navigation or major state change
playwright-cli snapshot
playwright-cli click e9 # ref from the current snapshot
Don't: Chain Commands Without Verification
# BAD: Assumes every step succeeds
playwright-cli goto url && playwright-cli click e3 && playwright-cli click e7
# GOOD: Verify each critical step
playwright-cli goto url
playwright-cli snapshot # confirm expected elements exist
playwright-cli click e3
playwright-cli snapshot # confirm the state actually changed
playwright-cli click e7