YouTip LogoYouTip

Playwright Test

Playwright, in addition to being a browser automation tool, also comes with a **complete testing framework** β€”β€” **Playwright Test**.\\n\\nPlaywright Test can help us organize test cases, generate reports, execute in parallel, and retry on failure. It is fully functional and ready to use out of the box.\\n\\n1. Playwright Test is an **integrated testing framework**, requiring no additional dependencies.\\n2. The configuration file can set **timeouts, retries, reports, browser projects**, etc.\\n3. Test cases support **grouping, hooks, data-driven**.\\n4. Provides advanced capabilities such as **parallel execution, HTML reports, failure retries**.\\n\\n* * *\\n\\n## Testing Framework Overview\\n\\n* **Integrated Testing Framework**: Comes with a test runner, no need to install Jest or Mocha additionally.\\n* **Built-in Assertion Library**: Supports `expect` assertions.\\n* **Test Isolation**: Each `test` executes in a new browser context by default, without interfering with each other.\\n* **Rich Features**: Parallel execution, retries, screenshots, recording, HTML reports, etc.\\n\\nInstallation method:\\n\\nnpm init playwright@latest\\nAutomatically generates the project structure, including the configuration file `playwright.config.js`.\\n\\n### 1. Configuration File Details\\n\\nPlaywright Test uses `playwright.config.js` (or `.ts`) as the configuration entry.\\n\\n// playwright.config.jsimport { defineConfig } from '@playwright/test';export default defineConfig({ testDir: './tests', // Test directory: 30 * 1000, // Per-test timeout: 2, // Retry count on failure: [['html'], ['list']], // Test report type: { headless: true, // Headless mode: 'only-on-failure', // Screenshot on failure: 'retain-on-failure', // Retain video on failure: 'https://example.com', // Base URL }, projects: [ { name: 'Chromium', use: { browserName: 'chromium' } }, { name: 'Firefox', use: { browserName: 'firefox' } }, { name: 'WebKit', use: { browserName: 'webkit' } }, ],});\\n### 2. Test Script Structure\\n\\nPlaywright Test scripts typically include:\\n\\n**1. Import the test library**\\n\\n import { test, expect } from '@playwright/test';\\n**2. Write test cases**\\n\\ntest('Example test', async ({ page }) => { await page.goto('https://example.com'); await expect(page).toHaveTitle('Example Domain');});\\n**3. Grouping and Hooks**\\n\\n* Use `describe` to organize tests\\n* Use `beforeEach` / `afterEach` for pre- and post-processing\\n\\n* * *\\n\\n## Writing Test Cases\\n\\n### 1. Using the `test()` function\\n\\ntest('Page title verification', async ({ page }) => { await page.goto('https://playwright.dev'); await expect(page).toHaveTitle(/Playwright/);});\\n### 2. `describe()` grouping\\n\\ntest.describe('UserLoginModule', () => { test('Enter correct account and password', async ({ page }) => { // LoginLogic... }); test('Enter incorrect password', async ({ page }) => { // Verify error message... });});\\n### 3. Test Hooks\\n\\ntest.describe('Shopping Cart Module', () => { test.beforeEach(async ({ page }) => { await page.goto('https://example.com/cart'); }); test.afterEach(async ({ page }) => { await page.screenshot({ path: 'cart.png' }); }); test('Add product', async ({ page }) => { await page.click('#add-item'); await expect(page.locator('#cart-count')).toHaveText('1'); });});\\n### 4. Test Data Preparation\\n\\nSupports parameterized testing:\\n\\nconst users = [ { name: 'admin', password: '123456' }, { name: 'guest', password: 'guest' },];for (const user of users) { test(`User ${user.name} Login`, 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(); });}\\n\\n* * *\\n\\n## Running and Reporting\\n\\n### 1. Test Execution Commands\\n\\nnpx playwright test # Run all tests.spec.js # Run a single file "Login" # Run specified test case\\n### 2. Parallel Testing\\n\\nPlaywright **executes in parallel by file** by default, and you can also specify the number of workers in the configuration file:\\n\\nnpx playwright test --workers=4\\n### 3. Test Report Generation\\n\\nGenerate an **HTML report** after running:\\n\\nnpx playwright show-report\\n### 4. Failure Retry Mechanism\\n\\nSet in the configuration file `playwright.config.js`:\\n\\nretries: 2\\nIt will automatically retry when a test fails, which is suitable for handling sporadic errors.\\n\\n1. Playwright Test is an **integrated testing framework**, requiring no additional dependencies.\\n2. The configuration file can set **timeouts, retries, reports, browser projects**, etc.\\n3. Test cases support **grouping, hooks, data-driven**.\\n4. Provides advanced capabilities such as **parallel execution, HTML reports, failure retries**.\\n\\n* * *\\n\\n## Complete Test Suite Example\\n\\n### 1. Project Structure\\n\\nplaywright-demo/β”œβ”€ playwright.config.ts # Global configuration (multi-project, multi-browser, reports, retries...)β”œβ”€ package.json β”œβ”€ tests/β”‚ β”œβ”€ auth.setup.ts # One-time Login to generate storageStateβ”‚ β”œβ”€ smoke/β”‚ β”‚ └─ home.spec.ts # Smoke test cases: title/URL/screenshot comparisonβ”‚ └─ e2e/β”‚ └─ cart.spec.ts # End-to-end: add to cart, assertions, attachments, stepsβ”œβ”€ fixtures/β”‚ β”œβ”€ pages.ts # Page Object (PO)β”‚ └─ test.extend.ts # Custom fixtures└─ snapshots/ # Visual baseline (automatically generated)\\n### 2. Configuration File (playwright.config.ts)\\n\\n## Instance\\n\\n// playwright.config.ts\\n\\nimport{ defineConfig, devices } from '@playwright/test';\\n\\nexport default defineConfig({\\n\\n testDir:'./tests',\\n\\n timeout:30 _000,\\n\\n retries:2,\\n\\n workers:4,\\n\\n reporter:[['html',{ outputFolder:'report'}],['list']],\\n\\n forbidOnly:!!process.env.CI,\\n\\n// Unified default setting (can be overridden at project or test level)\\n\\n use:{\\n\\n baseURL:'https://demo.playwright.dev',\\n\\n headless:true,\\n\\n screenshot:'only-on-failure',\\n\\n video:'retain-on-failure',\\n\\n trace:'retain-on-failure',\\n\\n viewport:{ width:1366, height:900},\\n\\n locale:'zh-CN',\\n\\n},\\n\\n// Multi-project: Different Browsers/Devices/LoginState\\n\\n projects:[\\n\\n{ name:'Chromium', use:{ ...devices['Desktop Chrome']}},\\n\\n{ name:'Firefox',use:{ ...devices['Desktop Firefox']}},\\n\\n{\\n\\n name:'Mobile Chrome',\\n\\n use:{ ...devices['Pixel 7'], headless:true},\\n\\n},\\n\\n// withLoginStateProject (reuse storageState)\\n\\n{\\n\\n name:'Chromium Logged-in',\\n\\n use:{ storageState:'storageState.json'},\\n\\n dependencies:['setup'],// Depends on prerequisite project to generate Login state\\n\\n},\\n\\n// Prerequisite"setup"Project: run once to generate storageState\\n\\n{\\n\\n name:'setup',\\n\\n testMatch:/auth\\\\.setup\\\\.ts/,\\n\\n},\\n\\n],\\n\\n});\\n\\n**Key Points:** projects allow the same set of test cases to run under different browsers/configurations; use can be overridden at the global/project/test levels; reports and retries are managed uniformly in the configuration.\\n\\n### 3. Fixtures and Page Objects\\n\\nfixtures/test.extend.ts (Custom fixture + common step encapsulation)\\n\\n## Instance\\n\\n// fixtures/test.extend.ts\\n\\nimport{ test as base } from '@playwright/test';\\n\\nimport{ HomePage, CartPage } from './pages';\\n\\ntype MyFixtures ={\\n\\n home: HomePage;\\n\\n cart: CartPage;\\n\\n};\\n\\nexport const test = base.extend({\\n\\n home: async ({ page }, use)=>{\\n\\nconst home =new HomePage(page);\\n\\n await use(home);\\n\\n},\\n\\n cart: async ({ page }, use)=>{\\n\\nconst cart =new CartPage(page);\\n\\n await use(cart);\\n\\n},\\n\\n});\\n\\nexport{ expect } from '@playwright/test';\\n\\nAdd custom fixtures based on test.extend(), making it convenient to directly inject home and cart instances into any test case.\\n\\n**fixtures/pages.ts (Page Object)**\\n\\n## Instance\\n\\n// fixtures/pages.ts\\n\\nimport{ Page, expect } from '@playwright/test';\\n\\nexport class HomePage {\\n\\n constructor(private page: Page){}\\n\\n async goto(){ await this.page.goto('/');}\\n\\nget tryTodoLink(){return this.page.getByRole('link',{ name:/ToDo MVC/i});}\\n\\n}\\n\\nexport class CartPage {\\n\\n constructor(private page: Page){}\\n\\n async goto(){ await this.page.goto('/e2e');}// Assume e2e example page exists\\n\\nget addFirstItem(){return this.page.getByRole('button',{ name:/Add .* #1/i});}\\n\\nget cartCount(){return this.page.locator('');}\\n\\n async addOne(){ await this.addFirstItem.click();}\\n\\n async expectCount(n: number){ await expect(this.cartCount).toHaveText(String(n));}\\n\\n}\\n\\n### 4. Pre-login (One-time generation of storageState)\\n\\ntests/auth.setup.ts (Only executed in the "setup" project)\\n\\n## Instance\\n\\n// tests/auth.setup.ts\\n\\nimport{ test, expect } from '@playwright/test';\\n\\ntest('create storageState', async ({ page })=>{
← Playwright Network InterceptioPlaywright Advanced Page Opera β†’