跳到主要内容

Playwright 测试

Playwright Test 提供了 test 函数来声明测试,以及 expect 函数来编写断言。

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

test('basic test', async ({ page }) => {
await page.goto('https://playwright.net.cn/');
const name = await page.innerText('.navbar__title');
expect(name).toBe('Playwright');
});

方法

test

添加于: v1.10 test.test

声明一个测试。

  • test(title, body)
  • test(title, details, body)

用法

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

test('basic test', async ({ page }) => {
await page.goto('https://playwright.net.cn/');
// ...
});

标签

你可以通过提供额外的测试详情来给测试打标签。或者,你也可以在测试标题中包含标签。注意,每个标签必须以 @ 符号开头。

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

test('basic test', {
tag: '@smoke',
}, async ({ page }) => {
await page.goto('https://playwright.net.cn/');
// ...
});

test('another test @smoke', async ({ page }) => {
await page.goto('https://playwright.net.cn/');
// ...
});

测试标签会显示在测试报告中,并且可以通过自定义报告器的 TestCase.tags 属性获取。

你还可以在测试执行期间根据标签过滤测试

了解更多关于打标签的信息。

注解

你可以通过提供额外的测试详情来给测试添加注解。

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

test('basic test', {
annotation: {
type: 'issue',
description: 'https://github.com/microsoft/playwright/issues/23180',
},
}, async ({ page }) => {
await page.goto('https://playwright.net.cn/');
// ...
});

测试注解会显示在测试报告中,并且可以通过自定义报告器的 TestCase.annotations 属性获取。

你还可以在运行时通过操作 testInfo.annotations 添加注解。

了解更多关于测试注解的信息。

参数


test.afterAll

添加于: v1.10 test.test.afterAll

声明一个 afterAll 钩子,该钩子在所有测试运行后,每个 worker 执行一次。

当在测试文件范围内调用时,在文件中的所有测试运行后执行。当在 test.describe() 组内调用时,在组内的所有测试运行后执行。

用法

test.afterAll(async () => {
console.log('Done with tests');
// ...
});

或者,你也可以声明一个带标题的钩子。

test.afterAll('Teardown', async () => {
console.log('Done with tests');
// ...
});

参数

  • title string (可选)添加于: v1.38#

    钩子标题。

  • hookFunction function(Fixtures, TestInfo)#

    钩子函数,接受一个或两个参数:一个包含 worker 夹具的对象和可选的 TestInfo

详情

添加多个 afterAll 钩子时,它们将按照注册的顺序运行。

请注意,worker 进程会在测试失败时重启,并且 afterAll 钩子会在新的 worker 中再次运行。了解更多关于workers 和失败的信息。

即使某些适用的钩子失败,Playwright 也会继续运行所有其他钩子。

  • test.afterAll(hookFunction)
  • test.afterAll(title, hookFunction)

test.afterEach

添加于: v1.10 test.test.afterEach

声明一个 afterEach 钩子,该钩子在每个测试运行后执行。

当在测试文件范围内调用时,在文件中的每个测试运行后执行。当在 test.describe() 组内调用时,在组内的每个测试运行后执行。

你可以访问与测试体本身相同的所有 Fixtures,还可以访问提供许多有用信息的 TestInfo 对象。例如,你可以检查测试是成功还是失败。

  • test.afterEach(hookFunction)
  • test.afterEach(title, hookFunction)

用法

example.spec.ts
import { test, expect } from '@playwright/test';

test.afterEach(async ({ page }) => {
console.log(`Finished ${test.info().title} with status ${test.info().status}`);

if (test.info().status !== test.info().expectedStatus)
console.log(`Did not run as expected, ended up at ${page.url()}`);
});

test('my test', async ({ page }) => {
// ...
});

或者,你也可以声明一个带标题的钩子。

example.spec.ts
test.afterEach('Status check', async ({ page }) => {
if (test.info().status !== test.info().expectedStatus)
console.log(`Did not run as expected, ended up at ${page.url()}`);
});

参数

详情

添加多个 afterEach 钩子时,它们将按照注册的顺序运行。

即使某些适用的钩子失败,Playwright 也会继续运行所有其他钩子。


test.beforeAll

添加于: v1.10 test.test.beforeAll

声明一个 beforeAll 钩子,该钩子在所有测试运行前,每个 worker 进程执行一次。

