Skip to main content

playwright-testing

Playwright end-to-end testing for web applications. Cross-browser testing (Chromium, Firefox, WebKit), visual regression, API testing, mobile emulation. Use when writing E2E tests, testing across browsers, or setting up automated UI testing workflows.

Jump to install

Source facts

Repository
laurigates/CleanScope
Last source activity
December 21, 2025 at 14:28
Detected SKILL.md language
English
Stars
1
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
created
2025-12-16T00:00:00.000Z
modified
2025-12-16T00:00:00.000Z
reviewed
2025-12-16T00:00:00.000Z
name
Playwright Testing
description
Playwright end-to-end testing for web applications. Cross-browser testing (Chromium, Firefox, WebKit), visual regression, API testing, mobile emulation. Use when writing E2E tests, testing across browsers, or setting up automated UI testing workflows.
allowed-tools
Glob, Grep, Read, Bash, Edit, Write, TodoWrite, WebFetch, WebSearch, BashOutput, KillShell
# Playwright Testing Playwright is a modern end-to-end testing framework for web applications. It provides reliable, fast, and cross-browser testing with excellent developer experience. ## Core Expertise **What is Playwright?** - **Cross-browser**: Test on Chromium, Firefox, WebKit (Safari) - **Reliable**: Auto-wait, auto-retry, no flaky tests - **Fast**: Parallel execution, browser context isolation - **Modern**: TypeScript-first, async/await, auto-complete - **Multi-platform**: Windows, macOS, Linux **Key Capabilities** - End-to-end UI testing - API testing (REST, GraphQL) - Visual regression testing - Mobile emulation - Network interception and mocking - Authentication state management - Parallel test execution - Video and screenshot capture - Trace viewer for debugging ## Installation ```bash # Initialize Playwright (recommended) bun create playwright # Or install manually bun add --dev @playwright/test # Install browsers bunx playwright install # Install with system dependencies (Linux) bunx playwright install --with-deps # Verify installation bunx playwright --version ``` ## Configuration (playwright.config.ts) ### Minimal Setup ```typescript // playwright.config.ts import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: './tests', timeout: 30000, use: { baseURL: 'http://localhost:3000', trace: 'on-first-retry', }, projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] }, }, ], }); ``` ### Recommended Production Setup ```typescript // playwright.config.ts import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: './tests', fullyParallel: true, forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 1 : undefined, reporter: [ ['html'], ['json', { outputFile: 'test-results/results.json' }], ['junit', { outputFile: 'test-results/junit.xml' }], ], timeout: 30000, expect: { timeout: 5000, }, use: { baseURL: process.env.BASE_URL || 'http://localhost:3000', trace: 'on-first-retry', screenshot: 'only-on-failure', video: 'retain-on-failure', actionTimeout: 10000, navigationTimeout: 30000, }, projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] }, }, { name: 'firefox', use: { ...devices['Desktop Firefox'] }, }, { name: 'webkit', use: { ...devices['Desktop Safari'] }, }, { name: 'mobile-chrome', use: { ...devices['Pixel 5'] }, }, { name: 'mobile-safari', use: { ...devices['iPhone 13'] }, }, ], webServer: { command: 'bun run dev', url: 'http://localhost:3000', reuseExistingServer: !process.env.CI, timeout: 120000, }, }); ``` ## Essential Commands ```bash # Run all tests bunx playwright test # Run specific test file bunx playwright test tests/login.spec.ts # Run tests in headed mode (see browser) bunx playwright test --headed # Run tests in debug mode bunx playwright test --debug # Run specific project (browser) bunx playwright test --project=chromium # Run tests in UI mode bunx playwright test --ui # Generate tests (record interactions) bunx playwright codegen http://localhost:3000 # Open last test report bunx playwright show-report # Open trace viewer bunx playwright show-trace trace.zip # Update snapshots bunx playwright test --update-snapshots ``` ## Writing Tests ### Basic Test Structure ```typescript // tests/example.spec.ts import { test, expect } from '@playwright/test'; test('basic test', async ({ page }) => { await page.goto('https://example.com'); await expect(page).toHaveTitle(/Example/); }); test.describe('login flow', () => { test('should login successfully', async ({ page }) => { await page.goto('/login'); await page.fill('input[name="email"]', 'user@example.com'); await page.fill('input[name="password"]', 'password123'); await page.click('button[type="submit"]'); await expect(page).toHaveURL('/dashboard'); }); }); ``` ### Selectors and Locators ```typescript import { test, expect } from '@playwright/test'; test('selectors', async ({ page }) => { await page.goto('/'); // Text selector (recommended) await page.getByText('Sign in').click(); await page.getByRole('button', { name: 'Submit' }).click(); // Label selector await page.getByLabel('Email').fill('user@example.com'); // Placeholder selector await page.getByPlaceholder('Enter your name').fill('John'); // Test ID selector await page.getByTestId('login-button').click(); // CSS selector await page.locator('.button-primary').click(); // XPath selector await page.locator('xpath=//button[text()="Submit"]').click(); // Chaining selectors await page .locator('.card') .filter({ hasText: 'Product' }) .getByRole('button') .click(); }); ``` ### Assertions ```typescript import { test, expect } from '@playwright/test'; test('assertions', async ({ page }) => { await page.goto('/'); // Page assertions await expect(page).toHaveTitle('My App'); await expect(page).toHaveURL(/dashboard/); // Element assertions const button = page.getByRole('button'); await expect(button).toBeVisible(); await expect(button).toBeEnabled(); await expect(button).toHaveText('Submit'); await expect(button).toContainText('Sub'); await expect(button).toHaveAttribute('type', 'submit'); await expect(button).toHaveClass(/btn-primary/); // Input assertions const input = page.getByLabel('Email'); await expect(input).toHaveValue('user@example.com'); await expect(input).toBeEmpty(); // Count assertions await expect(page.locator('.item')).toHaveCount(5); // Negation await expect(button).not.toBeDisabled(); }); ``` ### Page Object Model ```typescript // page-objects/login-page.ts import { Page, Locator } from '@playwright/test'; export class LoginPage { readonly page: Page; readonly emailInput: Locator; readonly passwordInput: Locator; readonly submitButton: 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' }); } async goto() { await this.page.goto('/login'); } async login(email: string, password: string) { await this.emailInput.fill(email); await this.passwordInput.fill(password); await this.submitButton.click(); } } // tests/login.spec.ts import { test, expect } from '@playwright/test'; import { LoginPage } from '../page-objects/login-page'; test('login with page object', async ({ page }) => { const loginPage = new LoginPage(page); await loginPage.goto(); await loginPage.login('user@example.com', 'password123'); await expect(page).toHaveURL('/dashboard'); }); ``` ## Fixtures ### Built-in Fixtures ```typescript import { test } from '@playwright/test'; test('built-in fixtures', async ({ page, context, browser }) => { // page - isolated browser page await page.goto('/'); // context - browser context (cookies, storage) await context.clearCookies(); // browser - browser instance const newPage = await browser.newPage(); }); ``` ### Custom Fixtures ```typescript // fixtures/auth-fixture.ts import { test as base } from '@playwright/test'; import { LoginPage } from '../page-objects/login-page'; type AuthFixtures = { authenticatedPage: Page; }; export const test = base.extend<AuthFixtures>({ authenticatedPage: async ({ page }, use) => { const loginPage = new LoginPage(page); await loginPage.goto(); await loginPage.login('user@example.com', 'password123'); await use(page); }, }); // tests/dashboard.spec.ts import { test } from '../fixtures/auth-fixture'; test('access dashboard', async ({ authenticatedPage }) => { await authenticatedPage.goto('/dashboard'); // User is already logged in }); ``` ## Authentication State ### Save Authentication State ```typescript // tests/auth.setup.ts import { test as setup } from '@playwright/test'; const authFile = 'playwright/.auth/user.json'; setup('authenticate', async ({ page }) => { await page.goto('/login'); await page.getByLabel('Email').fill('user@example.com'); await page.getByLabel('Password').fill('password123'); await page.getByRole('button', { name: 'Sign in' }).click(); await page.waitForURL('/dashboard'); await page.context().storageState({ path: authFile }); }); ``` ### Use Saved State ```typescript // playwright.config.ts export default defineConfig({ projects: [ { name: 'setup', testMatch: /.*\.setup\.ts/ }, { name: 'chromium', use: { ...devices['Desktop Chrome'], storageState: 'playwright/.auth/user.json', }, dependencies: ['setup'], }, ], }); ``` ## API Testing ```typescript import { test, expect } from '@playwright/test'; test('api testing', async ({ request }) => { // GET request const response = await request.get('https://api.example.com/users'); expect(response.ok()).toBeTruthy(); expect(response.status()).toBe(200); const users = await response.json(); expect(users).toHaveLength(10); // POST request const createResponse = await request.post('https://api.example.com/users', { data: { name: 'John Doe', email: 'john@example.com', }, });
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub