@cerios/playwright-step-decorator

中文文档
2.3.0发布于 2026/11/05MITTypeScriptESM + CJS零依赖构建来源已验证近 30 天下载 4127

创建步法测试的 Playwright 装饰器

中文使用文档
文档目录32 节
  1. 特征
  2. 安装
  3. 促进发展
  4. 使用量
  5. 导入装饰器
  6. 基本示例
  7. 通过 test.step() 选项
  8. 如何运作
  9. 占位符
  10. 实例
  11. 1. 命名和嵌入式占位符
  12. 2. 索引占位符
  13. 3. 混合命名和索引占位符
  14. 4. 数值选择器占位符
  15. 报告中准确的来源位置
  16. 示例
  17. 处理错误
  18. 访问步骤上下文 getStepInfo (中文(简体) )
  19. 示例
  20. API 密码
  21. step(description: string)
  22. step(description: string, options)
  23. step(options)
  24. getStepInfo()
  25. getStepInfo(instance)
  26. stepResult()
  27. stepResult(value)
  28. stepResult(() => value)
  29. 许可证
  30. 作者
  31. 捐款
  32. 链接

由 Cerios 制作

用于 Playwright 的 TypeScript 装饰器,通过允许您在测试步骤中添加动态,参数化描述,使您的测试步骤更加可读和可追踪.

特征

  • 装饰语法 用于Playwright步骤.
  • 动态说明: 使用占位符将参数值注入步骤描述.
  • 支持嵌入属性:在描述中引用嵌入对象属性.
  • 基于索引的占位符: 按其立场提出的参考论据.
  • 类型安全值占位符数字 : __key__ 占位符由羊肉填充,其参数取自装饰法. 你得到完整的自动补全, 和编译器检查 每个密钥 完全有一个选择器.
  • 更好的参数匹配:命名的占位符现在处理默认值和休息参数更加可靠.
  • 可读复数: 可能时, 对象和阵列作为步骤描述中的 JSON 提供 .
  • 转发 Playwright 步骤选项: 传出 box, (中文(简体) ), timeout,或习惯 location 改为 test.step()。 。 。 .
  • 准确来源位置: 报告中的步入位置指实际方法调用站点,而不是装饰器的执行.

安装

npm install @cerios/playwright-step-decorator

促进发展

npm install --save-dev @cerios/playwright-step-decorator

使用量

@step 是类方法的标准ECMAScript装饰. Playwright的转写器支持这个出盒子. 如果您将测试汇编为 tsc,确保 experimentalDecorators 未启用 : @step 然后没有效果,没有步骤的报告.

符号命名方法: babel 版本被 Playwright 所捆绑 Cannot convert a Symbol value to a string 在装饰器运行之前,使用以符号命名的方法进行任何装饰。 装饰一种具有正常名称的方法,并从符号名取出:

class MyTest {
    @step("Iterate over {{items}}")
    async iterate(items: string[]) {
        // ...
    }

    [run](items: string[]) {
        return this.iterate(items);
    }
}

导入装饰器

import { step, stepResult } from "@cerios/playwright-step-decorator";

使用 stepResult() 用于非同步 @step 解析无值的方法, stepResult(value) 当它们解决非函数值时,或 stepResult(() => { ... }) 当你想要一个有多重动作的小羊羔。 函数输入作为工厂处理,所以如果需要自行解决某个函数,则从lobda中返回,例如: stepResult(() => actualFunction)。 。 。 .

基本示例

class MyTest {
    @step("Login as {{user.name}}")
    async login(user: { name: string }) {
        // ...login logic
    }

    @step("Click button [[0]] times")
    async clickButton(times: number) {
        // ...click logic
    }

    @step("Build greeting for {{name}}")
    buildGreeting(name: string): Promise<string> {
        return stepResult(`Hello ${name}`);
    }

    @step("Prepare greeting for {{name}}")
    prepareGreeting(name: string): Promise<string> {
        return stepResult(() => {
            const greeting = `Hello ${name}`;
            return greeting.toUpperCase();
        });
    }

    @step("Reset the form")
    resetForm(): Promise<void> {
        // No `await` inside and no `async` keyword needed (avoids the require-await lint error)
        this.dirty = false;
        return stepResult();
    }
}

通过 test.step() 选项

您可以通过 Playwright 步骤选项作为唯一的装饰器参数, 或者在您同时想要自定义描述时作为第二个参数 :

class MyTest {
    @step("Wait for checkout", { box: true, timeout: 15_000 })
    async waitForCheckout() {
        // ...wait logic
    }

