Receber por email
← Voltar para o catálogo

playwright-testing

Automatically activated when user works with Playwright tests, mentions Playwright configuration, asks about selectors/locators/page objects, or has files matching *.spec.ts in e2e or tests directories. Provides Playwright-specific expertise for E2E and integration testing.

367estrelas
Atualizado há 4 meses

Ver no GitHub ↗

Como adicionar

/plugin marketplace add aiskillstore/marketplace

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/playwright-testing/svg)](https://www.skillteca.com.br/skills/playwright-testing)

Skills relacionadas

Ver todas de Segurança →

Alerta por categoria

Receba novas skills de Segurança toda segunda

1 email curto, só com as skills novas de Segurança. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

Playwright Testing Expertise

You are an expert in Playwright testing framework with deep knowledge of browser automation, selectors, page objects, and best practices for end-to-end testing.

Your Capabilities

  1. Playwright Configuration: Projects, browsers, reporters, and fixtures
  2. Locators & Selectors: Role-based, text, CSS, and chained locators
  3. Page Object Model: Organizing tests with page objects
  4. Assertions: Built-in assertions, custom matchers, auto-waiting
  5. Test Fixtures: Built-in and custom fixtures, test isolation
  6. Debugging: Traces, screenshots, videos, and Playwright Inspector
  7. API Testing: Request fixtures and API testing capabilities

When to Use This Skill

Claude should automatically invoke this skill when:

  • The user mentions Playwright, playwright.config, or Playwright features
  • Files matching *.spec.ts in e2e, tests, or playwright directories are encountered
  • The user asks about locators, page objects, or browser automation
  • E2E or integration testing is discussed
  • Browser testing configuration is needed

How to Use This Skill

Accessing Resources

Use {baseDir} to reference files in this skill directory:

  • Scripts: {baseDir}/scripts/
  • Documentation: {baseDir}/references/
  • Templates: {baseDir}/assets/

Available Resources

This skill includes ready-to-use resources in {baseDir}:

  • references/playwright-cheatsheet.md - Quick reference for locators, assertions, actions, and CLI commands
  • assets/page-object.template.ts - Complete Page Object Model template with base class and examples
  • scripts/check-playwright-setup.sh - Validates Playwright configuration and browser installation

Playwright Best Practices

Test Structure

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

test.describe('Contact Form', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/contact');
  });

  test('should show success message after form submission', async ({ page }) => {
    // Arrange
    await page.getByLabel('Name').fill('Test User');
    await page.getByLabel('Email').fill('test@example.com');
    await page.getByLabel('Message').fill('Hello, this is a test message.');

    // Act
    await page.getByRole('button', { name: 'Submit' }).click();

    // Assert
    await expect(page.getByText('Thank you for your message')).toBeVisible();
    await expect(page.getByLabel('Name')).toBeEmpty();
  });
});

Locator Best Practices

Preferred Locators (Most Resilient)

// Role-based (best)
page.getByRole('button', { name: 'Submit' });
page.getByRole('textbox', { name: 'Email' });
page.getByRole('heading', { level: 1 });

// Label-based
page.getByLabel('Email address');
page.getByPlaceholder('Enter your email');

// Text-based
page.getByText('Welcome');
page.getByTitle('Close');

Chaining Locators

page.getByRole('listitem')
  .filter({ hasText: 'Product 1' })
  .getByRole('button', { name: 'Add' });

Test IDs (Last Resort)

page.getByTestId('submit-button');

Page Object Pattern

// pages/login.page.ts
import { Page, Locator, expect } from '@playwright/test';

export class LoginPage {
  private readonly page: Page;
  readonly emailInput: Locator;
  readonly passwordInput: Locator;
  readonly submitButton: Locator;
  readonly errorMessage: Locator;

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

  async goto() {
    await this.page.goto('/login');
    await expect(this.emailInput).toBeVisible();
  }

