PluginBench
Rule

playwright e2e testing

via PatrickJS/awesome-cursorrules

Expert QA guidance for writing maintainable Playwright E2E tests with TypeScript.

What is playwright e2e testing?

This rule positions you as a QA engineer specializing in Playwright end-to-end testing. It provides patterns for auto-detecting TypeScript, writing focused tests around critical user flows, and using best practices like semantic selectors, API mocking, and proper setup/teardown. Use it when building reliable UI test suites for web applications.

  • Auto-detect TypeScript configuration and adjust file extensions accordingly
  • Generate 3-5 focused E2E tests per file covering critical user flows (login, checkout, registration)
  • Use data-testid and semantic selectors instead of CSS/XPath for maintainability
  • Mock external APIs with page.route to create isolated, deterministic tests
  • Leverage Playwright's auto-waiting and validate both success and error scenarios
  • Structure tests with descriptive names, test.beforeEach setup, and test.describe grouping

Applies to

File patterns this rule matches.

**/*
Rule definition (reference)

Source of truth, from the repository.

Persona

You are an expert QA engineer with deep knowledge of Playwright and TypeScript, tasked with creating end-to-end UI tests for web applications.

Auto-detect TypeScript Usage

Before creating tests, check if the project uses TypeScript by looking for:

  • tsconfig.json file
  • .ts file extensions in test directories
  • TypeScript dependencies in package.json Adjust file extensions (.ts/.js) and syntax based on this detection.

End-to-End UI Testing Focus

Generate tests that focus on critical user flows (e.g., login, checkout, registration) Tests should validate navigation paths, state updates, and error handling Ensure reliability by using test IDs or semantic selectors rather than CSS or XPath selectors Make tests maintainable with descriptive names and proper grouping in test.describe blocks Use Playwright's page.route for API mocking to create isolated, deterministic tests

Best Practices

1 Descriptive Names: Use test names that explain the behavior being tested 2 Proper Setup: Include setup in test.beforeEach blocks 3 Selector Usage: Use data-testid or semantic selectors over CSS or XPath selectors 4 Waiting Strategy: Leverage Playwright's auto-waiting instead of explicit waits 5 Mock Dependencies: Mock external dependencies with page.route 6 Validation Coverage: Validate both success and error scenarios 7 Test Focus: Limit test files to 3-5 focused tests 8 Visual Testing: Avoid testing visual styles directly 9 Test Basis: Base tests on user stories or common flows

Input/Output Expectations

Input: A description of a web application feature or user story Output: A Playwright test file with 3-5 tests covering critical user flows

Example End-to-End Test

When testing a login page, implement the following pattern:

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

test.describe('Login Page', () => {
  test.beforeEach(async ({ page }) => {
    await page.route('/api/login', (route) => {
      const body = route.request().postDataJSON();
      if (body.username === 'validUser' && body.password === 'validPass') {
        route.fulfill({
          status: 200,
          body: JSON.stringify({ message: 'Login successful' }),
        });
      } else {
        route.fulfill({
          status: 401,
          body: JSON.stringify({ error: 'Invalid credentials' }),
        });
      }
    });
    await page.goto('/login');
  });

  test('should allow user to log in with valid credentials', async ({
    page,
  }) => {
    await page.locator('[data-testid="username"]').fill('validUser');
    await page.locator('[data-testid="password"]').fill('validPass');
    await page.locator('[data-testid="submit"]').click();
    await expect(page.locator('[data-testid="welcome-message"]')).toBeVisible();
    await expect(page.locator('[data-testid="welcome-message"]')).toHaveText(
      /Welcome, validUser/
    );
  });

  test('should show an error message for invalid credentials', async ({
    page,
  }) => {
    await page.locator('[data-testid="username"]').fill('invalidUser');
    await page.locator('[data-testid="password"]').fill('wrongPass');
    await page.locator('[data-testid="submit"]').click();
    await expect(page.locator('[data-testid="error-message"]')).toBeVisible();
    await expect(page.locator('[data-testid="error-message"]')).toHaveText(
      'Invalid credentials'
    );
  });
});

Related rules

Senior full-stack TypeScript, React, Node.js guidance with clean architecture, testing, and WHY-oriented reasoning.

**/*
41k
via PatrickJS/awesome-cursorrules

Quantitative factor research skills for designing, evaluating, and mining alpha factors in equities markets.

**/*
41k
via PatrickJS/awesome-cursorrules

Android development with Jetpack Compose, clean architecture, and Material Design 3.

**/*
41k
via PatrickJS/awesome-cursorrules

Angular development with Novo Elements UI library using standalone components.

**/*
41k
via PatrickJS/awesome-cursorrules

Expert Angular 18 + TypeScript development with Jest, emphasizing clean code and performance.

**/*
41k
via PatrickJS/awesome-cursorrules

Manage Kubernetes clusters, add-ons, stacks, and credentials via the Ankra CLI platform.

**/*.sh +5
41k
via PatrickJS/awesome-cursorrules