playwright-e2e-testing
10
总安装量
4
周安装量
#29226
全站排名
安装命令
npx skills add https://github.com/fugazi/test-automation-skills-agents --skill playwright-e2e-testing
Agent 安装分布
opencode
4
codex
4
amp
3
github-copilot
3
gemini-cli
3
Skill 文档
Playwright E2E Testing (TypeScript)
Comprehensive toolkit for end-to-end testing of web applications using Playwright with TypeScript. Enables robust UI testing, API validation, and responsive design verification following best practices.
Activation: This skill is triggered when working with Playwright tests, browser automation, E2E testing, API testing with Playwright, or test infrastructure setup.
When to Use This Skill
- Write E2E tests for user flows, forms, navigation, and authentication
- API testing via
requestfixture or network interception during UI tests - Responsive testing across mobile, tablet, and desktop viewports
- Debug flaky tests using traces, screenshots, videos, and Playwright Inspector
- Setup test infrastructure with Page Object Model and fixtures
- Mock/intercept APIs for isolated, deterministic testing
- Visual regression testing with screenshot comparisons
Prerequisites
| Requirement | Details |
|---|---|
| Node.js | v18+ recommended |
| Package Manager | npm, yarn, or pnpm |
| Playwright | @playwright/test package |
| TypeScript | typescript + ts-node (optional but recommended) |
| Browsers | Installed via npx playwright install |
Quick Setup
# Initialize new project
npm init playwright@latest
# Or add to existing project
npm install -D @playwright/test
npx playwright install
First Questions to Ask
Before writing tests, clarify:
- App URL: Local dev server command + port, or staging URL?
- Critical flows: Which user journeys must be covered (happy path + error states)?
- Browsers/devices: Chrome, Firefox, Safari? Mobile viewports?
- API strategy: Real backend, mocked responses, or hybrid?
- Test data: Seed data available? Reset/cleanup strategy?
Core Principles
1. Test Runner & TypeScript
Always use @playwright/test with TypeScript for type safety and better IDE support.
import { test, expect } from '@playwright/test';
test('user can login', async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill('user@test.com');
await page.getByLabel('Password').fill('password123');
await page.getByRole('button', { name: 'Sign in' }).click();
await expect(page).toHaveURL(/.*dashboard/);
});
2. Locator Strategy (Priority Order)
| Priority | Locator | Example |
|---|---|---|
| 1 | Role + accessible name | getByRole('button', { name: 'Submit' }) |
| 2 | Label | getByLabel('Email') |
| 3 | Placeholder | getByPlaceholder('Enter email') |
| 4 | Text | getByText('Welcome') |
| 5 | Test ID | getByTestId('submit-btn') |
| 6 | CSS (avoid) | locator('.btn-primary') |
See Locator Strategies Guide for detailed patterns.
3. Auto-Waiting & Web-First Assertions
Playwright auto-waits for elements. Never use sleep() or arbitrary timeouts.
// â
Web-first assertions (auto-retry)
await expect(page.getByRole('alert')).toBeVisible();
await expect(page).toHaveURL(/dashboard/);
await expect(page.getByTestId('status')).toHaveText('Success!');
// â Avoid manual waits
await page.waitForTimeout(2000); // Bad practice
4. Test Structure with Steps
Use test.step() for readable reports and failure localization:
test('checkout flow', async ({ page }) => {
await test.step('Add item to cart', async () => {
await page.goto('/products/1');
await page.getByRole('button', { name: 'Add to Cart' }).click();
});
await test.step('Complete checkout', async () => {
await page.goto('/checkout');
await page.getByRole('button', { name: 'Pay Now' }).click();
});
await test.step('Verify confirmation', async () => {
await expect(page.getByRole('heading')).toContainText('Order Confirmed');
});
});
Key Workflows
Forms & Navigation
// Form submit and wait for navigation (auto-waiting)
await page.getByRole('button', { name: 'Login' }).click();
await expect(page).toHaveURL(/.*dashboard/);
// Form with API response validation
const responsePromise = page.waitForResponse(
r => r.url().includes('/api/login') && r.status() === 200
);
await page.getByRole('button', { name: 'Login' }).click();
const response = await responsePromise;
API Testing (Request Fixture)
test('API health check', async ({ request }) => {
const response = await request.get('/api/health');
expect(response.ok()).toBeTruthy();
expect(await response.json()).toMatchObject({ status: 'ok' });
});
API Mocking & Interception
test('handles API error', async ({ page }) => {
await page.route('**/api/users', route =>
route.fulfill({ status: 500, body: JSON.stringify({ error: 'Server error' }) })
);
await page.goto('/users');
await expect(page.getByRole('alert')).toContainText('Something went wrong');
});
Responsive Testing
const viewports = [
{ width: 375, height: 667, name: 'mobile' },
{ width: 768, height: 1024, name: 'tablet' },
{ width: 1280, height: 720, name: 'desktop' },
];
for (const vp of viewports) {
test(`navigation works on ${vp.name}`, async ({ page }) => {
await page.setViewportSize(vp);
await page.goto('/');
// Mobile: hamburger menu
if (vp.width < 768) {
await page.getByRole('button', { name: /menu/i }).click();
}
await page.getByRole('link', { name: 'About' }).click();
await expect(page).toHaveURL(/about/);
});
}
Configuration
Use playwright.config.ts for project-wide settings:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
retries: process.env.CI ? 2 : 0,
reporter: [['html'], ['junit', { outputFile: 'results.xml' }]],
use: {
baseURL: 'http://localhost:3000',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
projects: [
{ name: 'chromium', use: devices['Desktop Chrome'] },
{ name: 'mobile', use: devices['Pixel 5'] },
],
webServer: {
command: 'npm run dev',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
},
});
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
| Element not found | Wrong locator or not rendered | Use PWDEBUG=1 to inspect, verify with getByRole |
| Timeout waiting | Element hidden or slow load | Check for overlays, increase timeout, use waitFor() |
| Flaky tests | Race conditions, animations | Add test.step(), use proper waits, disable animations |
| Strict mode violation | Multiple elements match | Use .first(), .filter(), or more specific locator |
| Screenshots differ | Dynamic content | Mask dynamic areas, use deterministic data |
| CI fails, local passes | Environment differences | Check baseURL, timeouts, webServer config |
| API mock not working | Route pattern mismatch | Use **/api/... glob, verify with page.on('request') |
CLI Quick Reference
| Command | Description |
|---|---|
npx playwright test |
Run all tests headless |
npx playwright test --ui |
Open UI mode (interactive) |
npx playwright test --headed |
Run with visible browser |
npx playwright test --debug |
Run with Playwright Inspector |
npx playwright test -g "login" |
Run tests matching pattern |
npx playwright test --project=chromium |
Run specific project |
npx playwright show-report |
Open HTML report |
npx playwright codegen |
Generate tests by recording |
PWDEBUG=1 npx playwright test |
Debug with Inspector |
DEBUG=pw:api npx playwright test |
Verbose API logging |
References
| Document | Content |
|---|---|
| Snippets | Ready-to-use code patterns |
| Locator Strategies | Complete locator guide |
| Page Object Model | POM implementation patterns |
| Debugging Guide | Troubleshooting & debugging techniques |