Playwright Test
Playwright Test 提供了 test
函数来声明测试用例,以及 expect
函数来编写断言。
import { test, expect } from '@playwright/test';
test('basic test', async ({ page }) => {
await page.goto('https://playwright.dev/');
const name = await page.innerText('.navbar__title');
expect(name).toBe('Playwright');
});
方法
test
添加于: v1.10声明一个测试用例。
test(title, body)
test(title, details, body)
用法
import { test, expect } from '@playwright/test';
test('基础测试', async ({ page }) => {
await page.goto('https://playwright.dev/');
// ...
});
标签
您可以通过提供额外的测试详情来标记测试。或者,您也可以在测试标题中包含标签。注意每个标签必须以 @
符号开头。
import { test, expect } from '@playwright/test';
test('基础测试', {
tag: '@smoke',
}, async ({ page }) => {
await page.goto('https://playwright.dev/');
// ...
});
test('另一个测试 @smoke', async ({ page }) => {
await page.goto('https://playwright.dev/');
// ...
});
测试标签会显示在测试报告中,并且可以通过 TestCase.tags
属性供自定义报告器使用。
您还可以在执行测试时按标签筛选测试:
- 在命令行中;
- 在配置文件中使用 testConfig.grep 和 testProject.grep;
了解更多关于标签标记的信息。
注解
您可以通过提供额外的测试详情来注解测试。
import { test, expect } from '@playwright/test';
test('基础测试', {
annotation: {
type: 'issue',
description: 'https://github.com/microsoft/playwright/issues/23180',
},
}, async ({ page }) => {
await page.goto('https://playwright.dev/');
// ...
});
测试注解会显示在测试报告中,并且可以通过 TestCase.annotations
属性供自定义报告器使用。
您还可以通过操作 testInfo.annotations 在运行时添加注解。
了解更多关于测试注解的信息。
参数
-
测试标题。
-
details
Object (可选) 添加于: v1.42#额外的测试详情。
-
body
function(Fixtures, TestInfo)#测试体,接收一个或两个参数:包含 fixtures 的对象和可选的 TestInfo。
test.afterAll
添加于: v1.10声明一个 afterAll
钩子,该钩子会在所有测试完成后每个工作进程执行一次。
当在测试文件作用域内调用时,会在文件中的所有测试完成后运行。当在 test.describe() 分组内调用时,会在该分组的所有测试完成后运行。
用法
test.afterAll(async () => {
console.log('测试完成');
// ...
});
或者,你可以声明一个带标题的钩子。
test.afterAll('清理', async () => {
console.log('测试完成');
// ...
});
参数
详细信息
当添加多个 afterAll
钩子时,它们会按照注册顺序执行。
注意:当测试失败时工作进程会重启,afterAll
钩子会在新的工作进程中再次运行。了解更多关于工作进程和失败的信息。
即使某些钩子执行失败,Playwright 也会继续运行所有适用的钩子。
test.afterAll(hookFunction)
test.afterAll(title, hookFunction)
test.afterEach
添加于: v1.10声明一个在每个测试执行后运行的 afterEach
钩子函数。
当在测试文件作用域内调用时,会在该文件的每个测试后运行。当在 test.describe() 分组内调用时,会在该分组的每个测试后运行。
你可以访问与测试体相同的所有 Fixtures,以及提供大量有用信息的 TestInfo 对象。例如,你可以检查测试是否成功或失败。
test.afterEach(hookFunction)
test.afterEach(title, hookFunction)
用法
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 }) => {
// ...
});
或者,你可以带标题声明一个钩子。
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声明一个在所有测试之前执行的 beforeAll
钩子,每个工作进程只执行一次。
当在测试文件作用域内调用时,会在该文件所有测试之前运行。当在 test.describe() 分组内调用时,会在该分组所有测试之前运行。
可以使用 test.afterAll() 来清理在 beforeAll
中设置的资源。
test.beforeAll(hookFunction)
test.beforeAll(title, hookFunction)
用法
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 }) => {
// ...
});
也可以带标题声明钩子。
test.beforeAll('Setup', async () => {
console.log('Before tests');
});
参数
详细信息
当添加多个 beforeAll
钩子时,它们会按照注册顺序依次执行。
注意:当测试失败时工作进程会重启,beforeAll
钩子会在新的工作进程中再次运行。了解更多关于工作进程与失败的信息。
即使某些钩子执行失败,Playwright也会继续运行所有适用的钩子。
test.beforeEach
添加于: v1.10声明一个在每个测试之前执行的 beforeEach
钩子函数。
当在测试文件作用域内调用时,会在该文件的每个测试前运行。当在 test.describe() 分组内调用时,会在该分组的每个测试前运行。
你可以访问与测试体相同的所有 Fixtures,以及提供大量有用信息的 TestInfo 对象。例如,你可以在测试开始前导航到某个页面。
可以使用 test.afterEach() 来清理在 beforeEach
中设置的任何资源。
test.beforeEach(hookFunction)
test.beforeEach(title, hookFunction)
用法
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/');
});
或者,你可以带标题声明一个钩子。
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.describe(title, callback)
test.describe(callback)
test.describe(title, details, callback)
用法
可以通过标题声明一组测试用例。该标题将作为每个测试用例标题的一部分显示在测试报告中。
test.describe('两个测试', () => {
test('第一个', async ({ page }) => {
// ...
});
test('第二个', async ({ page }) => {
// ...
});
});
匿名分组
也可以声明不带标题的测试组。这对于使用 test.use() 为一组测试提供共同选项非常方便。
test.describe(() => {
test.use({ colorScheme: 'dark' });
test('第一个', async ({ page }) => {
// ...
});
test('第二个', async ({ page }) => {
// ...
});
});
标签
可以通过提供额外详情为组内所有测试添加标签。注意每个标签必须以 @
符号开头。
import { test, expect } from '@playwright/test';
test.describe('两个带标签的测试', {
tag: '@smoke',
}, () => {
test('第一个', async ({ page }) => {
// ...
});
test('第二个', async ({ page }) => {
// ...
});
});
了解更多关于标签的信息。
注解
可以通过提供额外详情为组内所有测试添加注解。
import { test, expect } from '@playwright/test';
test.describe('两个带注解的测试', {
annotation: {
type: 'issue',
description: 'https://github.com/microsoft/playwright/issues/23180',
},
}, () => {
test('第一个', async ({ page }) => {
// ...
});
test('第二个', async ({ page }) => {
// ...
});
});
了解更多关于测试注解的信息。
参数
-
分组标题。
-
details
Object (可选) 添加于: v1.42#组内所有测试的额外详情。
-
调用 test.describe() 时立即运行的回调函数。在此回调中声明的任何测试都将属于该组。
test.describe.configure
添加于: v1.10配置当前作用域。可以在顶层或 describe 内部执行。配置会应用于整个作用域,无论它是在测试声明之前还是之后运行。
了解更多关于执行模式的信息。
用法
-
并行运行测试
// 使用并行工作线程并发运行文件中的所有测试
test.describe.configure({ mode: 'parallel' });
test('并行运行 1', async ({ page }) => {});
test('并行运行 2', async ({ page }) => {}); -
按顺序运行测试,每个失败测试独立重试
这是默认模式。显式设置它可以覆盖使用
fullyParallel
的项目配置。// 文件中的测试按顺序运行。重试(如果有)独立运行
test.describe.configure({ mode: 'default' });
test('首先运行', async ({ page }) => {});
test('其次运行', async ({ page }) => {}); -
串行运行测试,从开始处重试。如果其中一个串行测试失败,所有后续测试都会被跳过。
:::注意
不建议使用串行模式。通常更好的做法是让测试相互隔离,以便可以独立运行。 :::
// 将测试标记为相互依赖
test.describe.configure({ mode: 'serial' });
test('首先运行', async ({ page }) => {});
test('其次运行', async ({ page }) => {}); -
为每个测试配置重试次数和超时时间
// 文件中的每个测试将重试两次,超时时间为20秒
test.describe.configure({ retries: 2, timeout: 20_000 });
test('首先运行', async ({ page }) => {});
test('其次运行', async ({ page }) => {}); -
并行运行多个 describe,但每个 describe 内的测试按顺序运行
test.describe.configure({ mode: 'parallel' });
test.describe('A, 与 B 并行运行', () => {
test.describe.configure({ mode: 'default' });
test('按顺序 A1', async ({ page }) => {});
test('按顺序 A2', async ({ page }) => {});
});
test.describe('B, 与 A 并行运行', () => {
test.describe.configure({ mode: 'default' });
test('按顺序 B1', async ({ page }) => {});
test('按顺序 B2', async ({ page }) => {});
});
参数
options
Object (可选)-
mode
"default" | "parallel" | "serial" (可选)#执行模式。了解更多关于执行模式的信息。
-
retries
number (可选) 添加于: v1.28#每个测试的重试次数。
-
timeout
number (可选) 添加于: v1.28#每个测试的超时时间(毫秒)。覆盖 testProject.timeout 和 testConfig.timeout。
-
test.describe.fixme
添加于: v1.25声明一个测试组,类似于 test.describe()。该组中的测试会被标记为"待修复"且不会执行。
test.describe.fixme(title, callback)
test.describe.fixme(callback)
test.describe.fixme(title, details, callback)
用法
test.describe.fixme('需要修复的损坏测试', () => {
test('示例', async ({ page }) => {
// 这个测试不会运行
});
});
也可以省略标题。
test.describe.fixme(() => {
// ...
});
参数
-
组标题。
-
details
Object (可选) 添加于: v1.42#详情描述请参见 test.describe()。
-
调用 test.describe.fixme() 时立即运行的回调函数。在此回调中添加的任何测试都将属于该组,并且不会被执行。
test.describe.only
添加于: v1.10声明一个聚焦测试组。如果存在某些聚焦测试或套件,将只运行这些聚焦项而忽略其他内容。
test.describe.only(title, callback)
test.describe.only(callback)
test.describe.only(title, details, callback)
用法
test.describe.only('聚焦组', () => {
test('在聚焦组内', async ({ page }) => {
// 这个测试会运行
});
});
test('不在聚焦组内', async ({ page }) => {
// 这个测试不会运行
});
也可以省略标题。
test.describe.only(() => {
// ...
});
参数
-
组标题。
-
details
Object (可选) 添加于: v1.42#详细描述请参见 test.describe()。
-
调用 test.describe.only() 时立即执行的回调函数。在此回调中添加的任何测试都将属于该组。
test.describe.skip
添加于: v1.10声明一个跳过的测试组,类似于 test.describe()。跳过组中的测试永远不会运行。
test.describe.skip(title, callback)
test.describe.skip(title)
test.describe.skip(title, details, callback)
用法
test.describe.skip('跳过的测试组', () => {
test('示例', async ({ page }) => {
// 这个测试不会运行
});
});
也可以省略标题。
test.describe.skip(() => {
// ...
});
参数
-
组标题。
-
details
Object (可选) 添加于: v1.42#详情描述请参见 test.describe()。
-
调用 test.describe.skip() 时立即运行的回调函数。在此回调中添加的任何测试都将属于该组,并且不会运行。
test.extend
添加于: v1.10通过定义可以在测试中使用的 fixtures 和/或选项来扩展 test
对象。
用法
首先定义一个 fixture 和/或选项。
- TypeScript
- JavaScript
import { test as base } from '@playwright/test';
import { TodoPage } from './todo-page';
export type Options = { defaultItem: string };
// 通过提供 "defaultItem" 选项和 "todoPage" fixture 来扩展基础测试
export const test = base.extend<Options & { todoPage: TodoPage }>({
// 定义一个选项并提供默认值
// 稍后可以在配置中覆盖它
defaultItem: ['Do stuff', { option: true }],
// 定义一个 fixture。注意它可以使用内置 fixture "page"
// 和新选项 "defaultItem"
todoPage: async ({ page, defaultItem }, use) => {
const todoPage = new TodoPage(page);
await todoPage.goto();
await todoPage.addToDo(defaultItem);
await use(todoPage);
await todoPage.removeAll();
},
});
const base = require('@playwright/test');
const { TodoPage } = require('./todo-page');
// 通过提供 "defaultItem" 选项和 "todoPage" fixture 来扩展基础测试
exports.test = base.test.extend({
// 定义一个选项并提供默认值
// 稍后可以在配置中覆盖它
defaultItem: ['Do stuff', { option: true }],
// 定义一个 fixture。注意它可以使用内置 fixture "page"
// 和新选项 "defaultItem"
todoPage: async ({ page, defaultItem }, use) => {
const todoPage = new TodoPage(page);
await todoPage.goto();
await todoPage.addToDo(defaultItem);
await use(todoPage);
await todoPage.removeAll();
},
});
然后在测试中使用该 fixture。
import { test } from './my-test';
test('test 1', async ({ todoPage }) => {
await todoPage.addToDo('my todo');
// ...
});
在配置文件中配置选项。
- TypeScript
- JavaScript
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!' },
},
]
});
// @ts-check
module.exports = defineConfig({
projects: [
{
name: 'shopping',
use: { defaultItem: 'Buy milk' },
},
{
name: 'wellbeing',
use: { defaultItem: 'Exercise!' },
},
]
});
参数
-
包含 fixtures 和/或选项的对象。了解更多关于 fixtures 格式。
返回值
test.fail
Added in: v1.10将测试标记为"预期失败"。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 (可选) Added in: v1.42#测试标题。
-
details
Object (可选) Added in: v1.42#详见 test() 的测试详情描述。
-
body
function(Fixtures, TestInfo) (可选) Added in: v1.42#测试体函数,接收一个或两个参数:包含 fixtures 的对象和可选的 TestInfo。
-
当条件为
true
时,测试被标记为"预期失败"。 -
callback
function(Fixtures):boolean (可选)#根据测试 fixtures 返回是否标记为"预期失败"的函数。当返回值为
true
时,测试或测试组被标记为"预期失败"。 -
可选描述,会在测试报告中显示。
test.fail.only
添加于: v1.49你可以使用 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 }) => {
// 这个测试预期会失败
});
test('not in the focused group', async ({ page }) => {
// 这个测试不会运行
});
参数
-
测试标题。
-
查看 test.describe() 了解测试详情描述。
-
body
function(Fixtures, TestInfo) (可选)#测试体,接收一个或两个参数:包含 fixtures 的对象和可选的 TestInfo。
test.fixme
添加于: v1.10将测试标记为"待修复",表示有意修复它。Playwright 不会运行 test.fixme()
调用之后的测试。
声明"待修复"测试的方式:
test.fixme(title, body)
test.fixme(title, details, body)
在运行时将测试标注为"待修复":
test.fixme(condition, description)
test.fixme(callback, description)
test.fixme()
用法
你可以声明一个测试需要修复,Playwright 将不会运行它。
import { test, expect } from '@playwright/test';
test.fixme('待修复', async ({ page }) => {
// ...
});
如果你的测试在某些配置下需要修复,但不是所有配置,你可以根据条件在测试体内标记为"待修复"。这种情况下我们建议传递 description
参数。Playwright 会运行测试,但在 test.fixme
调用后立即中止。
import { test, expect } from '@playwright/test';
test('在 Safari 中待修复', async ({ page, browserName }) => {
test.fixme(browserName === 'webkit', '由于某些原因此功能在 Safari 中会出错');
// ...
});
你可以基于某个条件,通过单个 test.fixme(callback, description)
调用将文件中的所有测试或 test.describe() 分组标记为"待修复"。
import { test, expect } from '@playwright/test';
test.fixme(({ browserName }) => browserName === 'webkit', '需要解决此问题');
test('在 Safari 中待修复 1', async ({ page }) => {
// ...
});
test('在 Safari 中待修复 2', async ({ page }) => {
// ...
});
你也可以在测试体内不带参数调用 test.fixme()
来始终将测试标记为失败。我们建议使用 test.fixme(title, body)
替代。
import { test, expect } from '@playwright/test';
test('可读性较差', async ({ page }) => {
test.fixme();
// ...
});
参数
-
测试标题。
-
details
Object (可选) 添加于: v1.42#参见 test() 了解测试详情描述。
-
body
function(Fixtures, TestInfo) (可选)#测试体,接受一个或两个参数:包含 fixtures 的对象和可选的 TestInfo。
-
当条件为
true
时,测试被标记为"应该失败"。 -
callback
function(Fixtures):boolean (可选)#根据测试 fixtures 返回是否标记为"应该失败"的函数。当返回值为
true
时,测试或测试组被标记为"应该失败"。 -
可选描述,将在测试报告中反映。
test.info
添加于: v1.10返回当前运行测试的相关信息。此方法只能在测试执行期间调用,否则会抛出异常。
用法
test('示例测试', async ({ page }) => {
// ...
await test.info().attach('截图', {
body: await page.screenshot(),
contentType: 'image/png',
});
});
返回值
test.only
添加于: v1.10声明一个聚焦测试。如果存在多个聚焦测试或测试套件,将只运行这些聚焦测试而忽略其他测试。
test.only(title, body)
test.only(title, details, body)
用法
test.only('focus this test', async ({ page }) => {
// 在整个项目中只运行聚焦测试
});
参数
-
测试标题。
-
details
Object (可选) 添加于: v1.42#详情描述请参见 test()。
-
body
function(Fixtures, TestInfo)#测试函数体,接收一个或两个参数:包含 fixtures 的对象和可选的 TestInfo。
test.setTimeout
添加于: v1.10修改测试的超时时间。零表示无超时限制。了解更多关于各种超时设置。
当前运行测试的超时时间可通过 testInfo.timeout 获取。
用法
-
修改单个测试的超时时间
test('very slow test', async ({ page }) => {
test.setTimeout(120000);
// ...
}); -
在缓慢的
beforeEach
钩子中修改超时时间。注意这会影响到与beforeEach
钩子共享的测试超时时间。test.beforeEach(async ({ page }, testInfo) => {
// 为所有运行此钩子的测试增加30秒超时时间
test.setTimeout(testInfo.timeout + 30000);
}); -
修改
beforeAll
或afterAll
钩子的超时时间。注意这影响的是钩子本身的超时时间,而非测试超时时间。test.beforeAll(async () => {
// 设置此钩子的超时时间
test.setTimeout(60000);
}); -
修改 test.describe() 分组中所有测试的超时时间
test.describe('group', () => {
// 应用于此分组中的所有测试
test.describe.configure({ timeout: 60000 });
test('test one', async () => { /* ... */ });
test('test two', async () => { /* ... */ });
test('test three', async () => { /* ... */ });
});
参数
test.skip
添加于: v1.10跳过测试。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();
// ...
});
参数
-
测试标题。
-
details
Object (可选) 添加于: v1.42#详见 test() 的测试详情描述。
-
body
function(Fixtures, TestInfo) (可选)#测试体函数,接收一个或两个参数:包含 fixtures 的对象和可选的 TestInfo。
-
当条件为
true
时,测试标记为"应跳过"。 -
callback
function(Fixtures):boolean (可选)#基于测试 fixtures 返回是否标记为"应跳过"的函数。当返回值为
true
时,测试或测试组会被标记为"应跳过"。 -
可选描述,会在测试报告中显示。
test.slow
添加于: v1.10将测试标记为"慢速测试"。慢速测试将获得三倍的默认超时时间。
注意 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 }) => {
// ...
});
参数
-
当条件为
true
时,测试被标记为"慢速"。 -
callback
function(Fixtures):boolean (可选)#一个基于测试 fixtures 返回是否标记为"慢速"的函数。当返回值为
true
时,测试或测试组被标记为"慢速"。 -
可选描述,将在测试报告中显示。
test.step
添加于: v1.10声明一个会在报告中显示的测试步骤。
用法
import { test, expect } from '@playwright/test';
test('test', async ({ page }) => {
await test.step('登录', async () => {
// ...
});
await test.step('外部步骤', async () => {
// ...
// 可以嵌套步骤
await test.step('内部步骤', async () => {
// ...
});
});
});
参数
-
步骤名称。
-
body
function(TestStepInfo):Promise<Object>#步骤执行体。
-
options
Object (可选)-
是否在报告中框选该步骤。默认为
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('登录', 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 | });
如上所示,测试可能会失败并显示指向步骤内部的错误。如果希望错误高亮显示"login"步骤而不是其内部操作,可以使用 box
选项。框选步骤内部的错误会指向步骤调用处。
async function login(page) {
await test.step('login', async () => {
// ...
}, { box: true }); // 注意这里的 "box" 选项
}
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 }); // 注意这里的 "box" 选项
};
}
class LoginPage {
constructor(readonly page: Page) {}
@boxedStep
async login() {
// ....
}
}
test('example', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.login(); // <-- 错误会报告在这一行
});
test.step.skip
添加于: v1.50将测试步骤标记为"跳过"以临时禁用其执行,适用于当前失败并计划近期修复的步骤。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 () => {
// ...
});
});
参数
返回值
test.use
Added in: v1.10指定在单个测试文件或 test.describe() 分组中使用的选项或 fixtures。最常用于设置选项,例如设置 locale
来配置 context
fixture。
用法
import { test, expect } from '@playwright/test';
test.use({ locale: 'en-US' });
test('test with locale', async ({ page }) => {
// 默认的 context 和 page 会使用指定的 locale
});
参数
-
options
TestOptions#包含本地选项的对象。
详情
test.use
可以在全局作用域或 test.describe
内部调用。在 beforeEach
或 beforeAll
中调用会报错。
也可以通过提供函数来覆盖 fixture:
import { test, expect } from '@playwright/test';
test.use({
locale: async ({}, use) => {
// 从某个配置文件中读取 locale
const locale = await fs.promises.readFile('test-locale', 'utf-8');
await use(locale);
},
});
test('test with locale', async ({ page }) => {
// 默认的 context 和 page 会使用指定的 locale
});
属性
test.expect
Added in: v1.10expect
函数可用于创建测试断言。了解更多关于 测试断言 的信息。
用法
test('example', async ({ page }) => {
await test.expect(page).toHaveTitle('Title');
});
类型
已弃用
test.describe.parallel
添加于: v1.10推荐使用 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(() => {
// ...
});
参数
-
分组标题。
-
details
Object (可选) 添加于: v1.42#详细描述请参见 test.describe()。
-
调用 test.describe.parallel() 时立即执行的回调函数。在此回调中添加的任何测试都将属于该分组。
test.describe.parallel.only
添加于: v1.10配置执行模式的推荐方式请参见 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(() => {
// ...
});
参数
-
测试组标题。
-
details
Object (可选) 添加于: v1.42#详细说明请参见 test.describe()。
-
调用 test.describe.parallel.only() 时立即运行的回调函数。在此回调中添加的任何测试都将属于该测试组。
test.describe.serial
添加于: v1.10推荐使用 test.describe.configure() 来配置执行模式。
声明一组必须串行执行的测试。如果其中某个测试失败,后续所有测试都会被跳过。组内所有测试会一起重试。
不建议使用 serial 模式。通常更好的做法是让测试相互隔离,以便可以独立运行。
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(() => {
// ...
});
参数
-
分组标题。
-
details
Object (可选) 添加于: v1.42#详情描述请参见 test.describe()。
-
调用 test.describe.serial() 时立即执行的回调函数。在此回调中添加的所有测试都属于该分组。
test.describe.serial.only
添加于: v1.10推荐使用 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(() => {
// ...
});
参数