当在测试文件范围内调用时,在文件中的所有测试运行前执行。当在 test.describe() 组内调用时,在组内的所有测试运行前执行。

你可以使用 test.afterAll() 来拆除在 beforeAll 中设置的任何资源。

  • test.beforeAll(hookFunction)
  • test.beforeAll(title, hookFunction)

用法

example.spec.ts
import { test, expect } from '@playwright/test';

test.beforeAll(async () => {
console.log('Before tests');
});

test.afterAll(async () => {
console.log('After tests');
});

test('my test', async ({ page }) => {
// ...
});

或者,你也可以声明一个带标题的钩子。

example.spec.ts
test.beforeAll('Setup', async () => {
console.log('Before tests');
});

参数

  • title string (可选)添加于: v1.38#

    钩子标题。

  • hookFunction function(Fixtures, TestInfo)#

    钩子函数,接受一个或两个参数:一个包含 worker 夹具的对象和可选的 TestInfo

详情

添加多个 beforeAll 钩子时,它们将按照注册的顺序运行。

请注意,worker 进程会在测试失败时重启,并且 beforeAll 钩子会在新的 worker 中再次运行。了解更多关于workers 和失败的信息。

即使某些适用的钩子失败,Playwright 也会继续运行所有其他钩子。


test.beforeEach

添加于: v1.10 test.test.beforeEach

声明一个 beforeEach 钩子,该钩子在每个测试运行前执行。

当在测试文件范围内调用时,在文件中的每个测试运行前执行。当在 test.describe() 组内调用时,在组内的每个测试运行前执行。

你可以访问与测试体本身相同的所有 Fixtures,还可以访问提供许多有用信息的 TestInfo 对象。例如,你可以在测试开始前导航到页面。

你可以使用 test.afterEach() 来拆除在 beforeEach 中设置的任何资源。

  • test.beforeEach(hookFunction)
  • test.beforeEach(title, hookFunction)

用法

example.spec.ts
import { test, expect } from '@playwright/test';

test.beforeEach(async ({ page }) => {
console.log(`Running ${test.info().title}`);
await page.goto('https://my.start.url/');
});

test('my test', async ({ page }) => {
expect(page.url()).toBe('https://my.start.url/');
});

或者,你也可以声明一个带标题的钩子。

example.spec.ts
test.beforeEach('Open start URL', async ({ page }) => {
console.log(`Running ${test.info().title}`);
await page.goto('https://my.start.url/');
});

参数

详情

添加多个 beforeEach 钩子时,它们将按照注册的顺序运行。

即使某些适用的钩子失败,Playwright 也会继续运行所有其他钩子。


test.describe

添加于: v1.10 test.test.describe

声明一个测试组。

  • test.describe(title, callback)
  • test.describe(callback)
  • test.describe(title, details, callback)

用法

你可以声明一个带标题的测试组。该标题将在测试报告中作为每个测试标题的一部分可见。

test.describe('two tests', () => {
test('one', async ({ page }) => {
// ...
});

test('two', async ({ page }) => {
// ...
});
});

匿名组

你也可以声明一个不带标题的测试组。这对于使用 test.use() 为一组测试提供通用选项很方便。

test.describe(() => {
test.use({ colorScheme: 'dark' });

test('one', async ({ page }) => {
// ...
});

test('two', async ({ page }) => {
// ...
});
});

标签

你可以通过提供额外的详情来给组中的所有测试打标签。注意,每个标签必须以 @ 符号开头。

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

test.describe('two tagged tests', {
tag: '@smoke',
}, () => {
test('one', async ({ page }) => {
// ...
});

test('two', async ({ page }) => {
// ...
});
});

了解更多关于打标签的信息。

注解

你可以通过提供额外的详情来给组中的所有测试添加注解。

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

test.describe('two annotated tests', {
annotation: {
type: 'issue',
description: 'https://github.com/microsoft/playwright/issues/23180',
},
}, () => {
test('one', async ({ page }) => {
// ...
});

test('two', async ({ page }) => {
// ...
});
});

了解更多关于测试注解的信息。

参数


test.describe.configure

添加于: v1.10 test.test.describe.configure

配置封闭范围。可以在顶层或 describe 内部执行。无论配置是在测试声明之前还是之后运行,它都应用于整个范围。