    @step({ timeout: 5_000 })
    async refreshTotals() {
        // Uses the default step name: "MyTest.refreshTotals"
    }

    @step("Open modal", {
        location: { file: "tests/cart.spec.ts", line: 42, column: 7 },
    })
    async openModal() {
        // Uses the explicit location instead of the generated call site
    }

    @step("Submit order", { timeout: 30_000 })
    async submitOrder() {
        // Still auto-generates the call-site location because no custom location was supplied
    }
}

如何运作

这个 @step 装饰器用 Playwright 将你的承诺返回方法包起来 test.step,使用动态描述。 描述中的占位符被运行时的实际参数值所取代.

说明: 装饰方法不需要 async 关键词 如果一个方法机构没有 await,您可以放弃 async 以避开 require-await 错误 。 因为装饰的电话是包裹在 test.step 呼唤者 await 它, 保留返回类型 a Promise 返回时 stepResult(), (中文(简体) ), stepResult(value) 非函数值,或 stepResult(() => { ... }) 而不是标记方法 async数字 :

@step("Reset the form")
resetForm(): Promise<void> {
  this.dirty = false;
  return stepResult(); // no `async`, no require-await warning
}

@step("Build greeting for {{name}}")
buildGreeting(name: string): Promise<string> {
  return stepResult(`Hello ${name}`);
}

@step("Prepare greeting for {{name}}")
prepareGreeting(name: string): Promise<string> {
  return stepResult(() => {
      const greeting = `Hello ${name}`;
      return greeting;
  });
}

