playwright

- Writing E2E tests with Playwright

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "playwright" with this command: npx skills add poletron/custom-rules/poletron-custom-rules-playwright

When to Use

Use this skill when:

  • Writing E2E tests with Playwright

  • Creating Page Object Models

  • Setting up selectors and assertions

  • Using MCP for test exploration

MCP Workflow (MANDATORY If Available)

⚠️ If you have Playwright MCP tools, ALWAYS use them BEFORE creating any test:

  • Navigate to target page

  • Take snapshot to see page structure and elements

  • Interact with forms/elements to verify exact user flow

  • Take screenshots to document expected states

  • Verify page transitions through complete flow

  • Document actual selectors from snapshots

  • Only after exploring create test code with verified selectors

Why This Matters:

  • ✅ Precise tests - exact steps needed, no assumptions

  • ✅ Accurate selectors - real DOM structure

  • ✅ Real flow validation

  • ✅ Avoid over-engineering

  • ✅ Prevent flaky tests

Critical Patterns

File Structure (REQUIRED)

tests/ ├── base-page.ts # Parent class for ALL pages ├── helpers.ts # Shared utilities └── {page-name}/ ├── {page-name}-page.ts # Page Object Model ├── {page-name}.spec.ts # ALL tests here (NO separate files!) └── {page-name}.md # Test documentation

File Naming:

  • ✅ sign-up.spec.ts (all sign-up tests)

  • ❌ sign-up-critical-path.spec.ts (WRONG - no separate files)

Selector Priority (REQUIRED)

// 1. BEST - getByRole for interactive elements this.submitButton = page.getByRole("button", { name: "Submit" }); this.navLink = page.getByRole("link", { name: "Dashboard" });

// 2. BEST - getByLabel for form controls this.emailInput = page.getByLabel("Email"); this.passwordInput = page.getByLabel("Password");

// 3. SPARINGLY - getByText for static content only this.errorMessage = page.getByText("Invalid credentials");

// 4. LAST RESORT - getByTestId when above fail this.customWidget = page.getByTestId("date-picker");

// ❌ AVOID fragile selectors this.button = page.locator(".btn-primary"); // NO this.input = page.locator("#email"); // NO

Page Object Pattern (REQUIRED)

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

// BasePage - ALL pages extend this export class BasePage { constructor(protected page: Page) {}

async goto(path: string): Promise<void> { await this.page.goto(path); await this.page.waitForLoadState("networkidle"); }

async waitForNotification(): Promise<void> { await this.page.waitForSelector('[role="status"]'); } }

// Page-specific implementation export interface LoginData { email: string; password: string; }

export class LoginPage extends BasePage { readonly emailInput: Locator; readonly passwordInput: Locator; readonly submitButton: Locator;

constructor(page: Page) { super(page); this.emailInput = page.getByLabel("Email"); this.passwordInput = page.getByLabel("Password"); this.submitButton = page.getByRole("button", { name: "Sign in" }); }

async goto(): Promise<void> { await super.goto("/login"); }

async login(data: LoginData): Promise<void> { await this.emailInput.fill(data.email); await this.passwordInput.fill(data.password); await this.submitButton.click(); } }

Decision Tree

Need to click? → Use getByRole or getByTestId Need to type? → Use getByLabel + fill() Need to assert? → Use expect() with locator Need to wait? → Auto-wait is built-in Need reusable logic? → Create Page Object Need shared utilities? → Add to helpers.ts

Scope Detection (ASK IF AMBIGUOUS)

User Says Action

"a test", "one test", "new test" Create ONE test() in existing spec

"comprehensive tests", "all tests", "test suite" Create full suite

Code Examples

Test Pattern with Tags

import { test, expect } from "@playwright/test"; import { LoginPage } from "./login-page";

test.describe("Login", () => { test("User can login successfully", { tag: ["@critical", "@e2e", "@login", "@LOGIN-E2E-001"] }, async ({ page }) => { const loginPage = new LoginPage(page); await loginPage.goto(); await loginPage.login({ email: "user@test.com", password: "pass123" }); await expect(page).toHaveURL("/dashboard"); } ); });

Page Object Reuse

// ✅ GOOD: Reuse existing page objects import { SignInPage } from "../sign-in/sign-in-page"; import { HomePage } from "../home/home-page";

test("User can sign up and login", async ({ page }) => { const signUpPage = new SignUpPage(page); const signInPage = new SignInPage(page); // REUSE const homePage = new HomePage(page); // REUSE

await signUpPage.signUp(userData); await homePage.signOut(); await signInPage.login(credentials); });

Refactoring to BasePage

// Move to BasePage when used by multiple pages: export class BasePage { async waitForNotification(): Promise<void> { await this.page.waitForSelector('[role="status"]'); } }

// Move to helpers.ts for test data: export function generateUniqueEmail(): string { return test.${Date.now()}@example.com; }

Commands

npx playwright test # Run all npx playwright test --grep "login" # Filter by name npx playwright test --ui # Interactive UI npx playwright test --debug # Debug mode npx playwright codegen # Generate tests npx playwright show-report # View report

Test Documentation Format

E2E Tests: {Feature Name}

Suite ID: {SUITE-ID} Priority: {critical|high|medium|low}

Tags: @e2e, @{feature-name}

Preconditions:

  • {Prerequisites}

Flow Steps:

  1. {Step 1}
  2. {Step 2}

Expected Result:

  • {Expected outcome}

Resources

  • Best Practices: best-practices.md

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

lancedb

No summary provided by upstream source.

Repository SourceNeeds Review
General

git-flow

No summary provided by upstream source.

Repository SourceNeeds Review
General

javascript-mastery

No summary provided by upstream source.

Repository SourceNeeds Review
General

coding-standards

No summary provided by upstream source.

Repository SourceNeeds Review