在此处了解有关执行模式的更多信息:这里

用法

  • 并行运行测试。

    // Run all the tests in the file concurrently using parallel workers.
    test.describe.configure({ mode: 'parallel' });
    test('runs in parallel 1', async ({ page }) => {});
    test('runs in parallel 2', async ({ page }) => {});
  • 按顺序运行测试,独立重试每个失败的测试。

    这是默认模式。将其显式设置以覆盖使用 fullyParallel 的项目配置可能很有用。

    // Tests in this file run in order. Retries, if any, run independently.
    test.describe.configure({ mode: 'default' });
    test('runs first', async ({ page }) => {});
    test('runs second', async ({ page }) => {});
  • 串行运行测试,从头开始重试。如果其中一个串行测试失败,则所有后续测试都将被跳过。

    注意

    不推荐串行运行。通常最好使你的测试相互隔离,以便它们可以独立运行。

    // Annotate tests as inter-dependent.
    test.describe.configure({ mode: 'serial' });
    test('runs first', async ({ page }) => {});
    test('runs second', async ({ page }) => {});
  • 配置每个测试的重试次数和超时。

    // Each test in the file will be retried twice and have a timeout of 20 seconds.
    test.describe.configure({ retries: 2, timeout: 20_000 });
    test('runs first', async ({ page }) => {});
    test('runs second', async ({ page }) => {});
  • 并行运行多个 describe,但每个 describe 内部的测试按顺序运行。

    test.describe.configure({ mode: 'parallel' });

    test.describe('A, runs in parallel with B', () => {
    test.describe.configure({ mode: 'default' });
    test('in order A1', async ({ page }) => {});
    test('in order A2', async ({ page }) => {});
    });

    test.describe('B, runs in parallel with A', () => {
    test.describe.configure({ mode: 'default' });
    test('in order B1', async ({ page }) => {});
    test('in order B2', async ({ page }) => {});
    });

参数

  • options Object (可选)
    • mode "default" | "parallel" | "serial" (可选)#

      执行模式。在此处了解有关执行模式的更多信息:这里

    • retries number (可选)添加于: v1.28#

      每个测试的重试次数。

    • timeout number (可选)添加于: v1.28#

      每个测试的超时时间,单位为毫秒。会覆盖 testProject.timeouttestConfig.timeout


test.describe.fixme

添加于: v1.25 test.test.describe.fixme

声明一个测试组,类似于 test.describe()。此组中的测试被标记为“fixme”,不会被执行。

  • test.describe.fixme(title, callback)
  • test.describe.fixme(callback)
  • test.describe.fixme(title, details, callback)

用法

test.describe.fixme('broken tests that should be fixed', () => {
test('example', async ({ page }) => {
// This test will not run
});
});

你也可以省略标题。

test.describe.fixme(() => {
// ...
});

参数


test.describe.only

添加于: v1.10 test.test.describe.only

声明一个聚焦的测试组。如果存在聚焦的测试或套件,则只会运行它们,其他都不会运行。

  • test.describe.only(title, callback)
  • test.describe.only(callback)
  • test.describe.only(title, details, callback)

用法

test.describe.only('focused group', () => {
test('in the focused group', async ({ page }) => {
// This test will run
});
});
test('not in the focused group', async ({ page }) => {
// This test will not run
});

你也可以省略标题。

test.describe.only(() => {
// ...
});

参数


test.describe.skip

添加于: v1.10 test.test.describe.skip

声明一个跳过的测试组,类似于 test.describe()。跳过组中的测试永远不会运行。

  • test.describe.skip(title, callback)
  • test.describe.skip(title)
  • test.describe.skip(title, details, callback)

用法

test.describe.skip('skipped group', () => {
test('example', async ({ page }) => {
// This test will not run
});
});

你也可以省略标题。

test.describe.skip(() => {
// ...
});

参数


test.extend

添加于: v1.10 test.test.extend

通过定义可以在测试中使用的夹具和/或选项来扩展 test 对象。

用法

首先定义一个夹具和/或一个选项。

import { test as base } from '@playwright/test';
import { TodoPage } from './todo-page';

export type Options = { defaultItem: string };

