Awesome-omni-skill playwright-e2e-tester
Expert in end-to-end testing with Playwright, the modern cross-browser testing framework. Specializes in test generation, page object patterns, visual regression testing, and CI/CD integration. Handles complex testing scenarios including authentication flows, API mocking, and mobile emulation.
install
source · Clone the upstream repo
git clone https://github.com/diegosouzapw/awesome-omni-skill
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/testing-security/playwright-e2e-tester" ~/.claude/skills/diegosouzapw-awesome-omni-skill-playwright-e2e-tester && rm -rf "$T"
manifest:
skills/testing-security/playwright-e2e-tester/SKILL.mdsource content
Playwright E2E Tester
Overview
Expert in end-to-end testing with Playwright, the modern cross-browser testing framework. Specializes in test generation, page object patterns, visual regression testing, and CI/CD integration. Handles complex testing scenarios including authentication flows, API mocking, and mobile emulation.
When to Use
- Setting up Playwright in a new or existing project
- Writing E2E tests for critical user flows
- Debugging flaky tests or test failures
- Implementing visual regression testing
- Configuring Playwright for CI/CD pipelines
- Migrating from Cypress, Selenium, or Puppeteer
- Testing authenticated flows with session management
- Cross-browser testing (Chromium, Firefox, WebKit)
Capabilities
Test Generation & Writing
- Generate Playwright tests from user stories or acceptance criteria
- Write tests using best practices (locators, assertions, waits)
- Implement Page Object Model (POM) patterns
- Create reusable test fixtures and utilities
- Handle dynamic content and race conditions
Configuration & Setup
- Configure
for different environmentsplaywright.config.ts - Set up projects for multiple browsers and viewports
- Configure base URL, timeouts, and retries
- Implement global setup/teardown for auth
- Set up test reporters (HTML, JSON, JUnit)
Advanced Patterns
- API mocking with
androute()fulfill() - Network interception and request validation
- Visual regression with
toHaveScreenshot() - Accessibility testing with
@axe-core/playwright - Mobile emulation and device testing
- Geolocation and permissions mocking
CI/CD Integration
- GitHub Actions workflow configuration
- Parallel test execution with sharding
- Artifact collection (traces, screenshots, videos)
- Flaky test detection and retry strategies
- Test result reporting and notifications
Debugging & Maintenance
- Use Playwright Inspector and Trace Viewer
- Debug with
and headed modepage.pause() - Analyze test traces for failures
- Reduce test flakiness with proper waits
- Maintain test stability over time
Dependencies
Works well with:
- Unit test patterns that complement E2Evitest-testing-patterns
- CI/CD pipeline setupgithub-actions-pipeline-builder
- Extended accessibility testingaccessibility-auditor
- API contract testing alongside E2Eapi-architect
Examples
Basic Test Structure
import { test, expect } from '@playwright/test'; test.describe('User Authentication', () => { test('should allow user to sign in', async ({ page }) => { await page.goto('/login'); await page.getByLabel('Email').fill('user@example.com'); await page.getByLabel('Password').fill('securepassword'); await page.getByRole('button', { name: 'Sign In' }).click(); await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible(); await expect(page).toHaveURL('/dashboard'); }); });
Page Object Pattern
// pages/LoginPage.ts import { Page, Locator } from '@playwright/test'; export class LoginPage { readonly page: Page; readonly emailInput: Locator; readonly passwordInput: Locator; readonly signInButton: Locator; constructor(page: Page) { this.page = page; this.emailInput = page.getByLabel('Email'); this.passwordInput = page.getByLabel('Password'); this.signInButton = page.getByRole('button', { name: 'Sign In' }); } async goto() { await this.page.goto('/login'); } async signIn(email: string, password: string) { await this.emailInput.fill(email); await this.passwordInput.fill(password); await this.signInButton.click(); } }
Auth Setup Fixture
// fixtures/auth.ts import { test as base } from '@playwright/test'; export const test = base.extend({ authenticatedPage: async ({ page }, use) => { // Perform authentication await page.goto('/login'); await page.getByLabel('Email').fill(process.env.TEST_USER!); await page.getByLabel('Password').fill(process.env.TEST_PASS!); await page.getByRole('button', { name: 'Sign In' }).click(); // Wait for auth to complete await page.waitForURL('/dashboard'); // Use the authenticated page in tests await use(page); }, });
GitHub Actions CI
name: E2E Tests on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - name: Install dependencies run: npm ci - name: Install Playwright browsers run: npx playwright install --with-deps - name: Run E2E tests run: npx playwright test - name: Upload test results if: always() uses: actions/upload-artifact@v4 with: name: playwright-report path: playwright-report/
Visual Regression Test
test('homepage matches snapshot', async ({ page }) => { await page.goto('/'); // Full page screenshot comparison await expect(page).toHaveScreenshot('homepage.png', { fullPage: true, maxDiffPixelRatio: 0.01, }); // Component-level screenshot const hero = page.getByTestId('hero-section'); await expect(hero).toHaveScreenshot('hero-section.png'); });
API Mocking
test('displays products from API', async ({ page }) => { // Mock the API response await page.route('**/api/products', async (route) => { await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify([ { id: 1, name: 'Product A', price: 29.99 }, { id: 2, name: 'Product B', price: 49.99 }, ]), }); }); await page.goto('/products'); await expect(page.getByText('Product A')).toBeVisible(); await expect(page.getByText('$29.99')).toBeVisible(); });
Best Practices
- Use role-based locators - Prefer
,getByRole()
,getByLabel()
over CSS selectorsgetByText() - Avoid hard waits - Use
,waitForSelector()
, or assertions instead ofwaitForURL()waitForTimeout() - Isolate tests - Each test should be independent and not rely on state from other tests
- Use fixtures - Share setup logic through fixtures rather than
hooksbeforeEach - Keep tests focused - Test one user flow per test, avoid testing multiple unrelated things
- Handle flakiness proactively - Use proper waits, retries, and stable locators
- Organize with Page Objects - Encapsulate page interactions for maintainability
- Run in CI - Always run E2E tests in CI before merging
Common Pitfalls
- Flaky locators: Avoid fragile selectors like
or auto-generated class namesnth-child(3) - Race conditions: Always wait for elements/navigation before interacting
- Shared state: Tests should not depend on execution order
- Slow tests: Use API calls to set up state instead of UI interactions when possible
- Missing cleanup: Clean up test data to avoid pollution between runs