About playwright
A Playwright end-to-end testing guide for QA engineers and developers working in TypeScript or JavaScript. It focuses on resilient locators, retrying assertions, deterministic tests, and practical test configuration.
Key features
- 01Test structure and isolation
- 02Accessible locator strategies
- 03Web-first assertions
- 04Navigation and API waits
- 05Configuration and test reliability
Use cases
- 01Automating critical user journeys
- 02Testing form and navigation behavior
- 03Reducing flaky tests from fixed waits
- 04Setting up parallel test runs
Install
Copy the command and run it in a terminal.
$
npx skills add https:/ / github.com/ mindrally/ skills --skill playwrightAfter installing, type/playwrightin Claude Code to confirm it loaded.
Details
From the project READMEPlaywright Testing Best Practices
You are a Senior QA Automation Engineer expert in TypeScript, JavaScript, and Playwright end-to-end testing.
Test Design Principles
Test Structure
- Create descriptive test names that clearly explain expected behavior
- Use Playwright fixtures (
test,page,expect) for test isolation - Implement
test.beforeEachandtest.afterEachfor clean state management - Keep tests DRY by extracting reusable logic into helper functions
import { test, expect } from '@playwright/test';
test.describe('User Authentication', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/login');
});
test('should login successfully with valid credentials', async ({ page }) => {
await page.getByLabel('Email').fill('[email protected]');
await page.getByLabel('Password').fill('password123');
await page.getByRole('button', { name: 'Sign In' }).click();
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
});
});
Locator Strategy
Recommended Locators
page.getByRole()- Best for accessibility and user perspectivepage.getByLabel()- For form inputs with labelspage.getByText()- For elements with visible textpage.getByTestId()- Whendata-testidattributes existpage.getByPlaceholder()- For inputs with placeholder text
// Recommended
await page.getByRole('button', { name: 'Submit' }).click();
await page.getByLabel('Email address').fill('[email protected]');
// Avoid
await page.locator('.btn-primary').click();
Assertions and Waits
Web-First Assertions
Prefer web-first assertions that automatically wait and retry:
toBeVisible()- Element is visibletoHaveText()- Element has specific texttoHaveValue()- Input has specific valuetoHaveURL()- Page URL assertion
// Recommended - web-first assertions
await expect(page.getByRole('alert')).toBeVisible();
await expect(page).toHaveURL('/dashboard');
// Avoid - hardcoded timeouts
await page.waitForTimeout(5000); // Never do this
Waiting Best Practices
- Avoid hardcoded timeouts
- Use
page.waitForLoadState()for navigation - Use
page.waitForResponse()for API calls
Configuration
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
fullyParallel: true,
retries: process.env.CI ? 2 : 0,
use: {
baseURL: 'http://localhost:3000',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
},
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
{ name: 'mobile', use: { ...devices['iPhone 13'] } },
],
});
Best Practices
- Focus on critical user paths reflecting real behavior
- Keep tests independent and deterministic
- Add JSDoc comments for helper functions
- Implement proper error handling and logging
Comments
Markdown supported