// Extend basic test by providing a "defaultItem" option and a "todoPage" fixture.
export const test = base.extend<Options & { todoPage: TodoPage }>({
// Define an option and provide a default value.
// We can later override it in the config.
defaultItem: ['Do stuff', { option: true }],

// Define a fixture. Note that it can use built-in fixture "page"
// and a new option "defaultItem".
todoPage: async ({ page, defaultItem }, use) => {
const todoPage = new TodoPage(page);
await todoPage.goto();
await todoPage.addToDo(defaultItem);
await use(todoPage);
await todoPage.removeAll();
},
});

然后在测试中使用该夹具。

example.spec.ts
import { test } from './my-test';

test('test 1', async ({ todoPage }) => {
await todoPage.addToDo('my todo');
// ...
});

在配置文件中配置选项。

playwright.config.ts
import { defineConfig } from '@playwright/test';
import type { Options } from './my-test';

export default defineConfig<Options>({
projects: [
{
name: 'shopping',
use: { defaultItem: 'Buy milk' },
},
{
name: 'wellbeing',
use: { defaultItem: 'Exercise!' },
},
]
});

了解更多关于夹具参数化测试的信息。

参数

  • fixtures Object#

    一个包含夹具和/或选项的对象。了解更多关于夹具格式的信息。

返回值


test.fail

添加于: v1.10 test.test.fail

将测试标记为“应该失败”。Playwright 会运行此测试,并确保它确实失败。这对于文档很有用,可以表明某些功能在修复之前是损坏的。

声明一个“失败的”测试

  • test.fail(title, body)
  • test.fail(title, details, body)

在运行时将测试标记为“失败的”

  • test.fail(condition, description)
  • test.fail(callback, description)
  • test.fail()

用法

你可以将测试声明为失败的,这样 Playwright 就会确保它确实失败。

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

test.fail('not yet ready', async ({ page }) => {
// ...
});

如果你的测试在某些配置中失败,但在其他配置中不失败,你可以在测试体内部根据某些条件将测试标记为失败。在这种情况下,我们建议传递一个 description 参数。

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

test('fail in WebKit', async ({ page, browserName }) => {
test.fail(browserName === 'webkit', 'This feature is not implemented for Mac yet');
// ...
});

你可以使用单个 test.fail(callback, description) 调用,根据某些条件将文件或 test.describe() 组中的所有测试标记为“应该失败”。

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

test.fail(({ browserName }) => browserName === 'webkit', 'not implemented yet');

test('fail in WebKit 1', async ({ page }) => {
// ...
});
test('fail in WebKit 2', async ({ page }) => {
// ...
});

你也可以在测试体内部不带参数地调用 test.fail() 来始终将测试标记为失败。在这种情况下,我们建议改用 test.fail(title, body) 来声明失败的测试。

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

test('less readable', async ({ page }) => {
test.fail();
// ...
});

参数

  • title string (可选)添加于: v1.42#

    测试标题。

  • details Object (可选)添加于: v1.42#

    有关测试详情描述,请参阅 test()

  • body function(Fixtures, TestInfo) (可选)添加于: v1.42#

    测试体,接受一个或两个参数:一个包含夹具的对象和可选的 TestInfo

  • condition boolean (可选)#

    当条件为 true 时,测试被标记为“应该失败”。

  • callback function(Fixtures):boolean (可选)#

    一个函数,根据测试夹具返回是否标记为“应该失败”。当返回值为 true 时,测试或测试组被标记为“应该失败”。

  • description string (可选)#

    可选的描述,将反映在测试报告中。


test.fail.only

添加于: v1.49 test.test.fail.only

你可以使用 test.fail.only 来聚焦于一个预期会失败的特定测试。这在调试失败的测试或处理特定问题时特别有用。

声明一个聚焦的“失败的”测试

  • test.fail.only(title, body)
  • test.fail.only(title, details, body)

用法

你可以声明一个聚焦的失败测试,这样 Playwright 就只会运行这个测试并确保它确实失败。

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

test.fail.only('focused failing test', async ({ page }) => {
// This test is expected to fail
});
test('not in the focused group', async ({ page }) => {
// This test will not run
});

参数


test.fixme

添加于: v1.10 test.test.fixme

将测试标记为“fixme”,表示有待修复。Playwright 在遇到 test.fixme() 调用后将不再运行该测试。

声明一个“fixme”测试

  • test.fixme(title, body)
  • test.fixme(title, details, body)

