Agent skill

playwright-testing

Expert guidance for writing end-to-end tests with Playwright Test framework. Use this skill when writing browser automation tests, creating test suites, working with locators and assertions, mocking network requests, handling authentication, or configuring the Playwright test runner. Trigger keywords include "playwright", "e2e test", "end-to-end", "browser test", "getByRole", "locator", "toBeVisible", "page.goto", "test runner".

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/playwright-testing-aehrc-pathling

SKILL.md

Playwright Testing

End-to-end testing framework with auto-waiting, web-first assertions, and multi-browser support.

Quick Start

typescript
import { test, expect } from "@playwright/test";

test("user can log in", async ({ page }) => {
    await page.goto("/login");
    await page.getByLabel("Email").fill("[email protected]");
    await page.getByLabel("Password").fill("secret");
    await page.getByRole("button", { name: "Sign in" }).click();
    await expect(page.getByText("Welcome")).toBeVisible();
});

Core Concepts

Locators (Priority Order)

  1. page.getByRole('button', { name: 'Submit' }) — ARIA roles (most resilient)
  2. page.getByLabel('Email') — Form labels
  3. page.getByText('Welcome') — Visible text
  4. page.getByTestId('user-menu') — Test IDs (explicit contracts)
  5. page.getByPlaceholder('Search') — Placeholder text

Avoid CSS selectors and XPath—they break with DOM changes.

Chaining and filtering:

typescript
// Chain to narrow scope
page.locator(".modal").getByRole("button", { name: "Save" });

// Filter by text or child elements
page.getByRole("listitem").filter({ hasText: "Product" });
page.getByRole("listitem").filter({ has: page.getByRole("button") });

See references/locators.md for complete locator API.

Assertions

Auto-retrying (use these for web elements):

typescript
await expect(locator).toBeVisible();
await expect(locator).toHaveText("Hello");
await expect(locator).toHaveValue("input text");
await expect(locator).toBeChecked();
await expect(page).toHaveURL(/dashboard/);

Non-retrying (for static values):

typescript
expect(value).toBe(5);
expect(array).toContain("item");
expect(obj).toEqual({ key: "value" });

See references/assertions.md for all assertion types.

Actions

typescript
await locator.click();
await locator.fill("text"); // Clear and type
await locator.pressSequentially("t"); // Character by character
await locator.selectOption("value");
await locator.check(); // Checkbox
await locator.setInputFiles("file.pdf");
await page.keyboard.press("Enter");

All actions auto-wait for elements to be visible, stable, and enabled.

See references/actions.md for complete action reference.

Test Structure

typescript
import { test, expect } from "@playwright/test";

test.describe("Feature", () => {
    test.beforeEach(async ({ page }) => {
        await page.goto("/");
    });

    test("scenario one", async ({ page }) => {
        // Arrange - Act - Assert
    });

    test("scenario two", async ({ page }) => {
        // ...
    });
});

Hooks

  • test.beforeEach() / test.afterEach() — Run before/after each test
  • test.beforeAll() / test.afterAll() — Run once per worker

Configuration

Minimal playwright.config.ts:

typescript
import { defineConfig, devices } from "@playwright/test";

export default defineConfig({
    testDir: "./tests",
    fullyParallel: true,
    retries: process.env.CI ? 2 : 0,
    workers: process.env.CI ? 2 : undefined,
    reporter: "html",
    use: {
        baseURL: "http://localhost:3000",
        trace: "on-first-retry",
    },
    projects: [
        { name: "chromium", use: { ...devices["Desktop Chrome"] } },
        { name: "firefox", use: { ...devices["Desktop Firefox"] } },
        { name: "webkit", use: { ...devices["Desktop Safari"] } },
    ],
    webServer: {
        command: "npm run dev",
        url: "http://localhost:3000",
        reuseExistingServer: !process.env.CI,
    },
});

See references/configuration.md for all options.

CLI Commands

bash
npx playwright test                    # Run all tests
npx playwright test --ui               # Interactive UI mode
npx playwright test --headed           # Show browser
npx playwright test --debug            # Step-through debugger
npx playwright test -g "login"         # Filter by title
npx playwright test --project=chromium # Specific browser
npx playwright test --last-failed      # Retry failures only
npx playwright codegen                 # Generate tests
npx playwright show-report             # View HTML report

Advanced Features

Network Mocking

typescript
await page.route("**/api/users", (route) =>
    route.fulfill({ json: [{ id: 1, name: "Mock User" }] }),
);

await page.route("**/api/error", (route) => route.fulfill({ status: 500 }));

Authentication State

typescript
// Save auth state after login
await page.context().storageState({ path: "auth.json" });

// Reuse in config
use: {
    storageState: "auth.json";
}

Fixtures

typescript
const test = base.extend<{ userPage: Page }>({
    userPage: async ({ browser }, use) => {
        const context = await browser.newContext();
        const page = await context.newPage();
        await page.goto("/login");
        // ... login
        await use(page);
        await context.close();
    },
});

See references/advanced.md for network mocking, auth patterns, fixtures, and Page Object Model.

Best Practices

  1. Use role-based locatorsgetByRole() is most resilient to changes
  2. Prefer auto-retrying assertionsawait expect(locator).toBeVisible() not locator.isVisible()
  3. Keep tests isolated — Each test gets fresh browser context
  4. Avoid hardcoded waits — Playwright auto-waits; use explicit waits only for custom conditions
  5. Test user behaviour — Focus on what users see, not implementation details
  6. Use soft assertions sparinglyexpect.soft() continues after failure for comprehensive reports

Expand your agent's capabilities with these related and highly-rated skills.

Didn't find tool you were looking for?

Be as detailed as possible for better results