Playwright E2E Test Writer

Writes Playwright end-to-end tests from a described user flow using role-based selectors and web-first assertions, with no arbitrary waits.

Reviewed Jul 7, 2026Testing & QAby AI World InformationMIT

What this skill does

Key features

  • Turns a described user flow into a runnable Playwright spec
  • Uses role and label selectors instead of brittle CSS or XPath
  • Relies on web-first assertions that auto-wait for state
  • Avoids fixed timeouts and manual sleeps that cause flake

Use cases

  • Cover a critical signup or checkout flow before shipping
  • Add a regression test that reproduces a reported UI bug

SKILL.md

The skill definition — its metadata and the exact instructions an agent follows. Copy it into a SKILL.md file in your agent's skills folder.

namee2e-playwright
descriptionWrite a Playwright end-to-end test for a described user flow using stable selectors and web-first assertions.
allowed-toolsRead, Grep, Write, Bash(npx playwright test:*)
outputplaywright spec file
runnerplaywright

Musts

  • Restate the user flow as ordered steps before writing the spec, so each assertion maps to a user-visible outcome.
  • Select elements by role, label, or accessible text using getByRole, getByLabel, or getByText.
  • Use web-first assertions such as expect(locator).toBeVisible() that auto-wait for the expected state.
  • Assert the outcome of each step, not just that navigation happened.
  • Keep tests independent so any one can run alone without relying on another’s leftover state.

Guidelines

  • Never use page.waitForTimeout or fixed sleeps; let assertions and auto-waiting handle timing.
  • Prefer a stable data-testid only when no accessible role or label fits.
  • Reset or isolate test data per test so reruns are deterministic.
  • Group steps with test.step when a flow has several stages, to make failures readable.
  • Keep one user journey per test file section rather than one giant test.

Output format

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

test('user can sign in and reach the dashboard', async ({ page }) => {
  await page.goto('/login');

  await page.getByLabel('Email').fill('user@example.com');
  await page.getByLabel('Password').fill('correct-horse');
  await page.getByRole('button', { name: 'Sign in' }).click();

  await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
  await expect(page.getByText('Welcome back')).toBeVisible();
});

FAQ

Why not use CSS selectors for elements?
CSS classes change with styling and break tests. Role and label selectors track what the user sees and stay stable across refactors.
How does it avoid flaky waits?
It uses web-first assertions like expect(locator).toBeVisible() that retry until the condition holds, instead of page.waitForTimeout.

Before running any skill, read its instructions and the tools it's allowed to use, and test it on a safe target first. See LLM security best practices.