在运行时将测试标记为“fixme”

  • test.fixme(condition, description)
  • test.fixme(callback, description)
  • test.fixme()

用法

你可以将测试声明为待修复,Playwright 将不会运行它。

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

test.fixme('to be fixed', async ({ page }) => {
// ...
});

如果你的测试在某些配置中需要修复,但在其他配置中不需要,你可以在测试体内部根据某些条件将测试标记为“fixme”。在这种情况下,我们建议传递一个 description 参数。Playwright 会运行测试,但在遇到 test.fixme 调用后立即中止。

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

test('to be fixed in Safari', async ({ page, browserName }) => {
test.fixme(browserName === 'webkit', 'This feature breaks in Safari for some reason');
// ...
});

你可以使用单个 test.fixme(callback, description) 调用,根据某些条件将文件或 test.describe() 组中的所有测试标记为“fixme”。

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

test.fixme(({ browserName }) => browserName === 'webkit', 'Should figure out the issue');

test('to be fixed in Safari 1', async ({ page }) => {
// ...
});
test('to be fixed in Safari 2', async ({ page }) => {
// ...
});

你也可以在测试体内部不带参数地调用 test.fixme() 来始终将测试标记为“fixme”。我们建议改用 test.fixme(title, body) 来声明“fixme”测试。

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

test('less readable', async ({ page }) => {
test.fixme();
// ...
});

参数

  • title string (可选)#

    测试标题。

  • details Object (可选)添加于: v1.42#

    有关测试详情描述,请参阅 test()

  • body function(Fixtures, TestInfo) (可选)#

    测试体,接受一个或两个参数:一个包含夹具的对象和可选的 TestInfo

  • condition boolean (可选)#

    当条件为 true 时,测试被标记为“应该失败”。

  • callback function(Fixtures):boolean (可选)#

    一个函数,根据测试夹具返回是否标记为“应该失败”。当返回值为 true 时,测试或测试组被标记为“应该失败”。

  • description string (可选)#

    可选的描述,将反映在测试报告中。


test.info

添加于: v1.10 test.test.info

返回当前正在运行的测试的信息。此方法只能在测试执行期间调用,否则会抛出错误。

用法

test('example test', async ({ page }) => {
// ...
await test.info().attach('screenshot', {
body: await page.screenshot(),
contentType: 'image/png',
});
});

返回值


test.only

添加于: v1.10 test.test.only

声明一个聚焦的测试。如果存在聚焦的测试或套件,则只会运行它们,其他都不会运行。

  • test.only(title, body)
  • test.only(title, details, body)

用法

test.only('focus this test', async ({ page }) => {
// Run only focused tests in the entire project.
});

参数


test.setTimeout

添加于: v1.10 test.test.setTimeout

更改测试的超时时间。零表示没有超时。了解更多关于各种超时的信息。

当前正在运行的测试的超时时间可通过 testInfo.timeout 获取。

用法

  • 更改测试超时时间。

    test('very slow test', async ({ page }) => {
    test.setTimeout(120000);
    // ...
    });
  • 从一个缓慢的 beforeEach 钩子中更改超时时间。注意,这会影响与 beforeEach 钩子共享的测试超时时间。

    test.beforeEach(async ({ page }, testInfo) => {
    // Extend timeout for all tests running this hook by 30 seconds.
    test.setTimeout(testInfo.timeout + 30000);
    });
  • 更改 beforeAllafterAll 钩子的超时。注意这影响的是钩子的超时,而不是测试的超时。

    test.beforeAll(async () => {
    // Set timeout for this hook.
    test.setTimeout(60000);
    });
  • 更改 test.describe() 组中所有测试的超时。

    test.describe('group', () => {
    // Applies to all tests in this group.
    test.describe.configure({ timeout: 60000 });

    test('test one', async () => { /* ... */ });
    test('test two', async () => { /* ... */ });
    test('test three', async () => { /* ... */ });
    });

参数

  • timeout number#

    超时时间(毫秒)。


test.skip

添加于: v1.10 test.test.skip

跳过测试。Playwright 不会运行 `test.skip()` 调用之后的测试。

跳过的测试不应该运行。如果你打算修复该测试,请改用 test.fixme()

声明要跳过的测试

  • test.skip(title, body)
  • test.skip(title, details, body)

