Playwright Test
In addition to being a browser automation tool, Playwright also comes with acomplete test framework —— Playwright Test。
Playwright Test helps us organize test cases, generate reports, run in parallel, retry on failure, and is fully featured out of the box.
- Playwright Test is anintegrated test framework, with no additional dependencies.
- The configuration file can settimeout, retries, reports, browser projectsetc.
- Test cases supportgrouping, hooks, data-driven。
- and provideparallel execution, HTML reports, failure retriesand other advanced capabilities.
Test Framework Overview
- Integrated test framework: comes with a built-in test runner, no need to install Jest or Mocha separately.
- Built-in assertion library: supports
expectassertions. - Test isolation: each
testruns in a new browser context by default, independent of each other. - Rich features: parallel execution, retries, screenshots, recording, HTML reports, etc.
Installation method:
npm init playwright@latest
Automatically generate project structure, including configuration fileplaywright.config.js。
1. Configuration File Details
Playwright Test usesplaywright.config.js(or.ts) as the configuration entry point.
// playwright.config.js
import { defineConfig } from '@playwright/test';
export default defineConfig({
testDir: './tests', // 测试目录
timeout: 30 * 1000, // 单个测试超时时间
retries: 2, // 失败重试次数
reporter: [['html'], ['list']], // 测试报告类型
use: {
headless: true, // 是否无头模式
screenshot: 'only-on-failure', // 失败时截图
video: 'retain-on-failure', // 失败时保留视频
baseURL: 'https://example.com', // 基础 URL
},
projects: [
{ name: 'Chromium', use: { browserName: 'chromium' } },
{ name: 'Firefox', use: { browserName: 'firefox' } },
{ name: 'WebKit', use: { browserName: 'webkit' } },
],
});
2. Test Script Structure
Playwright Test scripts usually include:
1. Import the test library
import { test, expect } from '@playwright/test';
2. Write test cases
test('示例测试', async ({ page }) => {
await page.goto('https://example.com');
await expect(page).toHaveTitle('Example Domain');
});
3. Grouping and hooks
- Use
describeto organize tests - Use
beforeEach/afterEachfor setup and teardown
Writing Test Cases
1. test()Function Usage
test('页面标题验证', async ({ page }) => {
await page.goto('https://playwright.dev');
await expect(page).toHaveTitle(/Playwright/);
});
2. describe()Grouping
test.describe('用户登录模块', () => {
test('输入正确账号密码', async ({ page }) => {
// 登录逻辑...
});
test('输入错误密码', async ({ page }) => {
// 验证错误提示...
});
});
3. Test Hooks
test.describe('购物车模块', () => {
test.beforeEach(async ({ page }) => {
await page.goto('https://example.com/cart');
});
test.afterEach(async ({ page }) => {
await page.screenshot({ path: 'cart.png' });
});
test('添加商品', async ({ page }) => {
await page.click('#add-item');
await expect(page.locator('#cart-count')).toHaveText('1');
});
});
4. Test Data Preparation
Supports parameterized tests:
const users = [
{ name: 'admin', password: '123456' },
{ name: 'guest', password: 'guest' },
];
for (const user of users) {
test(`用户 ${user.name} 登录`, async ({ page }) => {
await page.goto('https://example.com/login');
await page.fill('#username', user.name);
await page.fill('#password', user.password);
await page.click('#submit');
await expect(page.locator('.welcome')).toBeVisible();
});
}
Running and Reporting
1. Test Execution Commands
npx playwright test # 运行全部测试 npx playwright test login.spec.js # 运行单个文件 npx playwright test -g "登录" # 运行指定用例
2. Parallel Testing
Playwright by defaultruns files in parallel, or you can specify the number of workers in the configuration file:
npx playwright test --workers=4
3. Test Report Generation
After running, generateHTML report:
npx playwright show-report
4. Failure Retry Mechanism
In the configuration fileplaywright.config.jsset:
retries: 2
When a test fails, it will automatically retry, suitable for handling intermittent errors.
- Playwright Test is anintegrated test framework, no additional dependencies needed.
- The configuration file can settimeout, retries, reports, browser projectsetc.
- Test cases supportgrouping, hooks, data-driven。
- and provideparallel execution, HTML reports, failure retriesand other advanced capabilities.
Complete Test Suite Example
1. Project Structure
playwright-demo/ ├─ playwright.config.ts # 全局配置(多项目、多浏览器、报告、重试…) ├─ package.json ├─ tests/ │ ├─ auth.setup.ts # 一次性登录,生成 storageState │ ├─ smoke/ │ │ └─ home.spec.ts # 冒烟用例:标题/URL/截图对比 │ └─ e2e/ │ └─ cart.spec.ts # 端到端:添加购物车、断言、附件、步骤 ├─ fixtures/ │ ├─ pages.ts # 页面对象(PO) │ └─ test.extend.ts # 自定义 fixtures └─ snapshots/ # 视觉基线(自动生成)
2. Configuration File (playwright.config.ts)
Example
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
timeout: 30_000,
retries: 2,
workers: 4,
reporter: [['html', { outputFolder: 'report' }], ['list']],
forbidOnly: !!process.env.CI,
// Unified default usage (can be overridden at project or test level)
use: {
baseURL: 'https://demo.playwright.dev',
headless: true,
screenshot: 'only-on-failure',
video: 'retain-on-failure',
trace: 'retain-on-failure',
viewport: { width: 1366, height: 900 },
locale: 'zh-CN',
},
// Multiple projects: different browsers/devices/login states
projects: [
{ name: 'Chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'Firefox', use: { ...devices['Desktop Firefox'] } },
{
name: 'Mobile Chrome',
use: { ...devices['Pixel 7'], headless: true },
},
// Project with login state (reuse storageState)
{
name: 'Chromium Logged-in',
use: { storageState: 'storageState.json' },
dependencies: ['setup'], // Depends on a setup project to generate login state
},
// Setup project: runs once to generate storageState
{
name: 'setup',
testMatch: /auth\.setup\.ts/,
},
],
});
Key points:projects allow the same test suite to run in different browsers/configurations; use can be overridden at the global/project/test level; reports and retries are managed centrally in the configuration.
3. Fixtures and Page Objects
fixtures/test.extend.ts (custom fixtures + encapsulation of common steps)
Example
import { test as base } from '@playwright/test';
import { HomePage, CartPage } from './pages';
type MyFixtures = {
home: HomePage;
cart: CartPage;
};
export const test = base.extend<MyFixtures>({
home: async ({ page }, use) => {
const home = new HomePage(page);
await use(home);
},
cart: async ({ page }, use) => {
const cart = new CartPage(page);
await use(cart);
},
});
export { expect } from '@playwright/test';
Add custom fixtures based on test.extend(), making it easy to directly inject home and cart instances in any test case.
fixtures/pages.ts (page objects)
Example
import { Page, expect } from '@playwright/test';
export class HomePage {
constructor(private page: Page) {}
async goto() { await this.page.goto('/'); }
get tryTodoLink() { return this.page.getByRole('link', { name: /ToDo MVC/i }); }
}
export class CartPage {
constructor(private page: Page) {}
async goto() { await this.page.goto('/e2e'); } // Assuming an e2e sample page exists
get addFirstItem() { return this.page.getByRole('button', { name: /Add .* #1/i }); }
get cartCount() { return this.page.locator('[data-test=cart-count]'); }
async addOne() { await this.addFirstItem.click(); }
async expectCount(n: number) { await expect(this.cartCount).toHaveText(String(n)); }
}
4. Pre-login (Generate storageState Once)
tests/auth.setup.ts (runs only in the "setup" project)
Example
import { test, expect } from '@playwright/test';
test('create storageState', async ({ page }) => {
await page.goto('https://demo.playwright.dev/todomvc');
// ...Replace with your login flow...
// Assume login is successful
await expect(page).toHaveURL(/todomvc/);
await page.context().storageState({ path: 'storageState.json' });
});
5. Smoke Tests (Title/URL/Visual Comparison)
tests/smoke/home.spec.ts
Example
test.describe('Smoke - Home', () => {
test('title & url & visual snapshot', async ({ page }) => {
await page.goto('https://playwright.dev');
await expect(page).toHaveTitle(/Playwright/);
await expect(page).toHaveURL(/playwright\.dev/);
// Visual regression (auto-generate/compare baseline)
await expect(page).toHaveScreenshot(); // First run generates a baseline
});
});
For visual comparison, it is recommended to use toHaveScreenshot (preferred over the manual approach using page.screenshot() + toMatchSnapshot).
6. End-to-End Tests (Steps, Attachments, Assertions)
tests/e2e/cart.spec.ts
Example
test.describe.configure({ mode: 'parallel' });
test.describe('E2E - Cart', () => {
test.beforeEach(async ({ home }) => {
await test.step('Go to homepage', async () => {
await home.goto();
});
});
test('Add product to cart (with attachment and assertion)', async ({ page, cart }) => {
await test.step('Go to cart page and add product', async () => {
await cart.goto();
await cart.addOne();
await cart.expectCount(1);
});
await test.step('Attach debug information to report', async () => {
await test.info().attach('state.json', {
contentType: 'application/json',
body: Buffer.from(JSON.stringify({ ts: Date.now(), note: 'after add' })),
});
});
// Element-level screenshot
await test.step('Element screenshot', async () => {
const badge = page.locator('[data-test=cart-count]');
await expect(badge).toBeVisible();
await expect(badge).toHaveScreenshot(); // Element snapshot
});
});
});
Use test.step to record steps hierarchically, and use test.info().attach() to attach debug data/screenshots to the report for easier troubleshooting; parallel mode can use describe.configure({ mode: 'parallel' }).
7. Running and Reporting
Common commands:
npx playwright test # 运行全部 npx playwright test tests/e2e # 运行目录 npx playwright test -g "Cart" # 按标题过滤 npx playwright test --project="Chromium" # 指定项目 npx playwright show-report # 打开HTML报告 npx playwright test --update-snapshots # 更新视觉基线 npx playwright test --debug # 调试模式(Inspector)
For CLI filtering, project selection, report viewing, snapshot updates, etc., see the official CLI/Reporting/Snapshot documentation.
Common Related API Quick Reference (Playwright Test)
1. Tests and Grouping
| API | Purpose |
|---|---|
test(name, fn) |
Define tests |
test.describe(title, fn) |
Grouping |
test.describe.configure({ mode }) |
parallel / serial |
test.beforeAll/afterAll |
Group-level before/after hooks |
test.beforeEach/afterEach |
Test case before/after hooks |
test.skip/only/fixme/slow/fail |
Mark/control test cases |
2. Fixtures and Configuration
| API | Purpose |
|---|---|
test.extend<Fixtures>(defs) |
Extend custom fixtures |
test.use(options) |
Test-level overrideuseOptions (such asstorageState、viewport、localeetc.) |
defineConfig({...}) |
Configuration file entry (testDir、retries、workers、reporter…) |
projects |
multi-project/multi-browser/different configurations running |
use: { baseURL, trace, video, screenshot, viewport, locale, timezoneId, storageState } |
Runtime environment and capture strategy |
For details on fixtures / use / configuration options and projects, see the official "Fixtures / Use options / Configuration / Projects" documentation. (Playwright)
3. Assertions (expect)
| API | Purpose | |
|---|---|---|
expect(value).toBe / toEqual / toContain ... |
General assertions | |
expect(locator).toHaveText/Value/Attribute |
Web-specific assertions (with smart waiting) | |
expect(locator).toBeVisible/Hidden/Enabled/Disabled/Checked |
State assertions | |
expect(page).toHaveTitle/URL |
Page assertions | |
| `expect(page/locator).toHaveScreenshot([name | options])` | Visual snapshot comparison (recommended) |
For recommended practices on assertions and visual snapshots, see the Assertions and Snapshots documentation.(Playwright)
4. Steps and Attachments
| API | Purpose | |
|---|---|---|
test.step(name, fn) |
Break tests down into steps (report visualization) | |
| `test.info().attach(name, { path | body, contentType })` | Attach files/data to tests or steps (displayed in the report) |
Attachments can also be applied at the step level (see TestStep / TestStepInfo).(Playwright)
5. Reporting and CLI
| Command/Configuration | Purpose |
|---|---|
reporter: [['html', { outputFolder }], ['list']] |
Report configuration |
npx playwright test --project="Chromium" |
Select project to run |
-g "keyword" / --grep / --grep-invert |
Filter test cases |
--update-snapshots |
Update visual baselines |
npx playwright show-report |
Open report |
Other extensionsSee the official documentation for the full CLI and Reporter options.(Playwright)