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

问题描述 投票:0回答:3

我一直在寻找解决方案来解决我在赛普拉斯遇到的 .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 load 事件或 GlobalEventHandler.onload,但我找不到任何有关在 Cypress 中使用这些事件的文档。

我希望所有回答者都能理解一件事,我是个新手。我有使用 Java、Selenium、Unirest 和 Junit 的经验。我必须彻底改变我对 Cypress 的心态,而且我不懂 Javascript,所以我仍处于学习阶段。在 Selenium 中我会有

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

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

typescript asynchronous cypress
3个回答
6
投票

我们最喜欢使用三种选项来避免隐式等待,因为在应用程序中添加延迟被认为是一种不好的做法,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')

结束本次讨论,Option-1Option-3 在 cypress 社区中使用最广泛


1
投票

更具体一些

您可能想更具体地了解您正在等待哪种类型的服务器请求响应。请勿使用一般:

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()。


0
投票

您可以为整个网页中的特定元素添加特定超时,然后添加

should(be.visible)
。它将确保断言自动重试,直到超时。[Cypress Docs]

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

另一种方法是增加所有

cy.get()
命令的超时时间。为此,请在
cypress.json
文件中写入以下内容。[Cypress 文档]

{
defaultCommandTimeout: 10000
}
© www.soinside.com 2019 - 2024. All rights reserved.