在运行时跳过测试

  • test.skip(condition, description)
  • test.skip(callback, description)
  • test.skip()

用法

你可以声明一个要跳过的测试,Playwright 将不会运行它。

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

test.skip('never run', async ({ page }) => {
// ...
});

如果你的测试在某些配置下应该跳过,而不是全部配置下都跳过,你可以在测试体内根据某些条件来跳过测试。在这种情况下,我们建议传递 `description` 参数。Playwright 会运行该测试,但在 `test.skip` 调用后立即中止它。

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

test('Safari-only test', async ({ page, browserName }) => {
test.skip(browserName !== 'webkit', 'This feature is Safari-only');
// ...
});

你可以通过调用一次 `test.skip(callback, description)`,根据某些条件跳过文件或 test.describe() 组中的所有测试。

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

test.skip(({ browserName }) => browserName !== 'webkit', 'Safari-only');

test('Safari-only test 1', async ({ page }) => {
// ...
});
test('Safari-only test 2', async ({ page }) => {
// ...
});

你也可以在测试体内不带参数地调用 `test.skip()` 来始终将测试标记为失败。我们建议改用 `test.skip(title, body)`。

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

test('less readable', async ({ page }) => {
test.skip();
// ...
});

参数

  • title string (可选)#

    测试标题。

  • details Object (可选)添加于: v1.42#

    有关测试详情描述,请参阅 test()

  • body function(Fixtures, TestInfo) (可选)#

    测试体,接受一个或两个参数:一个包含夹具的对象和可选的 TestInfo

  • condition boolean (可选)#

    当条件为 true 时,测试被标记为“应该失败”。

  • callback function(Fixtures):boolean (可选)#

    一个函数,根据测试夹具返回是否标记为“应该失败”。当返回值为 true 时,测试或测试组被标记为“应该失败”。

  • description string (可选)#

    可选的描述,将反映在测试报告中。


test.slow

添加于: v1.10 test.test.slow

将测试标记为“慢速”。慢速测试将获得默认超时时间的三倍。

请注意,test.slow() 不能用于 `beforeAll` 或 `afterAll` 钩子。请改用 test.setTimeout()

  • test.slow()
  • test.slow(condition, description)
  • test.slow(callback, description)

用法

你可以在测试体内调用 `test.slow()` 来将测试标记为慢速。

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

test('slow test', async ({ page }) => {
test.slow();
// ...
});

如果你的测试在某些配置下慢速,而不是全部配置下都慢速,你可以根据条件将其标记为慢速。在这种情况下,我们建议传递 `description` 参数。

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

test('slow in Safari', async ({ page, browserName }) => {
test.slow(browserName === 'webkit', 'This feature is slow in Safari');
// ...
});

你可以通过传递一个回调函数,根据某些条件将文件或 test.describe() 组中的所有测试标记为“慢速”。

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

test.slow(({ browserName }) => browserName === 'webkit', 'all tests are slow in Safari');

test('slow in Safari 1', async ({ page }) => {
// ...
});
test('fail in Safari 2', async ({ page }) => {
// ...
});

参数

  • condition boolean (可选)#

    当条件为 `true` 时,测试被标记为“慢速”。

  • callback function(Fixtures):boolean (可选)#

    一个函数,根据测试夹具(fixtures)返回是否标记为“慢速”。当返回值为 `true` 时,测试或测试集被标记为“慢速”。

  • description string (可选)#

    可选的描述,将反映在测试报告中。


test.step

添加于: v1.10 test.test.step

声明一个在报告中显示的测试步骤。

用法

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

test('test', async ({ page }) => {
await test.step('Log in', async () => {
// ...
});

await test.step('Outer step', async () => {
// ...
// You can nest steps inside each other.
await test.step('Inner step', async () => {
// ...
});
});
});

参数

  • title string#

    步骤名称。

  • body function(TestStepInfo):Promise<Object>#

    步骤体。

  • options Object (可选)

    • box boolean (可选)添加于: v1.39#

      是否在报告中将步骤框起来。默认为 `false`。当步骤被框起来时,从步骤内部抛出的错误会指向步骤的调用位置。详见下文。

    • location Location (可选)添加于: v1.48#

      指定在测试报告和跟踪查看器中显示的自定义步骤位置。默认情况下,显示 test.step() 调用的位置。

    • timeout number (可选)添加于: v1.50#

      允许步骤完成的最大时间(毫秒)。如果步骤未在指定时间内完成,test.step() 方法将抛出 TimeoutError。默认为 `0`(无超时)。

