在赛普拉斯测试中加载页面后,如何可靠地等待 XHR 请求?
how can i reliably wait for XHR requests after loading a page in a Cypress test?
在我的应用程序中,当我访问一个页面时,它会发出一些网络请求来获取数据并将其显示在页面上。之后,您单击按钮并填写字段以过滤该数据。
我有一个 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'. No response ever occurred.
因为它正在等待一个已经发生的请求。
有没有更好的方法来编写这个测试?有没有一种方法可以访问页面并等待 XHR 请求来避免这种竞争情况?
更新
我试图在一个孤立的测试用例中重新创建它,但它似乎一切正常,所以可能存在一些操作错误。
由于您使用的是 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
你可以这样做
// 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
所以大部分答案现在都已弃用。从 Cypress@6.4.0 开始,您应该使用 intercept()
.
这是我的做法:
cy.intercept({
method: "GET",
url: "http://my-api.biz/api/**",
}).as("dataGetFirst");
cy.wait("@dataGetFirst");
就是这样。您可以做更多并在等待时做一个断言链,但它本身已经是一个断言。
在我的应用程序中,当我访问一个页面时,它会发出一些网络请求来获取数据并将其显示在页面上。之后,您单击按钮并填写字段以过滤该数据。
我有一个 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'. No response ever occurred.
因为它正在等待一个已经发生的请求。
有没有更好的方法来编写这个测试?有没有一种方法可以访问页面并等待 XHR 请求来避免这种竞争情况?
更新
我试图在一个孤立的测试用例中重新创建它,但它似乎一切正常,所以可能存在一些操作错误。
由于您使用的是 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
你可以这样做
// 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
所以大部分答案现在都已弃用。从 Cypress@6.4.0 开始,您应该使用 intercept()
.
这是我的做法:
cy.intercept({
method: "GET",
url: "http://my-api.biz/api/**",
}).as("dataGetFirst");
cy.wait("@dataGetFirst");
就是这样。您可以做更多并在等待时做一个断言链,但它本身已经是一个断言。