在赛普拉斯测试中加载页面后,如何可靠地等待 XHR 请求?

Posted

技术标签:

【中文标题】在赛普拉斯测试中加载页面后,如何可靠地等待 XHR 请求?【英文标题】:how can i reliably wait for XHR requests after loading a page in a Cypress test? 【发布时间】:2018-09-21 20:18:04 【问题描述】:

在我的应用程序中,当我访问一个页面时,它会发出一些网络请求来获取数据并将其显示在页面上。之后,您单击按钮并填写字段以过滤该数据。

我有一个 cypress 测试,它基本上会访问页面,应用一些过滤器,并确保 dom 中的内容看起来正确:

it(`filters the data by 'price'`, () => 
  cy.server()
  cy.route('POST', 'http://my-api.biz/api').as('apiRequest')

  cy.visit('/')

  // initial page load loads the min and max price bounds for the UI,
  // as well as the data to initially populate the page. they happen
  // to hit the same URL with different POST params
  cy.wait(['@apiRequest', '@apiRequest'])

  cy.get('#price-filter-min').type('1000')
  cy.get('#price-filter-max').type('1400')

  // wait for data to get refreshed
  cy.wait('@apiRequest')

  cy
    .get('[data-test-column="price"]')
    .each($el => 
      const value = parseFloat($el.text())
      expect(value).to.be.gte(1000)
      expect(value).to.be.lte(1400)
    )
)

但有时 cypress 似乎会加载页面,等待之前执行 XHR 请求,然后偶尔会失败:

CypressError: Timed out retrying: cy.wait() timed out waiting 30000ms for the 2nd response to the route: 'apiRequest'。从未发生任何响应。

因为它正在等待一个已经发生的请求。

有没有更好的方法来编写这个测试?有没有办法访问页面并等待 XHR 请求来避免这种竞争条件?

更新

我试图在一个孤立的测试用例中重新创建它,但它似乎一切正常,因此可能存在一些操作错误。

【问题讨论】:

【参考方案1】:

你可以这样做

// Give an alias to request
cy.intercept(
  method: 'GET',
  url: '/odata/locations/**',
).as('dataGetFirst');

// Visit site
cy.visit('admin/locations');

// Wait for response.status to be 200
cy.wait('@dataGetFirst').its('response.statusCode').should('equal', 200)

// Continue

【讨论】:

谢谢!似乎路线也区分大小写,所以请注意 我不得不用cy.wait('@cartIsUpdating').its('status').should('equal', 200);替换:cy.wait('@dataGetFirst').its('status').should('be', 200); 类似于 Zeth 我不得不做cy.wait('@getSomething').its('response.statusCode').should('equal', 200)。也许是因为cy.server 现在被cy.intercept 取代了?答案应该更新到当前的赛普拉斯版本。 在执行某些 UI 操作时,是否有办法检查网络选项卡中调用的特定 API?【参考方案2】:

所以现在大多数答案都已弃用。从 Cypress@6.4.0 开始,您应该使用 intercept()

我的做法是这样的:

cy.intercept(
      method: "GET",
      url: "http://my-api.biz/api/**",
    ).as("dataGetFirst");
cy.wait("@dataGetFirst");

就是这样。你可以做更多的事情并在等待时做一个断言链,但它本身已经是一个断言。

【讨论】:

不错!我会在这里给 cypress 怀疑的好处并接受这一点,这样人们就可以更容易地发现新的 api 令人痛苦的越野车。我在 Cypress 错误跟踪器中发现了至少两个错误,标记为“已解决”。它仍然只在大约 20 次中起作用。其他 19 次等待只是超时。 在执行某些 UI 操作时,是否有办法检查网络选项卡中调用的特定 API? 所有网络请求都应该是可拦截的。 想补充一点,cy.intercept() 应该在cy.visit() 之前完成【参考方案3】:

由于您使用的是cy.visit('/'),我假设您在配置中设置了 baseUrl。 cy.route() 中的 URL 参数在后台执行 baseUrl + 您作为参数传递的字符串。

所以它发送 POST 请求的 url 是 http://my-api.biz/apihttp://my-api.biz/api 或类似的东西。

尝试将您的路由命令更改为:

cy.route('POST', '/api/foobar').as('apiRequest')

其他文档和示例: https://docs.cypress.io/guides/guides/network-requests.html#Fixtures

【讨论】:

如果你测试这个,你实际上发现它是不正确的。 baseUrl 不参与路由的匹配。 是的。看看这里的例子:docs.cypress.io/api/commands/route.html 这也是我在所有测试中成功实现它的方式。 该页面上的baseUrl在哪里引用? 看例子。他们是在使用“website.com/route”还是在使用“/route”? 从你所说的看来,似乎对 cy.route() 所做的事情有误解——它匹配路线,它不调用它。

以上是关于在赛普拉斯测试中加载页面后,如何可靠地等待 XHR 请求?的主要内容,如果未能解决你的问题,请参考以下文章

如何使赛普拉斯等待具有多个结果的异步搜索完成而不会导致测试失败

在赛普拉斯的 for 循环中等待异步方法

如何等待在画布中加载图像

赛普拉斯:失败后是不是可以完成测试

使用赛普拉斯,我将如何编写一个简单的测试来检查页面上是不是存在徽标图像

如何在赛普拉斯 e2e 测试之前设置 NGRX 状态?