返回值

详情

该方法返回步骤回调函数返回的值。

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

test('test', async ({ page }) => {
const user = await test.step('Log in', async () => {
// ...
return 'john';
});
expect(user).toBe('john');
});

装饰器

你可以使用 TypeScript 方法装饰器将一个方法转换为一个步骤。每次调用被装饰的方法都会在报告中显示为一个步骤。

function step(target: Function, context: ClassMethodDecoratorContext) {
return function replacementMethod(...args: any) {
const name = this.constructor.name + '.' + (context.name as string);
return test.step(name, async () => {
return await target.call(this, ...args);
});
};
}

class LoginPage {
constructor(readonly page: Page) {}

@step
async login() {
const account = { username: 'Alice', password: 's3cr3t' };
await this.page.getByLabel('Username or email address').fill(account.username);
await this.page.getByLabel('Password').fill(account.password);
await this.page.getByRole('button', { name: 'Sign in' }).click();
await expect(this.page.getByRole('button', { name: 'View profile and more' })).toBeVisible();
}
}

test('example', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.login();
});

装箱

当步骤内部出现失败时,你通常会看到错误指向失败的具体动作。例如,考虑以下登录步骤

async function login(page) {
await test.step('login', async () => {
const account = { username: 'Alice', password: 's3cr3t' };
await page.getByLabel('Username or email address').fill(account.username);
await page.getByLabel('Password').fill(account.password);
await page.getByRole('button', { name: 'Sign in' }).click();
await expect(page.getByRole('button', { name: 'View profile and more' })).toBeVisible();
});
}

test('example', async ({ page }) => {
await page.goto('https://github.com/login');
await login(page);
});
Error: Timed out 5000ms waiting for expect(locator).toBeVisible()
... error details omitted ...

8 | await page.getByRole('button', { name: 'Sign in' }).click();
> 9 | await expect(page.getByRole('button', { name: 'View profile and more' })).toBeVisible();
| ^
10 | });

如上所示,测试可能会因为指向步骤内部的错误而失败。如果你希望错误突出显示“登录”步骤而不是其内部细节,请使用 `box` 选项。装箱步骤内部的错误会指向步骤的调用位置。

async function login(page) {
await test.step('login', async () => {
// ...
}, { box: true }); // Note the "box" option here.
}
Error: Timed out 5000ms waiting for expect(locator).toBeVisible()
... error details omitted ...

14 | await page.goto('https://github.com/login');
> 15 | await login(page);
| ^
16 | });

你也可以为装箱步骤创建一个 TypeScript 装饰器,类似于上面常规的步骤装饰器

function boxedStep(target: Function, context: ClassMethodDecoratorContext) {
return function replacementMethod(...args: any) {
const name = this.constructor.name + '.' + (context.name as string);
return test.step(name, async () => {
return await target.call(this, ...args);
}, { box: true }); // Note the "box" option here.
};
}

class LoginPage {
constructor(readonly page: Page) {}

@boxedStep
async login() {
// ....
}
}

test('example', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.login(); // <-- Error will be reported on this line.
});

test.step.skip

添加于: v1.50 test.test.step.skip

将测试步骤标记为“跳过”以暂时禁用其执行,对于当前失败并计划近期修复的步骤很有用。Playwright 将不会运行该步骤。另请参阅 testStepInfo.skip()

我们建议改用 testStepInfo.skip()

用法

你可以声明一个跳过的步骤,Playwright 将不会运行它。

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

test('my test', async ({ page }) => {
// ...
await test.step.skip('not yet ready', async () => {
// ...
});
});

参数

  • title string#

    步骤名称。

  • body function():Promise<Object>#

    步骤体。

  • options Object (可选)

    • box boolean (可选)#

      是否在报告中将步骤框起来。默认为 `false`。当步骤被框起来时,从步骤内部抛出的错误会指向步骤的调用位置。详见下文。

    • location Location (可选)#

      指定在测试报告和跟踪查看器中显示的自定义步骤位置。默认情况下,显示 test.step() 调用的位置。

    • timeout number (可选)#

      步骤完成的最大时间(毫秒)。默认为 `0`(无超时)。

