由 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它, 保留返回类型 aPromise返回时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
捐款
欢迎拉出请求! 请先打开一个问题来讨论你想要改变什么.