有没有办法断言在赛普拉斯中没有调用路由?
Is there a way to assert that a route has not been called in Cypress?
我试图断言在 Cypress 中没有调用路由。我仔细查看了文档,但一无所获。
我正在尝试做这样的事情:
cy.get('@myRouteAlias').should('have.not.been.called');
我目前正在通过断言未显示成功的请求 toast 消息来解决此问题,但这是一个脆弱的解决方案。
有什么想法吗?
很难测试一个动作没有发生的情况。使用这种类型的断言,您实际上只能说:
"The XHR request was not made within the 400ms
that Cypress looked for this XHR request to have been made (or whatever you set your timeout to be)"
这确实确认 XHR 请求从未被调用。
也就是说,赛普拉斯提供了一种方法来检索使用未记录的 cy.state('requests')
发出的所有 XHR 请求。您可以检查它的长度,按别名过滤它们等,以确定您想要什么。
作为路由选项中的变体设置onResponse
函数,它会删除测试
例如expect(true).to.be.false;
如果调用当前路由会触发错误
cy.route({
url: <url>,
onResponse: function () {
expect("Unexpected Https call").to.be.false;
}
})
为了简化@Jennifer Shehane 的精彩回答:
let requestsCount = (alias) => cy.state('requests').filter(a => a.alias === alias).length;
expect(requestsCount('putRequest')).to.eq(0);
您也可以将其放入 Cypress 命令文件中!
我尝试了 Jonathan 发布的简化版本,但看到类型错误:无法读取未定义的 属性 'filter' 并且 cy.state('requests') 始终未定义。
值得考虑此测试的异步性质,这是前面的示例没有考虑到的。这是一个工作示例:
cy.route('/my-route').as('myRoute')
const noExpectedCalls = 1
cy.get('@myRoute').then(() => {
expect(cy.state('requests').filter(r => r.alias === 'myRoute')).to.have.length(noExpectedCalls)
})
不幸的是,上面的 none 确实对我有用,我用这个命令让它工作:
Cypress.Commands.add('shouldBeCalled', (alias, timesCalled) => {
expect(
cy.state('requests').filter(call => call.alias === alias),
`${alias} should have been called ${timesCalled} times`
).to.have.length(timesCalled);
});
然后我这样使用:
// Checks that FetchChatList has not been called
cy.shouldBeCalled('FetchChatList', 0);
这是使用 cypress 命令断言请求计数的正确方法。
将此放入您的 commands.js
文件中:
Cypress.Commands.add('requestsCount', (alias) =>
cy
.wrap()
.then(() => cy.state('requests').filter(req => req.alias === alias).length),
);
比在您的测试中使用如下新命令:
it('should count requests', () => {
cy.server();
cy.route('**').alias('theRequest');
cy.wait('@theRequest');
cy.requestsCount('theRequest').should('eq', 1);
});
cypress 团队是这样做的 (source):
it("throws when alias is never requested", (done) => {
Cypress.config("requestTimeout", 100);
cy.on("fail", (err) => {
expect(err.message).to.include(
"`cy.wait()` timed out waiting `100ms` for the 1st request to the route: `foo`. No request ever occurred."
);
done();
});
cy.server().route(/foo/, {}).as("foo").wait("@foo.request");
});
并且来自相关的docs:
Fires when the test has failed. It is technically possible to prevent the test from actually failing by binding to this event and invoking an async done callback. However this is strongly discouraged. Tests should never legitimately fail. This event exists because it’s extremely useful for debugging purposes
cy.state
0.
时好像未定义
此外,如果您想使用 @
调用命令,那么这将起作用。
Cypress.Commands.add('shouldBeCalled', (alias, timesCalled) => {
const aliasname = alias.substring(1);
const requests = cy.state('requests') || [];
expect(
requests.filter((call) => call.alias === aliasname),
`${aliasname} should have been called ${timesCalled} times`
).to.have.length(timesCalled);
});
cy.shouldBeCalled('@updateCalc', 1);
在 cy.route()
弃用后更新 cy.intercept()
。
如果您使用 cy.intercept()
,cy.state('requests')
将 return 具有未定义 alias
的对象,所以我改用 xhr.url
。
我把@SleepWalker 的解决方案改编成这样:
commands.js 文件中的命令:
Cypress.Commands.add('requestsCountByUrl', url =>
cy.wrap().then(() => {
const requests = cy.state('requests') || [];
return requests.filter(req => req.xhr.url === url).length;
})
);
测试中的用法:
cy.requestsCountByUrl('http://theUrl.com').should('eq', 1);
我想我找到了一种符合我预期的方式,使用 cy.intercept
和 cy.state
。
- 添加要通过
cy.intercept
嗅探的路由
- 等一个时间,你选择你信任的
- 然后看看你的URL是不是在
cy.state('routes')
.
it(`should NOT make foo request`, () => {
// listen for any request with "foo" using cy.intercept
// I like to return success just to not see warnings in the console...
cy.intercept(/.foo./, { success: true }).as("fooRequest");
cy.window().then(win => {
// do what ever logic could make the request
makeFooRequestOrSomething();
});
// use cy.wait to wiat whatever amount of time you trust that your logoc should have run
cy.wait(1000);
/*
* cy.intercept does not provide any information unless a request is made, so instead
* we can use the state and make sure our route is not in the list
*/
let routes = cy.state('routes'); // An object representing all the routes setup via cy.intercept
let fooRoutes = [];
for (let route in routes) {
// routes[route].requests is an object representing each request
for (let req in routes[route].requests) {
let reqUrl = routes[route].requests[req].request.url;
// test each URL for "foo" and if it has it, add the URL to the array
if((/foo/).test(reqUrl)) {
fooRoutes.push(reqUrl);
}
}
};
// if no request was made to our URL, our array should be empty
expect(fooRoutes).to.have.property("length", 0);
});
routes[route]
可能在某个地方有 alias
,如果您想以不同的方式过滤数据,然后查看 routes[route].requests
是否为空。
- 我没有在任何地方找到这个文档,所以如果有更好的定义 link ,请告诉我,尤其是
cy.state
方法。
当我们有路线时:
cy.intercept('PUT', '**/shoes/*', body).as('updateShoes');
以下解决方案对我有用:
cy.get('@updateShoes').then((interception) => {
assert.isNull(interception)
});
赛普拉斯 说:
预期 null 等于 null
当“@updateShoes”路由被调用时(拦截)是一个对象:
{id: "interceptedRequest551", routeId: "1623772693273-2831", request: {…}, state: "Complete", requestWaited: false, …}
id: "interceptedRequest551"
log: {get: ƒ, unset: ƒ, invoke: ƒ, toJSON: ƒ, set: ƒ, …}
request: {headers: {…}, url: "http://localhost:8080/api/shoes/38de4e08", method: "PUT", httpVersion: "1.1", body: {…}}
requestWaited: false
response: {headers: {…}, body: {…}, url: "http://localhost:8080/api/shoes/38de4e08", method: null, httpVersion: null, …}
responseWaited: false
routeId: "1623772693273-2831"
state: "Complete"
subscriptions: []
...}
Cypress 抛出一个错误:
AssertionError
expected { Object (id, routeId, ...) } to equal null
None 在 7.6 版中对我有用,但我找到了一个非常简单的解决方案。
假设你有这样的拦截:
cy.intercept('GET', '**/foo/bar**').as('myRequest');
现在你可以这样做了:
cy.wait(2000);
cy.get('@myRequest.all').then((interceptions) => {
expect(interceptions).to.have.length(0);
});
所以你等待一段时间,当请求可能已经发生时,并确保在等待之后它没有发生。对我来说工作得很好,不需要额外的命令。
我在这里找到了解决方案:https://www.gitmemory.com/issue/cypress-io/cypress/15036/780706160
我试图断言在 Cypress 中没有调用路由。我仔细查看了文档,但一无所获。
我正在尝试做这样的事情:
cy.get('@myRouteAlias').should('have.not.been.called');
我目前正在通过断言未显示成功的请求 toast 消息来解决此问题,但这是一个脆弱的解决方案。
有什么想法吗?
很难测试一个动作没有发生的情况。使用这种类型的断言,您实际上只能说:
"The XHR request was not made within the 400ms
that Cypress looked for this XHR request to have been made (or whatever you set your timeout to be)"
这确实确认 XHR 请求从未被调用。
也就是说,赛普拉斯提供了一种方法来检索使用未记录的 cy.state('requests')
发出的所有 XHR 请求。您可以检查它的长度,按别名过滤它们等,以确定您想要什么。
作为路由选项中的变体设置onResponse
函数,它会删除测试
例如expect(true).to.be.false;
如果调用当前路由会触发错误
cy.route({
url: <url>,
onResponse: function () {
expect("Unexpected Https call").to.be.false;
}
})
为了简化@Jennifer Shehane 的精彩回答:
let requestsCount = (alias) => cy.state('requests').filter(a => a.alias === alias).length;
expect(requestsCount('putRequest')).to.eq(0);
您也可以将其放入 Cypress 命令文件中!
我尝试了 Jonathan 发布的简化版本,但看到类型错误:无法读取未定义的 属性 'filter' 并且 cy.state('requests') 始终未定义。
值得考虑此测试的异步性质,这是前面的示例没有考虑到的。这是一个工作示例:
cy.route('/my-route').as('myRoute')
const noExpectedCalls = 1
cy.get('@myRoute').then(() => {
expect(cy.state('requests').filter(r => r.alias === 'myRoute')).to.have.length(noExpectedCalls)
})
不幸的是,上面的 none 确实对我有用,我用这个命令让它工作:
Cypress.Commands.add('shouldBeCalled', (alias, timesCalled) => {
expect(
cy.state('requests').filter(call => call.alias === alias),
`${alias} should have been called ${timesCalled} times`
).to.have.length(timesCalled);
});
然后我这样使用:
// Checks that FetchChatList has not been called
cy.shouldBeCalled('FetchChatList', 0);
这是使用 cypress 命令断言请求计数的正确方法。
将此放入您的 commands.js
文件中:
Cypress.Commands.add('requestsCount', (alias) =>
cy
.wrap()
.then(() => cy.state('requests').filter(req => req.alias === alias).length),
);
比在您的测试中使用如下新命令:
it('should count requests', () => {
cy.server();
cy.route('**').alias('theRequest');
cy.wait('@theRequest');
cy.requestsCount('theRequest').should('eq', 1);
});
cypress 团队是这样做的 (source):
it("throws when alias is never requested", (done) => {
Cypress.config("requestTimeout", 100);
cy.on("fail", (err) => {
expect(err.message).to.include(
"`cy.wait()` timed out waiting `100ms` for the 1st request to the route: `foo`. No request ever occurred."
);
done();
});
cy.server().route(/foo/, {}).as("foo").wait("@foo.request");
});
并且来自相关的docs:
Fires when the test has failed. It is technically possible to prevent the test from actually failing by binding to this event and invoking an async done callback. However this is strongly discouraged. Tests should never legitimately fail. This event exists because it’s extremely useful for debugging purposes
cy.state
0.
此外,如果您想使用 @
调用命令,那么这将起作用。
Cypress.Commands.add('shouldBeCalled', (alias, timesCalled) => {
const aliasname = alias.substring(1);
const requests = cy.state('requests') || [];
expect(
requests.filter((call) => call.alias === aliasname),
`${aliasname} should have been called ${timesCalled} times`
).to.have.length(timesCalled);
});
cy.shouldBeCalled('@updateCalc', 1);
在 cy.route()
弃用后更新 cy.intercept()
。
如果您使用 cy.intercept()
,cy.state('requests')
将 return 具有未定义 alias
的对象,所以我改用 xhr.url
。
我把@SleepWalker 的解决方案改编成这样:
commands.js 文件中的命令:
Cypress.Commands.add('requestsCountByUrl', url =>
cy.wrap().then(() => {
const requests = cy.state('requests') || [];
return requests.filter(req => req.xhr.url === url).length;
})
);
测试中的用法:
cy.requestsCountByUrl('http://theUrl.com').should('eq', 1);
我想我找到了一种符合我预期的方式,使用 cy.intercept
和 cy.state
。
- 添加要通过
cy.intercept
嗅探的路由
- 等一个时间,你选择你信任的
- 然后看看你的URL是不是在
cy.state('routes')
.
it(`should NOT make foo request`, () => {
// listen for any request with "foo" using cy.intercept
// I like to return success just to not see warnings in the console...
cy.intercept(/.foo./, { success: true }).as("fooRequest");
cy.window().then(win => {
// do what ever logic could make the request
makeFooRequestOrSomething();
});
// use cy.wait to wiat whatever amount of time you trust that your logoc should have run
cy.wait(1000);
/*
* cy.intercept does not provide any information unless a request is made, so instead
* we can use the state and make sure our route is not in the list
*/
let routes = cy.state('routes'); // An object representing all the routes setup via cy.intercept
let fooRoutes = [];
for (let route in routes) {
// routes[route].requests is an object representing each request
for (let req in routes[route].requests) {
let reqUrl = routes[route].requests[req].request.url;
// test each URL for "foo" and if it has it, add the URL to the array
if((/foo/).test(reqUrl)) {
fooRoutes.push(reqUrl);
}
}
};
// if no request was made to our URL, our array should be empty
expect(fooRoutes).to.have.property("length", 0);
});
routes[route]
可能在某个地方有alias
,如果您想以不同的方式过滤数据,然后查看routes[route].requests
是否为空。- 我没有在任何地方找到这个文档,所以如果有更好的定义 link ,请告诉我,尤其是
cy.state
方法。
当我们有路线时:
cy.intercept('PUT', '**/shoes/*', body).as('updateShoes');
以下解决方案对我有用:
cy.get('@updateShoes').then((interception) => {
assert.isNull(interception)
});
赛普拉斯 说: 预期 null 等于 null
当“@updateShoes”路由被调用时(拦截)是一个对象:
{id: "interceptedRequest551", routeId: "1623772693273-2831", request: {…}, state: "Complete", requestWaited: false, …}
id: "interceptedRequest551"
log: {get: ƒ, unset: ƒ, invoke: ƒ, toJSON: ƒ, set: ƒ, …}
request: {headers: {…}, url: "http://localhost:8080/api/shoes/38de4e08", method: "PUT", httpVersion: "1.1", body: {…}}
requestWaited: false
response: {headers: {…}, body: {…}, url: "http://localhost:8080/api/shoes/38de4e08", method: null, httpVersion: null, …}
responseWaited: false
routeId: "1623772693273-2831"
state: "Complete"
subscriptions: []
...}
Cypress 抛出一个错误:
AssertionError
expected { Object (id, routeId, ...) } to equal null
None 在 7.6 版中对我有用,但我找到了一个非常简单的解决方案。
假设你有这样的拦截:
cy.intercept('GET', '**/foo/bar**').as('myRequest');
现在你可以这样做了:
cy.wait(2000);
cy.get('@myRequest.all').then((interceptions) => {
expect(interceptions).to.have.length(0);
});
所以你等待一段时间,当请求可能已经发生时,并确保在等待之后它没有发生。对我来说工作得很好,不需要额外的命令。 我在这里找到了解决方案:https://www.gitmemory.com/issue/cypress-io/cypress/15036/780706160