Back to Skills

playwright-testing

verified

This skill should be used when user asks about "Playwright", "responsiveness test", "test with playwright", "test login flow", "file upload test", "handle authentication in tests", or "fix flaky tests".

View on GitHub

Marketplace

claude-settings

fcakyon/claude-codex-settings

Plugin

playwright-tools

development

Repository

fcakyon/claude-codex-settings
376stars

plugins/playwright-tools/skills/playwright-testing/SKILL.md

Last Verified

January 15, 2026

Install Skill

Select agents to install to:

Scope:
npx add-skill https://github.com/fcakyon/claude-codex-settings/blob/main/plugins/playwright-tools/skills/playwright-testing/SKILL.md -a claude-code --skill playwright-testing

Installation paths:

Claude
.claude/skills/playwright-testing/
Powered by add-skill CLI

Instructions

# Playwright Testing Best Practices

## Test Organization

### File Structure

```
tests/
├── auth/
│   ├── login.spec.ts
│   └── signup.spec.ts
├── dashboard/
│   └── dashboard.spec.ts
├── fixtures/
│   └── test-data.ts
├── pages/
│   └── login.page.ts
└── playwright.config.ts
```

### Naming Conventions

- Files: `feature-name.spec.ts`
- Tests: Describe user behavior, not implementation
- Good: `test('user can reset password via email')`
- Bad: `test('test reset password')`

## Page Object Model

### Basic Pattern

```typescript
// pages/login.page.ts
export class LoginPage {
  constructor(private page: Page) {}

  async goto() {
    await this.page.goto("/login");
  }

  async login(email: string, password: string) {
    await this.page.getByLabel("Email").fill(email);
    await this.page.getByLabel("Password").fill(password);
    await this.page.getByRole("button", { name: "Sign in" }).click();
  }
}

// tests/login.spec.ts
test("successful login", async ({ page }) => {
  const loginPage = new LoginPage(page);
  await loginPage.goto();
  await loginPage.login("user@example.com", "password");
  await expect(page).toHaveURL("/dashboard");
});
```

## Locator Strategies

### Priority Order (Best to Worst)

1. **`getByRole`** - Accessible, resilient
2. **`getByLabel`** - Form inputs
3. **`getByPlaceholder`** - When no label
4. **`getByText`** - Visible text
5. **`getByTestId`** - When no better option
6. **CSS/XPath** - Last resort

### Examples

```typescript
// Preferred
await page.getByRole("button", { name: "Submit" }).click();
await page.getByLabel("Email address").fill("user@example.com");

// Acceptable
await page.getByTestId("submit-button").click();

// Avoid
await page.locator("#submit-btn").click();
await page.locator('//button[@type="submit"]').click();
```

## Authentication Handling

### Storage State (Recommended)

Save logged-in state and reuse across tests:

```typescript
// global-setup.ts
async function globalSetup() {
  const browser = await chro

Validation Details

Front Matter
Required Fields
Valid Name Format
Valid Description
Has Sections
Allowed Tools
Instruction Length:
6885 chars