【发布时间】:2018-05-01 10:47:24
【问题描述】:
我试图断言在 Cypress 中没有调用路由。我彻底翻阅了文档,但一无所获。
我正在尝试做这样的事情:
cy.get('@myRouteAlias').should('have.not.been.called');
我目前正在通过断言未显示成功的请求 toast 消息来解决此问题,但这是一个脆弱的解决方案。
有什么想法吗?
【问题讨论】:
标签: javascript chai cypress
我试图断言在 Cypress 中没有调用路由。我彻底翻阅了文档,但一无所获。
我正在尝试做这样的事情:
cy.get('@myRouteAlias').should('have.not.been.called');
我目前正在通过断言未显示成功的请求 toast 消息来解决此问题,但这是一个脆弱的解决方案。
有什么想法吗?
【问题讨论】:
标签: javascript chai cypress
在 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
【讨论】:
当我们有路线时:
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: []
...}
赛普拉斯抛出错误:
AssertionError
expected { Object (id, routeId, ...) } to equal null
【讨论】:
我想我找到了一种符合我预期的方法,使用 cy.intercept 和 cy.state。
cy.intercept添加要被嗅探的路由
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 是否为空,您可以使用它。cy.state 方法。【讨论】:
在cy.route() 弃用后更新cy.intercept()。
如果你使用cy.intercept(),cy.state('requests') 将返回未定义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.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('/my-route').as('myRoute')
const noExpectedCalls = 1
cy.get('@myRoute').then(() => {
expect(cy.state('requests').filter(r => r.alias === 'myRoute')).to.have.length(noExpectedCalls)
})
【讨论】:
这就是 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:
测试失败时触发。从技术上讲,通过绑定到此事件并调用异步完成回调来防止测试实际失败是可能的。但是,强烈建议不要这样做。测试不应该合法地失败。存在此事件是因为它对调试非常有用
【讨论】:
这是使用 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);
});
【讨论】:
cy.intercept 的人,它不适用。
不幸的是,以上都没有真正对我有用,我用这个命令得到了它:
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);
【讨论】:
我尝试了 Jonathan 发布的简化版本,但看到 TypeError: Cannot read property 'filter' of undefined and cy.state('requests') is always undefined。
【讨论】:
为了简化@Jennifer Shehane 的最佳答案:
let requestsCount = (alias) => cy.state('requests').filter(a => a.alias === alias).length;
expect(requestsCount('putRequest')).to.eq(0);
您也可以将其放入赛普拉斯命令文件中!
【讨论】:
作为路由选项中设置的变体onResponse 函数,它会丢弃测试
例如expect(true).to.be.false;
如果当前路由发生调用会触发错误
cy.route({
url: <url>,
onResponse: function () {
expect("Unexpected Https call").to.be.false;
}
})
【讨论】:
let putRequestMade = false,并在我的路线的onRequest 中放了一个日志语句和一个putRequestMade = true。我在请求之前和之后断言putRequestMade。当我在cy.wait('@putRequest') 之后expect(putRequestMade).to.eq(true) 断言失败时,我可以看到日志语句没有触发。但是,当我删除 putRequestMade 断言时,我看到了日志语句,在调试器中我可以看到 putRequestMade = true。添加一个cy.wait 等待,但如果有断言,它会立即失败!
很难测试一个动作没有发生的情况。有了这种断言,你真的只能说:
“XHR 请求不是在赛普拉斯寻找此 XHR 请求的 400ms 内发出的(或任何你设置的超时时间)”
这并没有真的确认 XHR 请求从未被调用过。
话虽如此,赛普拉斯提供了一种方法来检索使用未记录的cy.state('requests') 发出的所有 XHR 请求。您可以检查它的长度,按别名过滤它们等,以确定您想要什么。
【讨论】:
state 方法似乎不再可用。是不是被别的东西代替了?
cy.state(...) is not a function 在 Cypress v7 及以后版本中不再存在。有没有其他功能可以做同样的事情?