避免在Cypress中使用.wait()来加载所有元素



我一直在寻找Cypress中.wait((问题的解决方案。我们的应用程序不会同时加载所有数据。对于这样的请求,最常见的答案如下:

cy.server();
cy.route('**/api/getData').as('getData');
cy.visit('/home');
cy.wait('@getData');

这根本不起作用。您将到达/customer/12345,但可能还需要几秒钟的时间才能加载全部数据,甚至是一些UI元素。所以,检查路线一点帮助都没有。我试图创建一个别名,但当我做这样的事情时:

cy.get('#submitButton').as('submit')

然后做:

cy.wait('@submit')

由于按钮尚未出现,因此别名检查失败。

我需要等到所有资源都加载完毕后才能开始测试元素。我团队中一位对Cypress一无所知的开发人员问我是否可以使用Window加载事件或GlobalEventHandler.onload,但我找不到任何关于在Cypress中使用这些事件的文档。

有一件事我想让任何回答者都明白,我是一个完全的新手。我有Java、Selenium、Unirest和Junit的经验。我不得不彻底改变我对Cypress的心态,我不知道Javascript,所以我仍处于学习阶段。在硒中,我会有

wait.until(ExpectedConditions.elementToBeClickable(By.id<submitButton>));

那么,我有没有办法确保在开始运行测试之前加载了所有资源?

有三个选项是我们最喜欢的,以避免隐含的等待,因为在应用程序中添加延迟被认为是一种糟糕的做法,99%的时候我们不应该这样做。

选项1:

您可以使用以下should方法来避免显式等待命令

cy.get('put-locator-class/ID-here').should('be.visible).then(($el)=>{ $el.click()})

你需要确保你的元素一定会出现。

选项2:

自定义等待->我们可以等待某些元素消失。这似乎更像是一种相反的方法。

示例:

cy.get(`span[title="${text}"][role="button"]`).click();
while (cy.get('div[class="g3-single-select-filter"]').find('i[class="fas fa-spinner fa-pulse"]').length > 0){
cy.wait(1000);
}

选项-3:我们可以使用拦截命令等待API完成调用

cy.intercept('http://example.com/settings').as('getSettings')
// once a request to get settings responds, 'cy.wait' will resolve
cy.wait('@getSettings')

最后,选项-1选择-3在柏树群落中使用最广泛

更具体

您可能希望更具体地说明您正在等待的服务器请求响应的类型。不要使用一般:

cy.route('**/api/getData').as('getData');

更具体一点:

cy.route('api/for/list').as('getList');
cy.route('api/for/header-data').as('getHeader');
cy.route('api/for/footer-data').as('getFooter');
cy.route('api/for/whatever').as('getElse');
...

并期望一些特定的端点将被请求并返回数据

cy.wait(['@getHeader']).then(([responseHeader]) => // check header elements)
cy.wait(['@getHeader', '@getList']).then(([responseHeader, responseList]) => // check list and header elements)

在期望某些结果之前,可以期望完成多个端点。

等待方法对于检查在导航或其他应用程序交互之后以及在检查您的期望值之前是否与服务器进行了正确的通信非常重要。在某些情况下,你可能会避免,但似乎你还有其他问题。

您可以用信号通知应用程序状态

如果以上还不够,您可以尝试触发事件(从应用程序代码中(或使用一些全局值来标记应用程序呈现或处理状态。

function render() {
window.cypressReady = false; // use some global values
// some rendering logic
window.cypressReady = true;
window.postMessage(); // or trigger event that can be catched by Cypress
}

在Cypress中,你可以观察到它如下:

Cypress.Commands.add('appReady', ({ timeout = 10000 } = {}) => {
return cy
.window({ timeout })
.should((win) => {
// when expecting is in callback we are retrying until assertion pass or timeouts
// without callback it will just check once when the variable will be available
expect(win['cypressReady'], 'app ready').to.be.eq(true);
});
});

当你写测试时:

// simulate some actions
cy.appReady()
// some expectations

您可以将这两种方法结合起来,首先等待需要为特定页面调用的特定端点,然后在运行预期之前运行appReady((。

您可以为网页中的特定元素添加特定超时,然后添加should(be.visible)。它将确保自动重试断言,直到它们超时。[Cypress Docs]

cy.get('#submitButton', {
timeout: 10000
}).should('be.visible').click()

另一种方式可以是增加所有cy.get()命令的超时。为此,请在cypress.json文件中写入以下内容。[Cypress Docs]

{
defaultCommandTimeout: 10000
}

最新更新