CLI Commands
npx playwright test # Run all tests
npx playwright test file.spec.ts # Run specific file
npx playwright test -g "login" # Filter by pattern
npx playwright test --headed # Show browser
npx playwright test --ui # UI mode
npx playwright test --debug # Debug mode
npx playwright test --project=chromium # Specific browser
npx playwright show-report # Open HTML report
npx playwright codegen https://example.com # Record tests
Test Structure
import { test, expect } from '@playwright/test';
test('basic test', async ({ page }) => { });
test.describe('group', () => {
test.beforeEach(async ({ page }) => { });
test('test 1', async ({ page }) => { });
});
Navigation
await page.goto('https://example.com');
await page.goBack();
await page.goForward();
await page.reload();
Locators (Priority Order)
page.getByRole('button', { name: 'Submit' }) // ARIA role
page.getByText('Welcome') // Text
page.getByLabel('Email') // Label
page.getByPlaceholder('Enter email') // Placeholder
page.getByTestId('submit-btn') // Test ID
page.locator('button') // CSS selector
page.locator('.btn').first() // First match
page.locator('.btn').nth(2) // Nth match
Actions
await page.locator('button').click();
await page.locator('button').dblclick();
await page.locator('#email').fill('test@test.com');
await page.locator('#input').clear();
await page.locator('#input').press('Enter');
await page.locator('#checkbox').check();
await page.locator('#checkbox').uncheck();
await page.locator('#select').selectOption('value');
await page.locator('.menu').hover();
await page.locator('#file').setInputFiles('file.pdf');
Assertions
// Visibility & State
await expect(page.locator('h1')).toBeVisible();
await expect(page.locator('.loading')).toBeHidden();
await expect(page.locator('button')).toBeEnabled();
await expect(page.locator('button')).toBeDisabled();
await expect(page.locator('#terms')).toBeChecked();
// Text & Content
await expect(page.locator('h1')).toHaveText('Welcome');
await expect(page.locator('h1')).toContainText('Welcome');
await expect(page.locator('#email')).toHaveValue('test@test.com');
// Attributes
await expect(page.locator('a')).toHaveAttribute('href', '/home');
await expect(page.locator('button')).toHaveClass('btn-primary');
// Page
await expect(page).toHaveURL('https://example.com/dashboard');
await expect(page).toHaveTitle('Dashboard');
// Count
await expect(page.locator('.item')).toHaveCount(5);
Waits
await page.waitForSelector('.loading', { state: 'hidden' });
await page.waitForLoadState('networkidle');
await page.waitForURL('**/dashboard');
await page.waitForTimeout(1000); // Avoid if possible
Get Information
const text = await page.locator('h1').textContent();
const value = await page.locator('#email').inputValue();
const href = await page.locator('a').getAttribute('href');
const count = await page.locator('.item').count();
const visible = await page.locator('button').isVisible();
const enabled = await page.locator('button').isEnabled();
Screenshots
await page.screenshot({ path: 'screenshot.png' });
await page.screenshot({ path: 'full.png', fullPage: true });
await page.locator('.error').screenshot({ path: 'error.png' });
Dialogs
page.on('dialog', async dialog => {
await dialog.accept(); // or dialog.dismiss()
});
Network
await page.route('**/api/data', route => {
route.fulfill({ status: 200, body: JSON.stringify({ data: 'mock' }) });
});
const response = await page.waitForResponse('**/api/data');
Common Patterns
// Login
test('login', async ({ page }) => {
await page.goto('https://example.com/login');
await page.getByLabel('Email').fill('user@test.com');
await page.getByLabel('Password').fill('pass123');
await page.getByRole('button', { name: 'Sign in' }).click();
await expect(page).toHaveURL('**/dashboard');
});
// Form
test('form', async ({ page }) => {
await page.getByLabel('Name').fill('John');
await page.getByLabel('Terms').check();
await page.getByRole('button', { name: 'Submit' }).click();
await expect(page.locator('.success')).toBeVisible();
});
// Loop items
const items = page.locator('.item');
for (let i = 0; i < await items.count(); i++) {
console.log(await items.nth(i).textContent());
}
Config (playwright.config.ts)
export default defineConfig({
testDir: './tests',
timeout: 30000,
retries: 2,
workers: 4,
use: {
baseURL: 'https://example.com',
headless: true,
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
],
});