返回值


test.use

添加于: v1.10 test.test.use

指定在单个测试文件或 test.describe() 组中使用的选项或夹具(fixtures)。最常用于设置选项,例如设置 `locale` 来配置 `context` 夹具(fixture)。

用法

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

test.use({ locale: 'en-US' });

test('test with locale', async ({ page }) => {
// Default context and page have locale as specified
});

参数

详情

test.use 可以在全局范围或 test.describe 内部调用。在 beforeEachbeforeAll 中调用它是错误的。

也可以通过提供一个函数来覆盖夹具(fixture)。

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

test.use({
locale: async ({}, use) => {
// Read locale from some configuration file.
const locale = await fs.promises.readFile('test-locale', 'utf-8');
await use(locale);
},
});

test('test with locale', async ({ page }) => {
// Default context and page have locale as specified
});

属性

test.expect

添加于: v1.10 test.test.expect

expect 函数可用于创建测试断言。了解更多关于测试断言的信息。

用法

test('example', async ({ page }) => {
await test.expect(page).toHaveTitle('Title');
});

类型


已弃用

test.describe.parallel

添加于: v1.10 test.test.describe.parallel
不推荐使用

有关配置执行模式的首选方法,请参阅 test.describe.configure()

声明一组可以并行运行的测试。默认情况下,单个测试文件中的测试是依次运行的,但使用 test.describe.parallel() 可以让它们并行运行。

  • test.describe.parallel(title, callback)
  • test.describe.parallel(callback)
  • test.describe.parallel(title, details, callback)

用法

test.describe.parallel('group', () => {
test('runs in parallel 1', async ({ page }) => {});
test('runs in parallel 2', async ({ page }) => {});
});

请注意,并行测试在单独的进程中执行,不能共享任何状态或全局变量。每个并行测试都会执行所有相关的钩子。

你也可以省略标题。

test.describe.parallel(() => {
// ...
});

参数


test.describe.parallel.only

添加于: v1.10 test.test.describe.parallel.only
不推荐使用

有关配置执行模式的首选方法,请参阅 test.describe.configure()

声明一组可以并行运行的、被聚焦的测试。这类似于 test.describe.parallel(),但它会聚焦此组。如果存在一些聚焦的测试或套件,将只运行它们,而不是其他测试。

  • test.describe.parallel.only(title, callback)
  • test.describe.parallel.only(callback)
  • test.describe.parallel.only(title, details, callback)

用法

test.describe.parallel.only('group', () => {
test('runs in parallel 1', async ({ page }) => {});
test('runs in parallel 2', async ({ page }) => {});
});

你也可以省略标题。

test.describe.parallel.only(() => {
// ...
});

参数


test.describe.serial

添加于: v1.10 test.test.describe.serial
不推荐使用

有关配置执行模式的首选方法,请参阅 test.describe.configure()

声明一组应该始终串行运行的测试。如果其中一个测试失败,所有后续测试都将被跳过。组中的所有测试会一起重试。

注意

不推荐使用串行。通常最好让你的测试相互隔离,这样它们可以独立运行。

  • test.describe.serial(title, callback)
  • test.describe.serial(title)
  • test.describe.serial(title, details, callback)

用法

test.describe.serial('group', () => {
test('runs first', async ({ page }) => {});
test('runs second', async ({ page }) => {});
});

你也可以省略标题。

test.describe.serial(() => {
// ...
});

参数


test.describe.serial.only

添加于: v1.10 test.test.describe.serial.only
不推荐使用

有关配置执行模式的首选方法,请参阅 test.describe.configure()

声明一组应该始终串行运行的、被聚焦的测试。如果其中一个测试失败,所有后续测试都将被跳过。组中的所有测试会一起重试。如果存在一些聚焦的测试或套件,将只运行它们,而不是其他测试。

注意

不推荐使用串行。通常最好让你的测试相互隔离,这样它们可以独立运行。

  • test.describe.serial.only(title, callback)
  • test.describe.serial.only(title)
  • test.describe.serial.only(title, details, callback)

用法

test.describe.serial.only('group', () => {
test('runs first', async ({ page }) => {
});
test('runs second', async ({ page }) => {
});
});

你也可以省略标题。

test.describe.serial.only(() => {
// ...
});

参数