首页 / Playwright 入门教程 / 测试钩子 beforeEach 等

Playwright 入门教程

测试钩子 beforeEach 等

本教程共 59 篇 · 第 41 篇 · 更新于 2026-08-04 · 约 10 分钟阅读

Playwright钩子beforeEachafterEachbeforeAllafterAll

本节目标:学完能正确使用四种钩子(beforeEach、afterEach、beforeAll、afterAll),清楚它们各自在什么时机、什么范围执行。

Fixture(夹具)负责「准备环境」,Hook(钩子)负责「在固定时机插一段代码」。Playwright 提供四个钩子,名字直白得不用翻译。但用错范围,坑就来了。

四种钩子一览

  • beforeEach:每条测试前执行。
  • afterEach:每条测试后执行。
  • beforeAll:整个文件(或 group)的所有测试之前,执行一次。
  • afterAll:整个文件(或 group)的所有测试之后,执行一次。
Note

钩子是写在 test. 下面的函数,比如 test.beforeEach(...)。它们只在同一个文件、同一个 describe 块内生效。

每条测试前后的准备

最常见的是 beforeEach,保证每条测试都从干净状态开始:

import { test, expect } from '@playwright/test';

test.beforeEach(async ({ page }) => {
  await page.goto('https://github.com/login');
});

test('能填用户名', async ({ page }) => {
  await page.getByLabel('Username').fill('user1');
});

test('能填密码', async ({ page }) => {
  await page.getByLabel('Password').fill('pass1');
});

只跑一次的重活

有些事没必要每条都做,比如开一个共享页面、准备一批共享数据。用 beforeAll

import { test, expect, type Page } from '@playwright/test';

let sharedPage: Page;

test.beforeAll(async ({ browser }) => {
  sharedPage = await browser.newPage();     // 注意:这个页面不走内置 page 夹具
  await sharedPage.goto('https://playwright.dev/');
});

test.afterAll(async () => {
  await sharedPage.close();                 // 自己开的,自己关
});

test('标题正确', async () => {
  await expect(sharedPage).toHaveTitle(/Playwright/);
});
Warning

beforeAll 里建的对象会被同文件的多条测试共享,一条测试改了状态,下一条就得跟着受影响。这也意味着测试不再彼此独立。所以这招只在「确实只需建一次、且各测试互不干扰」时才用。

钩子的生效范围

钩子受 describe 块约束。写在某个 describe 里的 beforeEach,只对那个块内的测试生效:

import { test, expect } from '@playwright/test';

test.describe('登录相关', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/login');
  });

  test('显示登录框', async ({ page }) => {
    await expect(page.getByRole('button', { name: 'Sign in' })).toBeVisible();
  });
});

在钩子里用夹具

钩子也能声明夹具,和测试一样方便。下面用的是第 39 章那个自定义的 settingsPage

import { test } from './my-test';   // 带自定义夹具的 test

test.beforeEach(async ({ settingsPage }) => {
  await settingsPage.switchToDarkMode();
});

还可以把注解写进钩子,比如移动端暂时跳过:

import { test } from '@playwright/test';

test.beforeEach(async ({ page, isMobile }) => {
  test.fixme(isMobile, '移动端设置页暂不支持');
  await page.goto('http://localhost:3000/settings');
});

执行顺序全景

结合夹具时,大致顺序是这样的:

  1. worker(工作进程)级夹具建起来。
  2. beforeAll
  3. 每条测试:自动夹具 → page 等测试级夹具 → beforeEach → 测试体 → afterEach → 测试级夹具拆掉。
  4. afterAll
  5. worker 级夹具在进程结束时才拆。

记住两条就够:自动夹具永远最先建,测试级夹具每条测试后就拆。

钩子还是夹具?

这是新手常纠结的。我的取舍:准备逻辑只服务于少数测试、且不需要清理,用钩子够快;如果多测试共用、还需要清理、想跨文件复用,就升级成夹具(第 37、39 章)。

Tip

想让某段「每个测试前后」的逻辑全局生效,不必每个文件都写钩子——把它做成 auto: true 的夹具(第 39 章)更省事。

常见翻车点

  1. beforeAll 里放了不该共享的状态,并行时互相污染。
  2. afterEach 的清理写成了 afterAll,导致第一条测试污染了第二条。
  3. 钩子依赖的夹具忘了声明,报「fixture 不存在」。

钩子用好了是利器,用岔了就成隐式耦合。保持每条测试独立,钩子只做轻量准备,基本不会出事。

小结

四个钩子按执行频次分两对:beforeEach/afterEach 每条测试前后跑,beforeAll/afterAll 整组测试只跑一次。常见坑就那几个——beforeAll 别放共享状态、afterEachafterAll 别搞混、夹具忘声明。记住:轻量准备用钩子,要复用要清理就上夹具。