  async login(email: string, password: string) {
    await this.emailInput.fill(email);
    await this.passwordInput.fill(password);
    await this.submitButton.click();
  }

  async getError(): Promise<string | null> {
    if (await this.errorMessage.isVisible()) {
      return this.errorMessage.textContent();
    }
    return null;
  }
}

// Usage in test
import { test, expect } from '@playwright/test';
import { LoginPage } from './pages/login.page';

test('should login successfully', async ({ page }) => {
  const loginPage = new LoginPage(page);
  await loginPage.goto();
  await loginPage.login('user@test.com', 'password');
  await expect(page).toHaveURL('/dashboard');
});

test('should show error for invalid credentials', async ({ page }) => {
  const loginPage = new LoginPage(page);
  await loginPage.goto();
  await loginPage.login('invalid@test.com', 'wrongpassword');
  const error = await loginPage.getError();
  expect(error).toContain('Invalid credentials');
});

Auto-Waiting & Assertions

// Auto-waits for element
await expect(page.getByRole('alert')).toBeVisible();
await expect(page.getByRole('button')).toBeEnabled();
await expect(page.getByText('Count: 5')).toBeVisible();

// Negative assertions
await expect(page.getByRole('dialog')).toBeHidden();
await expect(page.getByText('Error')).not.toBeVisible();

// With custom timeout
await expect(page.getByText('Loaded')).toBeVisible({ timeout: 10000 });

Fixtures

// fixtures.ts
import { test as base } from '@playwright/test';

export const test = base.extend<{
  authenticatedPage: Page;
}>({
  authenticatedPage: async ({ page }, use) => {
    await page.goto('/login');
    await page.getByLabel('Email').fill('test@test.com');
    await page.getByLabel('Password').fill('password');
    await page.getByRole('button', { name: 'Login' }).click();
    await page.waitForURL('/dashboard');
    await use(page);
  },
});

Storage State Authentication

For efficient authentication without UI login each time:

// Setup: Save auth state after login (run once)
// auth.setup.ts
import { test as setup, expect } from '@playwright/test';

setup('authenticate', async ({ page }) => {
  await page.goto('/login');
  await page.getByLabel('Email').fill('test@example.com');
  await page.getByLabel('Password').fill('password');
  await page.getByRole('button', { name: 'Sign in' }).click();
  await expect(page).toHaveURL('/dashboard');

  // Save storage state (cookies, localStorage)
  await page.context().storageState({ path: '.auth/user.json' });
});

// playwright.config.ts
export default defineConfig({
  projects: [
    { name: 'setup', testMatch: /.*\.setup\.ts/ },
    {
      name: 'chromium',
      use: { storageState: '.auth/user.json' },
      dependencies: ['setup'],
    },
  ],
});

// Tests automatically have auth state
test('dashboard loads for authenticated user', async ({ page }) => {
  await page.goto('/dashboard');
  await expect(page.getByText('Welcome back')).toBeVisible();
});

Network Mocking & Interception

Mock API responses for reliable, fast tests:

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

test('should display mocked user data', async ({ page }) => {
  // Mock API response
  await page.route('**/api/users', route => {
    route.fulfill({
      status: 200,
      contentType: 'application/json',
      body: JSON.stringify([
        { id: 1, name: 'Test User', email: 'test@example.com' }
      ]),
    });
  });

  await page.goto('/users');
  await expect(page.getByText('Test User')).toBeVisible();
});

test('should handle API errors gracefully', async ({ page }) => {
  // Mock error response
  await page.route('**/api/users', route => {
    route.fulfill({
      status: 500,
      body: JSON.stringify({ error: 'Internal Server Error' }),
    });
  });

  await page.goto('/users');
  await expect(page.getByText('Failed to load users')).toBeVisible();
});

test('should handle network failure', async ({ page }) => {
  // Abort network request
  await page.route('**/api/data', route => route.abort());

  await page.goto('/data');
  await expect(page.getByText('Network error')).
Compartilhar X LinkedIn