Playwright Scripts

Basic Navigation & Interaction

import { test, expect } from '@playwright/test'; test('login flow', async ({ page }) => { // Navigation await page.goto('https://example.com/login'); await page.goto('https://example.com', { waitUntil: 'networkidle' }); // Filling forms await page.fill('#email', '[email protected]'); await page.fill('[name="password"]', 'secret123'); await page.selectOption('select#role', 'admin'); await page.check('#rememberMe'); await page.uncheck('#newsletter'); // Clicking await page.click('button[type="submit"]'); await page.dblclick('.item'); await page.rightClick('.context-menu-trigger'); await page.click('text=Sign In'); // Keyboard await page.keyboard.press('Enter'); await page.keyboard.type('Hello World', { delay: 50 }); await page.keyboard.press('Control+A'); // Hover and focus await page.hover('.tooltip-trigger'); await page.focus('input[name="search"]'); });

Selectors

// CSS selectors page.locator('#submit-btn'); page.locator('.btn.btn-primary'); page.locator('input[type="email"]'); // Text content page.locator('text=Submit'); page.locator('button:has-text("Sign In")'); page.getByText('Welcome back'); // ARIA roles (recommended) page.getByRole('button', { name: 'Submit' }); page.getByRole('textbox', { name: 'Email' }); page.getByRole('heading', { level: 1 }); page.getByLabel('Password'); page.getByPlaceholder('Enter your email'); page.getByTestId('submit-button'); // data-testid attribute // XPath page.locator('xpath=//button[@type="submit"]'); // Chaining / filtering page.locator('.card').filter({ hasText: 'Alice' }); page.locator('li').nth(2); page.locator('.row').first(); page.locator('.row').last();

Waiting Strategies

// Auto-waiting โ€” Playwright waits automatically for most actions await page.click('#submit'); // waits for element to be clickable // Wait for specific state await page.waitForSelector('.modal', { state: 'visible' }); await page.waitForSelector('#loading', { state: 'hidden' }); await page.waitForSelector('.result', { timeout: 10000 }); // Wait for URL await page.waitForURL('**/dashboard'); await page.waitForURL(/dashboard/, { waitUntil: 'networkidle' }); // Wait for network await page.waitForResponse('**/api/users'); await page.waitForRequest(req => req.url().includes('/search')); // Wait for load state await page.waitForLoadState('networkidle'); await page.waitForLoadState('domcontentloaded'); // Wait for function await page.waitForFunction(() => window.appReady === true); // Expect auto-waits await expect(page.locator('.success')).toBeVisible({ timeout: 5000 }); await expect(page.locator('#count')).toHaveText('3');

Screenshots & Video Recording

// Manual screenshot await page.screenshot({ path: 'screenshot.png' }); await page.screenshot({ path: 'full.png', fullPage: true }); await page.locator('.chart').screenshot({ path: 'chart.png' }); // playwright.config.ts โ€” automatic on failure export default { use: { screenshot: 'only-on-failure', // or 'on', 'off' video: 'retain-on-failure', // or 'on', 'off', 'on-first-retry' trace: 'on-first-retry', // .zip with timeline, DOM, network }, }; // View trace // npx playwright show-trace trace.zip // Per-test override test('with recording', async ({ page }, testInfo) => { await page.goto('/'); // Attach to test report await testInfo.attach('screenshot', { body: await page.screenshot(), contentType: 'image/png', }); });

Test Fixtures

// fixtures.ts โ€” extend base test import { test as base, expect } from '@playwright/test'; type Fixtures = { loggedInPage: Page; adminUser: { email: string; token: string }; }; export const test = base.extend<Fixtures>({ adminUser: async ({}, use) => { const user = await createTestUser({ role: 'admin' }); await use(user); await deleteTestUser(user.id); }, loggedInPage: async ({ page, adminUser }, use) => { await page.goto('/login'); await page.fill('#email', adminUser.email); await page.fill('#password', 'testpass'); await page.click('[type="submit"]'); await page.waitForURL('**/dashboard'); await use(page); }, }); export { expect }; // usage in tests: import { test, expect } from './fixtures'; test('admin can see users', async ({ loggedInPage }) => { await loggedInPage.goto('/admin/users'); await expect(loggedInPage.getByRole('table')).toBeVisible(); });

playwright.config.ts Overview

import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: './tests', timeout: 30_000, retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 1 : undefined, reporter: [['html'], ['junit', { outputFile: 'results.xml' }]], use: { baseURL: 'http://localhost:3000', headless: true, viewport: { width: 1280, height: 720 }, screenshot: 'only-on-failure', video: 'retain-on-failure', trace: 'on-first-retry', }, projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] } }, { name: 'firefox', use: { ...devices['Desktop Firefox'] } }, { name: 'webkit', use: { ...devices['Desktop Safari'] } }, { name: 'mobile', use: { ...devices['iPhone 13'] } }, ], });