占位符

  • 命名参数数字 : {{param}} 替换为命名参数的值 param。命名的占位符支持标识符参数、默认值和休息参数.
  • 嵌入式财产数字 : {{param.prop}} 替换为财产价值 prop 参数 param。 。 。 .
  • 基于索引数字 : [[0]], (中文(简体) ), [[1]],, , , , , , , , . 替换为给定索引中的参数.
  • 数值选择器数字 : __key__ (例如 __0__ 或者说 __role__(中文(简体) ) 取而代之的是 values 选项。 无 values, (中文(简体) ), __key__ 是文字文本。 见 数值选择器占位符。 。 。 .

当一个占位符对一个对象或数组进行解析时,装饰器在可能时使其成为JSON,因此报告仍然可以读取. 正则表达式,错误, Maps 和 Sets以可读形式打印出,非常大的对象使用更短,深度有限的形式. 每个占位符在标题上最多添加了1000个字符;较长的值会以如下注释结尾: … (500 more characters)。 。 。 .

被嵌入的属性也用于字符串,数字和函数,例如 {{name.length}}。 。 。 .

已命名的占位符从方法的来源读取参数名称, 因此保留 @step 当与其他装饰器结合时,直接高于方法:

class MyTest {
    @retry() // Other decorators go above @step
    @step("Login as {{user.name}}")
    async login(user: { name: string }) {
        // ...
    }
}

如果另一个装饰者坐在下面 @step, (中文(简体) ), @step 可以看到装饰器的包装功能而不是你的参数. 然后一个占位符会因出错而失败,或者如果名称恰好匹配,会读取包装符的参数.


实例

1. 命名和嵌入式占位符

class Greeter {
    @step("User: {{user.name}}, Age: {{user.age}}")
    async greet(user: { name: string; age: number }) {
        // ...
    }
}
await new Greeter().greet({ name: "Alice", age: 30 });
// Step description: "User: Alice, Age: 30"

2. 索引占位符

class Worker {
    @step("First arg is [[0]], second is [[1]]")
    async doSomething(a: string, b: number) {
        // ...
    }
}
await new Worker().doSomething("foo", 42);
// Step description: "First arg is foo, second is 42"

3. 混合命名和索引占位符

class Example {
    @step("Named: {{name}}, Index: [[1]]")
    async run(name: string, value: number) {
        // ...
    }
}
await new Example().run("Bob", 77);
// Step description: "Named: Bob, Index: 77"

4. 数值选择器占位符

使用 __key__ 当步骤文本需要从参数中计算出某种东西时,例如数组中的一个项目、过滤过的列表或有条件的标签。 每一个关键地图,一个羊肉在 values 选项。 羊肉会得到方法的论证 与真实类型因此,你的编辑器自动完成它们,编译器检查它们:

type Contact = { name: string; email: string; primary: boolean };
type User = { name: string; role: string; contacts: Contact[] };

class ContactsPage {
    @step("Add contacts for __0__ (second: __second__, primary: __primary__)", {
        values: {
            0: user => user.name, // user: User
            second: (_user, contacts) => contacts[1].email, // contacts: Contact[]
            primary: user =>
                user.contacts
                    .filter(c => c.primary)
                    .map(c => c.name)
                    .join(", "),
        },
    })
    async addContacts(user: User, contacts: Contact[]) {
        // ...
    }
}
// Step description: "Add contacts for Alice (second: [email protected], primary: Bob, Dave)"

__key__ 占位符仅在您通过时激活 values 选项。 没有它,文本例如 __NEXT_DATA__ 指纹如是.

当你通过 values 带有字面描述的编译器执行:

  • 每个 __key__ 在描述中有一个选择器在 values, (中文(简体) ),
  • values 包含没有在描述中的密钥,
  • 每个羊肉达的参数与被装饰方法的参数相匹配. 明确说明,例如: (user: User) => ... 被允许,但他们必须匹配.

注释:

  • 键可以是数字( E)__0__ → { 0: ... }或名称(__role__ → { role: ... }) (中文(简体) ). 密钥是介于 __ 财务报告和审定财务报表 __ 没有空白、括号或方括号。 其他跨度,例如 a __ b __ c 或者说 report__{{date}}__final,保留为文字文本.
  • 要打印文字 __text__ 在同时使用的描述中 values,从选择器返回它: { literal: () => "__text__" }。包含完整 __key__,例如 {{a__b__c}},不能同时使用 values,因此使用索引占位符.
  • Lambdas收到的论据与通过的论点完全相同;省略的任择论据是: undefined。 。 。 .
  • Lambdas必须是同步的,因为它们在步骤开始前会跑. 羊肉达能还原承诺会造成错误.
  • 回来的羊肉 null 或者说 undefined 指纹 null 或者说 undefined对于无效参数,使用可选的链条(user => user?.name),编译器在参数类型允许时要求的 null 或者说 undefined。 。 。 .
  • 返回的值与其他任何占位符(字符串为-is,对象为JSON)一样格式化.
  • 如果描述是普通的 string 变量而不是字元,在编译时无法检查密钥。 缺少选择器, 然后在运行时丢出 .

报告中准确的来源位置

装饰者自动捕捉您装饰方法的呼叫站点位置,并将其传递至 Playwright 的 test.step()这意味着:

  • HTML 报告 显示使用该方法的正确文件和行号
  • 跟踪查看器 指向实际测试代码,而不是装饰器执行
  • 日志 显示准确的源位置以方便调试

此功能使用 Playwright 内置 location 参数 尽可能确保报告各步骤位置有所帮助。 如果你提供 location 在装饰者的第二个论点中,使用的是明示值。 否则,装饰器会自动倒回生成的呼叫站点位置.

示例

当你在测试中称装饰方法:

// my-test.spec.ts
test("example", async ({ page }) => {
    const loginPage = new LoginPage(page);
    await loginPage.login(user); // Line 10
});

Playwright 报告将显示步骤位置为 my-test.spec.ts:10,而不是装饰器执行的地点.


处理错误

当分类被定义时 : 一旦包含类负载的文件投出就永远无法工作的描述,所以即使方法从未被调用,也会找到打字. 发生于:

  • 描述中的命名参数在函数签名中不存在.
  • 已命名的占位符使用已解结构或以其他方式不支持的参数语法. 错误建议使用索引占位符 .
  • 索引占位符超出了已宣布的参数。 使用休息参数的方法 arguments 改为在呼叫时检查.
  • A 类 __key__ 占位符没有选择器 values。这也是文字描述的编译时间错误.

由于类名尚不得而知,这些错误只取出方法名.

当该方法被称为: 如果一个描述无法为特定调用解答,被装饰方法还原的允诺会拒绝,步骤也不会开始. 发生于:

  • 嵌入式属性在参数上不存在. 如果参数(或中间属性)是 null 或者说 undefined,占位符打印 null 或者说 undefined 换句话说 在省略对象默认中丢失的财产也是如此.
  • 指数占位符已超出通过的论点.
  • 省略的参数有一个默认值,不能被打印出. 文字可以被印刷,包括仅由文字制作的物体和阵列,例如: { timeout: 5, tags: ["a"] }任何需要评估的东西,比如 Mode.Auto, (中文(简体) ), { timeout: DEFAULT_TIMEOUT } 或者说 { ...base }。 。 。 .
  • A 类 values 选择者投出。 拒绝是一个描述性错误, 原始错误为 cause。 。 。 .
  • A 类 values 选择者返回一个承诺.

访问步骤上下文getStepInfo(中文(简体) )

有时您想要将文件,日志,或元数据附加到您装饰方法内的当前 Playwright 步骤中. 使用 getStepInfo 函数访问 TestStepInfo 当前步骤的对象.

示例

import { step, getStepInfo } from "@cerios/playwright-step-decorator";

class NavbarTest {
    @step("Assert the navbar items are as expected")
    async assertNavbarItems(expectedItems: string[]): Promise<void> {
        const stepInfo = getStepInfo();
        await stepInfo.attach("expected-items.json", {
            body: JSON.stringify(expectedItems),
            contentType: "application/json",
        });
        // ...your assertions...
        await stepInfo.attach("actual-items.json", {
            body: JSON.stringify(await this.navbarItem.allInnerTexts()),
            contentType: "application/json",
        });
    }
}

说明:

  • getStepInfo() 财务报告和审定财务报表 getStepInfo(this) 必须在一种用 @step。 。 。 .
  • 步骤上下文按协同引用进行跟踪,因此同时 Promise.all(...) 要求同一机构保持自己的地位 TestStepInfo。 。 。 .
  • 如果在步骤上下文之外调用, 则丢出错误 .

API 密码

step(description: string)

  • 说明: 步骤描述,支持占位符类似 {{param}}, (中文(简体) ), {{param.prop}},或 [[index]]。 。 。 .
  • 回返:用于承诺回放方法的装饰器功能.

step(description: string, options)

  • 选项.box / 选项.timeout / 选项. 位置: 转发到 Playwright 的 test.step()。 。 。 .
  • 选项: 每个对象映射 __key__ 对羊肉的描述中的占位符 (...methodArgs) => unknown通过它打开 __key__ 描述的占位符.

step(options)

  • 选项: Playwright 步骤选项; 该步骤使用默认 ClassName.methodName 说明.

导出帮助类型 : StepOptions, (中文(简体) ), StepValueSelector<Args>, (中文(简体) ), StepValues<Description, Args>, (中文(简体) ), StepOptionsWithValues<Description, Args>,以及 ValuePlaceholderKeys<Description>。 。 。 .

getStepInfo()

  • 回返: 当前剧作家 TestStepInfo 用于激活的装饰方法调用.

getStepInfo(instance)

  • 实例: 保留与更早的发行相倒相容.
  • 回返: 当前剧作家 TestStepInfo 用于激活的装饰方法调用.

stepResult()

  • 回返数字 : Promise<void> 用于非同步 @step 不返回值的方法.

stepResult(value)

  • 价值: 非函数值需要解决.
  • 回返数字 : Promise<Awaited<T>> 用于非同步 @step 返回一个值的方法.

stepResult(() => value)

  • 回调: 一个零参数的羊肉,在返回一个值之前可以执行多个同步动作.
  • 回返数字 : Promise<Awaited<T>> 带有回调结果,如果回调投出则拒绝.

如果您需要解决一个函数值本身,请以回调形式将其包入: stepResult(() => actualFunction)。 。 。 .


许可证

麻省理工学院


作者

罗纳德·韦斯 - Cerios


捐款

欢迎拉出请求! 请先打开一个问题来讨论你想要改变什么.


版本与发布记录

@cerios/playwright-step-decorator 共发布 13 个版本,首次发布于 2025/06/02;过去 12 个月发布了 7 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
2.3.0latest2026/11/053 天前
2.2.22026/09/301 个月前
2.2.12026/07/104 个月前
2.2.02026/06/045 个月前
2.1.22026/06/025 个月前
2.1.12026/03/247 个月前

关于 @cerios/playwright-step-decorator 的常见问题

@cerios/playwright-step-decorator 是什么?

创建步法测试的 Playwright 装饰器

如何安装 @cerios/playwright-step-decorator?

在项目目录运行 npm install @cerios/playwright-step-decorator,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@playwright/test(^1.51.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@cerios/playwright-step-decorator 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@cerios/playwright-step-decorator 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@cerios/playwright-step-decorator 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@cerios/playwright-step-decorator 可以商用吗?

@cerios/playwright-step-decorator 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@cerios/playwright-step-decorator 的下载量有多少?

根据 npm 官方下载统计,@cerios/playwright-step-decorator 在 2026/10/10 – 2026/11/08 这 30 天内被下载 4,127 次,日均约 138 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@cerios/playwright-step-decorator 还在维护吗?

最新版本 2.3.0 发布于 2026/11/05(3 天前);至今共发布 13 个版本,其中过去 12 个月发布了 7 个;首次发布于 2025/06/02。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。