Playwright前置代码失败时testInfo.annotations.push不生效问题求助
问题描述
我们用Playwright+TypeScript编写了大量测试用例,为了让JUnit XML报告中的每个<testcase/>节点都附带<property name="test_key" value="ABC-002"/>字段(方便将测试结果导入Jira并关联对应工单),我们在每个测试用例中添加了testInfo.annotations.push({ type: "test_key", description: "ABC-002" })代码。
但发现当测试在global-setup、test.beforeEach、test.beforeAll这类非测试代码块执行失败时,测试会被标记为失败或跳过,但上述test_key字段不会出现在XML报告中,导致无法正常关联Jira测试工单。
示例测试代码:
test("has title", async ({ page }, testInfo) => { testInfo.annotations.push({ type: "test_key", description: "ABC-002" }); await page.goto("https://playwright.dev/"); // 断言标题包含指定子串 await expect(page).toHaveTitle(/Playwright/); });
期望的JUnit XML报告:
<testsuites id="" name="" tests="2" failures="0" skipped="0" errors="0" time="6.236571"> <testsuite name="example.spec.ts" timestamp="2023-12-13T02:48:18.156Z" hostname="chromium" tests="2" failures="0" skipped="0" time="7.121" errors="0"> <testcase name="has title" classname="example.spec.ts" time="2.696"> <properties> <property name="test_key" value="ABC-001"> </property> </properties> </testcase> <testcase name="get started link" classname="example.spec.ts" time="4.425"> <properties> <property name="test_key" value="ABC-002"> </property> </properties> </testcase> </testsuite> </testsuites>
解决方案
方法1:将test_key注入逻辑移至test.beforeEach钩子
把添加test_key注解的逻辑放到test.beforeEach中,该钩子会在每个测试用例执行前触发——哪怕后续测试逻辑因钩子失败无法运行,testInfo已被注入注解,生成XML报告时会自动包含对应的property字段。
// 在测试文件顶部或全局配置文件中定义钩子 test.beforeEach(async ({}, testInfo) => { // 可根据测试名称映射对应的test_key,也可从外部配置文件读取 const testKeyMap: Record<string, string> = { "has title": "ABC-001", "get started link": "ABC-002" }; const targetKey = testKeyMap[testInfo.title]; if (targetKey) { testInfo.annotations.push({ type: "test_key", description: targetKey }); } }); // 测试用例无需再重复添加注解逻辑 test("has title", async ({ page }) => { await page.goto("https://playwright.dev/"); await expect(page).toHaveTitle(/Playwright/); }); test("get started link", async ({ page }) => { await page.goto("https://playwright.dev/"); await page.getByRole("link", { name: "Get started" }).click(); await expect(page).toHaveTitle(/Getting started/); });
方法2:自定义测试装饰器批量注入test_key
如果测试用例数量庞大,可封装自定义测试函数,统一处理test_key注入逻辑,避免重复代码:
import { test as base } from "@playwright/test"; // 自定义测试扩展类型 type TestOptions = { testKey: string; }; export const test = base.extend<TestOptions>({ testKey: ["", { option: true }] }); // 封装带test_key的测试函数 export const testWithKey = (title: string, testKey: string, testFn: typeof base.test) => { test(title, async ({}, testInfo) => { testInfo.annotations.push({ type: "test_key", description: testKey }); await testFn({} as any, testInfo); }); }; // 使用示例 testWithKey("has title", "ABC-001", async ({ page }) => { await page.goto("https://playwright.dev/"); await expect(page).toHaveTitle(/Playwright/); });
方法3:处理global-setup全局失败的极端情况
如果global-setup执行失败导致整个测试套件无法启动,Playwright不会生成单个测试用例的XML条目。此时可:
- 在
global-setup中捕获错误,手动生成包含通用test_key的报告片段; - 在CI流程中单独处理这类全局失败,关联到Jira中对应的全局测试工单。
内容的提问来源于stack exchange,提问作者Reed_Xia
相关产品推荐
相关产品推荐

