| name | playwright-e2e-automation |
| metadata | {"category":"QA and E2E Automation Testing"} |
| description | Master enterprise Playwright end-to-end (E2E) automation, Page Object Model (POM) architecture, cross-browser testing, network mocking, visual regression testing, and CI pipeline integrations. Trigger when writing Playwright tests, automating web UI E2E flows, or configuring Playwright CI/CD test runners. |
| compatibility | Node.js 18+, @playwright/test 1.35+, Chromium, Firefox, WebKit |
Playwright E2E Automation Skill Guide
This skill provides production standards, design patterns, and test harness setups for building resilient end-to-end (E2E) test suites with Playwright.
1. Test Architecture & Directory Layout
Structure Playwright test suites using the Page Object Model (POM) and custom test fixtures:
e2e-tests/
├── playwright.config.ts # Global configuration, browser matrix, CI settings
├── fixtures/
│ └── test-fixtures.ts # Custom Playwright fixtures (auth, page objects)
├── pages/
│ ├── base.page.ts # Shared base page class with common assertions
│ ├── login.page.ts # Login page object
│ └── dashboard.page.ts # Dashboard page object
├── tests/
│ ├── auth/
│ │ └── login.spec.ts # Authentication E2E test specs
│ └── dashboard/
│ └── analytics.spec.ts
└── .auth/
└── user.json # Cached storageState for authenticated sessions
2. Configuration Standard (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 ? 2 : undefined,
reporter: [
['html', { open: 'never' }],
['github'],
['list'],
],
use: {
baseURL: process.env.BASE_URL || 'http://localhost:3000',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
actionTimeout: 10000,
navigationTimeout: 15000,
},
projects: [
{
name: 'setup',
testMatch: /global\.setup\.ts/,
},
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
: [],
},
{
: ,
: { ...devices[] },
: [],
},
{
: ,
: { ...devices[] },
: [],
},
{
: ,
: { ...devices[] },
: [],
},
],
: {
: ,
: ,
: !process..,
: ,
},
});
3. Page Object Model (POM) Implementation
A. Base Page Class (pages/base.page.ts)
import { Page, Locator, expect } from '@playwright/test';
export abstract class BasePage {
readonly page: Page;
constructor(page: Page) {
this.page = page;
}
async waitForPageLoaded(): Promise<void> {
await this.page.waitForLoadState('domcontentloaded');
await this.page.waitForLoadState('networkidle');
}
async verifyHeading(text: string | RegExp): Promise<void> {
const heading = this.page.getByRole('heading', { level: 1 });
await expect(heading).toHaveText(text);
}
}
B. Login Page Object (pages/login.page.ts)
import { Page, Locator, expect } from '@playwright/test';
import { BasePage } from './base.page';
export class LoginPage extends BasePage {
readonly emailInput: Locator;
readonly passwordInput: Locator;
readonly submitButton: Locator;
readonly errorMessage: Locator;
constructor(page: Page) {
super(page);
this.emailInput = page.getByLabel('Email address');
this.passwordInput = page.getByLabel('Password');
this.submitButton = page.getByRole('button', { name: 'Sign in' });
this.errorMessage = page.getByRole('alert');
}
async goto(): <> {
..();
.();
}
(: , : ): <> {
..(email);
..(pass);
..();
}
(: ): <> {
(.).();
(.).(message);
}
}
4. Test Specifications & Network Interception
import { test, expect } from '@playwright/test';
import { LoginPage } from '../pages/login.page';
test.describe('Authentication E2E Flow', () => {
let loginPage: LoginPage;
test.beforeEach(async ({ page }) => {
loginPage = new LoginPage(page);
await loginPage.goto();
});
test('should display error on invalid credentials', async () => {
await loginPage.login('invalid@example.com', 'wrongpassword');
await loginPage.assertErrorMessage('Invalid email or password');
});
test('should mock backend API response for success flow', async ({ page }) => {
await page.route('**/api/v1/auth/login', async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ token: , : { : } }),
});
});
loginPage.(, );
(page).();
});
(, ({ page }) => {
(page).(, {
: ,
});
});
});
5. Execution Commands & Reporting
npx playwright test
npx playwright test --ui
npx playwright test tests/auth/login.spec.ts --project=chromium
npx playwright test --debug
npx playwright show-report
6. Anti-Patterns & Best Practices
| Anti-Pattern | Test Flakiness / Failure | Production Best Practice |
|---|
Using hardcoded delays (page.waitForTimeout(3000)) | Leads to slow, fragile tests that fail under loaded CI runtimes. | Rely on Playwright auto-waiting and locator assertions (expect(locator).toBeVisible()). |
Locating elements via CSS classes or XPath (div > span.btn-2) | Fragile selectors break whenever CSS layout or refactoring occurs. | Use user-visible aria locators (getByRole, getByLabel, getByText). |
| Re-authenticating via UI in every test spec | Dramatically slows execution time across large suites. | Authenticate once in global.setup.ts and save state to storageState: '.auth/user.json'. |
| Not running tests in parallel in CI | CI execution bottlenecking release pipelines. | Set fullyParallel: true and scale workers dynamically via CI runner CPU counts. |