目前我正在编写一个小型测试项目,使用页面对象模型和Playwright。我有一些页面的方法返回页面本身或另一个页面。这使我更容易编写测试。然而,当我使用异步方法时,我得到了很多等待。
var homePage = new HomePage(page);
await (await (await (await homePage.goto())
.DoSomething())
.NavigateToNextPage())
.ValidateResult();
我想知道是否有办法避免排队等候。或者我不应该默认使用异步,因为我的测试本质上是连续的。
我找到了Promise.all(),但在这种情况下,这似乎不起作用,因为我正在链接方法。
我将从API中删除链接,并将调用中断到多行:
const homePage = new HomePage(page);
await homePage.goto();
await homePage.doSomething();
await homePage.navigateToNextPage();
await homePage.validateResult();
只有当你有一系列调用被惰性地评估并以某种动作结束时,才能使用Playwright定位器样式链。使用Playwright文档中的示例:
await page
.getByRole('listitem')
.filter({ hasText: /Product 2/ })
.getByRole('button', { name: 'Add to cart' })
.click();
这里,唯一的动作是click()
。其他所有内容都可以在操作之前链接,因为这些方法的目的是选择和筛选,为单击做准备。页面实例可以返回可同步链接的对象,直到最后的click()
,CCD_2返回一个评估链并禁止进一步链接的promise。
但在您的情况下,每一行似乎都是一个可以单独执行的操作,并且不涉及任何可选的准备步骤。Playwright不支持像那样的动作链接
await page.goto().click().waitForNavigation().click();
如果我在这个答案顶部显示的模式看起来太";"镗孔";,考虑一下Puppeteer的API(以及除定位器之外的大多数剧作家)是100%的这种风格。阅读、写作和使用都很正常,也不足为奇。有人可以说,与Puppeteer的无链API相比,Playwright的懒惰定位器更聪明,因此更难推理。
但是,如果真的想这样做,最简单的方法是选择一个函数作为操作,并使用它来刷新链:
class HomePage {
constructor(page) {
this.page = page;
this.actions = [];
}
goto() {
this.actions.push(this.page.goto());
return this;
}
doSomething() {
this.actions.push(
this.page.doSomething(),
this.page.doSomethingElse(),
this.page.doAnotherSubStep(),
this.page.click()
);
return this;
}
navigateToNextPage() {
this.actions.push(this.page.navigateToNextPage());
return this;
}
validateResult() {
this.actions.push(this.page.validateResult());
return this;
}
async exec() {
for (const action of this.actions) {
await action;
}
this.actions = [];
}
}
const homePage = new HomePage(page);
await homePage
.goto()
.doSomething()
.navigateToNextPage()
.validateResult()
.exec();
或者,您可以使validateResult
而不是exec
清空承诺,这取决于您的用例。
这种设计的问题是,如果你只想采取一个单一的行动,那就很尴尬。如果使用exec()
进行刷新,则在每次操作之后都必须调用exec()
(或其他一些操作方法集),这是多余的代码。您可以使用一组不同的可链接方法,这对于调用者和被调用者来说是非常混乱的。
如果你使用validateResult()
来刷新,并且你确信最后你会一直调用它,也许这是可行的。然后决定我的第一个提议是否比链式版本更令人困惑(无论是维护还是使用)。
由于您处理的是一个看起来像原子工作单元的东西,因此最好将整个链抽象为一个函数validateHomePage()
或类似函数。
请注意,我使用的是camelCase
而不是PascalCase
和const
。