全局设置和拆卸
介绍
🌐 Introduction
配置全局设置和拆解有两种方法:使用全局设置文件并在配置中通过 globalSetup 设置,或者使用 项目依赖。使用项目依赖时,你可以定义一个在所有其他项目之前运行的项目。这是推荐的方法,因为它与 Playwright 测试运行器的集成更好:你的 HTML 报告将包括全局设置,会记录跟踪,并且可以使用 fixtures。有关两种方法的详细比较,请参见下表。
🌐 There are two ways to configure global setup and teardown: using a global setup file and setting it in the config under globalSetup or using project dependencies. With project dependencies, you define a project that runs before all other projects. This is the recommended approach, as it integrates better with the Playwright test runner: your HTML report will include the global setup, traces will be recorded, and fixtures can be used. For a detailed comparison of the two approaches, see the table below.
| 功能 | 项目依赖(推荐) | globalSetup(配置选项) |
|---|---|---|
| 在所有测试之前运行 | ✅ 是 | ✅ 是 |
| HTML 报告可见性 | ✅ 显示为单独项目 | ❌ 不显示 |
| 跟踪记录 | ✅ 可获取完整跟踪 | ❌ 不支持 |
| Playwright 夹具 | ✅ 完全支持 | ❌ 不支持 |
| 浏览器管理 | ✅ 通过 browser 夹具 | ❌ 全部手动通过 browserType.launch() |
| 并行和重试 | ✅ 通过标准配置支持 | ❌ 不适用 |
配置选项如 headless 或 testIdAttribute | ✅ 自动应用 | ❌ 忽略 |
选项 1:项目依赖
🌐 Option 1: Project Dependencies
项目依赖 是在另一个项目运行测试之前需要先运行的一系列项目。它们对于配置全局设置操作非常有用,这样一个项目就可以依赖于另一个项目先运行。使用依赖可以让全局设置生成跟踪信息和其他工件。
设置
🌐 Setup
首先,我们添加一个名为“setup db”的新项目。然后我们给它一个testProject.testMatch属性,以便匹配名为global.setup.ts的文件:
🌐 First we add a new project with the name 'setup db'. We then give it a testProject.testMatch property in order to match the file called global.setup.ts:
import { defineConfig } from '@playwright/test';
export default defineConfig({
testDir: './tests',
// ...
projects: [
{
name: 'setup db',
testMatch: /global\.setup\.ts/,
},
// {
// other project
// }
]
});
然后我们将 testProject.dependencies 属性添加到依赖于设置项目的项目中,并在数组中传入我们在上一步中定义的依赖目的名称:
🌐 Then we add the testProject.dependencies property to our projects that depend on the setup project and pass into the array the name of our dependency project, which we defined in the previous step:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
// ...
projects: [
{
name: 'setup db',
testMatch: /global\.setup\.ts/,
},
{
name: 'chromium with db',
use: { ...devices['Desktop Chrome'] },
dependencies: ['setup db'],
},
]
});
在此示例中,“chromium with db”项目依赖于“setup db”项目。然后我们创建一个设置测试,存储在项目的根目录下(注意,设置和拆卸代码必须通过调用test()函数定义为常规测试):
🌐 In this example the 'chromium with db' project depends on the 'setup db' project. We then create a setup test, stored at root level of your project (note that setup and teardown code must be defined as regular tests by calling test() function):
import { test as setup } from '@playwright/test';
setup('create new database', async ({ }) => {
console.log('creating new database...');
// Initialize the database
});
import { test, expect } from '@playwright/test';
test('menu', async ({ page }) => {
// Your test that depends on the database
});
拆除
🌐 Teardown
你可以通过在你的设置项目中添加 testProject.teardown 属性来拆除你的设置。这将在所有依赖目运行后执行。
🌐 You can teardown your setup by adding a testProject.teardown property to your setup project. This will run after all dependent projects have run.
首先,我们在设置项目中添加 testProject.teardown 属性,名称为“cleanup db”,这是我们在上一步为拆卸项目指定的名称:
🌐 First we add the testProject.teardown property to our setup project with the name 'cleanup db' which is the name we gave to our teardown project in the previous step:
import { defineConfig } from '@playwright/test';
export default defineConfig({
testDir: './tests',
// ...
projects: [
{
name: 'setup db',
testMatch: /global\.setup\.ts/,
teardown: 'cleanup db',
},
{
name: 'cleanup db',
testMatch: /global\.teardown\.ts/,
},
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
dependencies: ['setup db'],
},
]
});
然后我们在项目的 tests 目录中创建一个 global.teardown.ts 文件。这个文件将在所有测试运行完后用于删除数据库中的数据。
🌐 Then we create a global.teardown.ts file in the tests directory of your project. This will be used to delete the data from the database after all tests have run.
import { test as teardown } from '@playwright/test';
teardown('delete database', async ({ }) => {
console.log('deleting test database...');
// Delete the database
});
测试过滤
🌐 Test filtering
所有测试过滤选项,例如 --grep/--grep-invert、--shard、直接在命令行按位置过滤,或使用 test.only(),都会直接选择要运行的主要测试。如果这些测试属于有依赖的项目,那么这些依赖目中的所有测试也会运行。
🌐 All test filtering options, such as --grep/--grep-invert, --shard, filtering directly by location in the command line, or using test.only(), directly select the primary tests to be run. If those tests belong to a project with dependencies, all tests from those dependencies will also run.
你可以传递 --no-deps 命令行选项来忽略所有依赖和清理操作。只有你直接选择的项目会运行。
🌐 You can pass --no-deps command line option to ignore all dependencies and teardowns. Only your directly selected projects will run.
更多示例
🌐 More examples
有关更详细的示例,请查看:
🌐 For more detailed examples check out:
- 我们的认证指南
- 我们博客文章 在 Playwright 中更好地设置全局环境,通过项目依赖重用登录
- v1.31 版本发布视频 查看演示
选项 2:配置 globalSetup 和 globalTeardown
🌐 Option 2: Configure globalSetup and globalTeardown
你可以在配置文件中使用 globalSetup 选项在运行所有测试之前进行一次设置。全局设置文件必须导出一个接收配置对象的单一函数。此函数将在所有测试运行之前执行一次。
🌐 You can use the globalSetup option in the configuration file to set something up once before running all tests. The global setup file must export a single function that takes a config object. This function will be run once before all the tests.
同样,可以使用 globalTeardown 在所有测试之后运行一次某个操作。或者,让 globalSetup 返回一个函数,该函数将用作全局拆解(teardown)。你可以通过环境变量将数据(如端口号、认证令牌等)从全局设置传递给你的测试。
🌐 Similarly, use globalTeardown to run something once after all the tests. Alternatively, let globalSetup return a function that will be used as a global teardown. You can pass data such as port number, authentication tokens, etc. from your global setup to your tests using environment variables.
请注意,globalSetup 和 globalTeardown 缺少某些功能——详细对比请参见 简介 部分。建议改用 项目依赖 以获得完整功能支持。
🌐 Beware that globalSetup and globalTeardown lack some features — see the intro section for a detailed comparison. Consider using project dependencies instead to get full feature support.
import { defineConfig } from '@playwright/test';
export default defineConfig({
globalSetup: require.resolve('./global-setup'),
globalTeardown: require.resolve('./global-teardown'),
});
示例
🌐 Example
这是一个全局设置示例,它只进行一次身份验证并在测试中重复使用身份验证状态。它使用了配置文件中的 baseURL 和 storageState 选项。
🌐 Here is a global setup example that authenticates once and reuses authentication state in tests. It uses the baseURL and storageState options from the configuration file.
import { chromium, type FullConfig } from '@playwright/test';
async function globalSetup(config: FullConfig) {
const { baseURL, storageState } = config.projects[0].use;
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto(baseURL!);
await page.getByLabel('User Name').fill('user');
await page.getByLabel('Password').fill('password');
await page.getByText('Sign in').click();
await page.context().storageState({ path: storageState as string });
await browser.close();
}
export default globalSetup;
在配置文件中指定 globalSetup、baseURL 和 storageState。
🌐 Specify globalSetup, baseURL and storageState in the configuration file.
import { defineConfig } from '@playwright/test';
export default defineConfig({
globalSetup: require.resolve('./global-setup'),
use: {
baseURL: 'http://localhost:3000/',
storageState: 'state.json',
},
});
测试一开始就已认证,因为我们指定了由全局设置填充的 storageState。
🌐 Tests start already authenticated because we specify storageState that was populated by global setup.
import { test } from '@playwright/test';
test('test', async ({ page }) => {
await page.goto('/');
// You are signed in!
});
你可以通过在全局设置文件中将它们设置为环境变量(通过 process.env),在测试中提供任意数据。
🌐 You can make arbitrary data available in your tests from your global setup file by setting them as environment variables via process.env.
import type { FullConfig } from '@playwright/test';
async function globalSetup(config: FullConfig) {
process.env.FOO = 'some data';
// Or a more complicated data structure as JSON:
process.env.BAR = JSON.stringify({ some: 'data' });
}
export default globalSetup;
测试可以访问在全局设置中配置的 process.env 属性。
🌐 Tests have access to the process.env properties set in the global setup.
import { test } from '@playwright/test';
test('test', async ({ page }) => {
// environment variables which are set in globalSetup are only available inside test().
const { FOO, BAR } = process.env;
// FOO and BAR properties are populated.
expect(FOO).toEqual('some data');
const complexData = JSON.parse(BAR);
expect(BAR).toEqual({ some: 'data' });
});
捕获全局设置期间的故障痕迹
🌐 Capturing trace of failures during global setup
在某些情况下,捕获全局设置过程中遇到的失败跟踪可能会很有用。为此,你必须在设置中开始跟踪,并且必须确保在错误抛出之前发生错误时停止跟踪。这可以通过将你的设置封装在 try...catch 块中来实现。以下示例扩展了全局设置示例,以捕获跟踪信息。
🌐 In some instances, it may be useful to capture a trace of failures encountered during the global setup. In order to do this, you must start tracing in your setup, and you must ensure that you stop tracing if an error occurs before that error is thrown. This can be achieved by wrapping your setup in a try...catch block. Here is an example that expands the global setup example to capture a trace.
import { chromium, type FullConfig } from '@playwright/test';
async function globalSetup(config: FullConfig) {
const { baseURL, storageState } = config.projects[0].use;
const browser = await chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();
try {
await context.tracing.start({ screenshots: true, snapshots: true });
await page.goto(baseURL!);
await page.getByLabel('User Name').fill('user');
await page.getByLabel('Password').fill('password');
await page.getByText('Sign in').click();
await context.storageState({ path: storageState as string });
await context.tracing.stop({
path: './test-results/setup-trace.zip',
});
await browser.close();
} catch (error) {
await context.tracing.stop({
path: './test-results/failed-setup-trace.zip',
});
await browser.close();
throw error;
}
}
export default globalSetup;