跳到主要内容

全局设置与拆卸

简介

有两种方式可以配置全局设置和清理工作:使用全局设置文件并在配置中通过 globalSetup 设置,或者使用 项目依赖。通过项目依赖的方式,您可以定义一个在所有其他项目之前运行的项目。这是推荐的方式,因为它能更好地与 Playwright 测试运行器集成:您的 HTML 报告会包含全局设置、会记录追踪信息、并且可以使用 fixtures。两种方法的详细对比请见下表。

功能项目依赖(推荐)globalSetup(配置选项)
在所有测试前运行✅ 是✅ 是
HTML 报告可见性✅ 显示为独立项目❌ 不显示
追踪记录✅ 完整追踪可用❌ 不支持
Playwright fixtures✅ 完全支持❌ 不支持
浏览器管理✅ 通过 browser fixture❌ 完全手动通过 browserType.launch()
并行和重试✅ 通过标准配置支持❌ 不适用
配置选项如 headlesstestIdAttribute✅ 自动应用❌ 忽略

选项 1:项目依赖

项目依赖 是一个项目列表,这些项目需要在另一个项目的测试运行之前执行。它们可用于配置全局设置操作,使得一个项目依赖于这些先决条件的运行。使用依赖关系可以让全局设置生成追踪记录和其他产物。

设置

首先我们添加一个名为 'setup db' 的新项目。然后我们为其配置 testProject.testMatch 属性,以匹配名为 global.setup.ts 的文件:

playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
testDir: './tests',
// ...
projects: [
{
name: 'setup db',
testMatch: /global\.setup\.ts/,
},
// {
// 其他项目
// }
]
});

接着我们为依赖该设置项目的其他项目添加 testProject.dependencies 属性,并在数组中传入我们在上一步定义的依赖项目名称:

playwright.config.ts
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() 函数定义为常规测试):

tests/global.setup.ts
import { test as setup } from '@playwright/test';

setup('create new database', async ({ }) => {
console.log('creating new database...');
// 初始化数据库
});
tests/menu.spec.ts
import { test, expect } from '@playwright/test';

test('menu', async ({ page }) => {
// 你的依赖于数据库的测试
});

清理配置

您可以通过在设置项目中添加 testProject.teardown 属性来进行清理操作。这将在所有依赖项目运行完毕后执行。

首先我们在设置项目中添加 testProject.teardown 属性,命名为 'cleanup db'(这是我们在上一步中为清理项目指定的名称):

playwright.config.ts
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'],
},
]
});

然后在项目的测试目录中创建一个 global.teardown.ts 文件。这将在所有测试运行完毕后用于删除数据库中的数据。

tests/global.teardown.ts
import { test as teardown } from '@playwright/test';

teardown('delete database', async ({ }) => {
console.log('deleting test database...');
// 删除数据库
});

测试过滤

所有测试过滤选项,如 --grep/--grep-invert--shard、直接在命令行中按位置过滤,或使用 test.only(),都会直接选择要运行的主要测试。如果这些测试属于具有依赖关系的项目,则这些依赖项中的所有测试也将运行。

您可以传递 --no-deps 命令行选项来忽略所有依赖项和清理操作。只有您直接选择的项目会运行。

更多示例

如需查看更详细的示例,请参阅:

选项 2:配置 globalSetup 和 globalTeardown

您可以在 配置文件 中使用 globalSetup 选项,在运行所有测试前进行一次性的设置。全局设置文件必须导出一个接收配置对象的函数。该函数将在所有测试运行前执行一次。

类似地,使用 globalTeardown 在所有测试完成后执行一些操作。或者,让 globalSetup 返回一个函数作为全局清理操作。您可以通过环境变量将端口号、身份验证令牌等数据从全局设置传递到测试中。

:::注意

请注意 globalSetupglobalTeardown 缺少某些功能 — 详细比较请参阅 介绍 部分。建议考虑使用 项目依赖 来获得完整功能支持。 :::

playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
globalSetup: require.resolve('./global-setup'),
globalTeardown: require.resolve('./global-teardown'),
});

示例

下面是一个全局设置示例,它进行一次身份验证并在测试中复用认证状态。该示例使用了配置文件中的 baseURLstorageState 选项。

global-setup.ts
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;

在配置文件中指定 globalSetupbaseURLstorageState

playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
globalSetup: require.resolve('./global-setup'),
use: {
baseURL: 'http://localhost:3000/',
storageState: 'state.json',
},
});

测试开始时已经处于认证状态,因为我们指定了由全局设置填充的 storageState

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

test('test', async ({ page }) => {
await page.goto('/');
// 您已经登录了!
});

您可以通过 process.env 设置环境变量,使全局设置文件中的任意数据在测试中可用。

global-setup.ts
import type { FullConfig } from '@playwright/test';

async function globalSetup(config: FullConfig) {
process.env.FOO = 'some data';
// 或者更复杂的数据结构作为 JSON:
process.env.BAR = JSON.stringify({ some: 'data' });
}

export default globalSetup;

测试可以访问在全局设置中设置的 process.env 属性。

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

test('test', async ({ page }) => {
// 在 globalSetup 中设置的环境变量仅在 test() 内部可用
const { FOO, BAR } = process.env;

// FOO 和 BAR 属性已被填充
expect(FOO).toEqual('some data');

const complexData = JSON.parse(BAR);
expect(BAR).toEqual({ some: 'data' });
});

捕获全局设置期间的失败追踪

在某些情况下,捕获全局设置期间遇到的失败追踪会很有帮助。为此,您必须在设置中开始追踪,并确保在错误抛出之前停止追踪(如果发生错误)。这可以通过将您的设置代码包裹在 try...catch 块中实现。以下示例扩展了全局设置示例,增加了捕获追踪的功能。

global-setup.ts
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;