Blo*_*die 11 cypress cypress-intercept
我在我的应用程序中实现了 API 数据缓存,这样如果数据已经存在,就不会重新获取。
我可以拦截初始获取
cy.intercept('**/api/things').as('api');
cy.visit('/things')
cy.wait('@api') // passes
Run Code Online (Sandbox Code Playgroud)
为了测试缓存是否正常工作,我想明确地测试相反的情况。
如何修改cy.wait()类似于.should('not.exist')修改方式的行为cy.get()以允许负逻辑通过?
// data is cached from first route, how do I assert no call occurs?
cy.visit('/things2')
cy.wait('@api')
.should('not.have.been.called') // fails with "no calls were made"
Run Code Online (Sandbox Code Playgroud)
最小可重复示例
<body>
<script>
setTimeout(() =>
fetch('https://jsonplaceholder.typicode.com/todos/1')
}, 300)
</script>
</body>
Run Code Online (Sandbox Code Playgroud)
由于我们测试的是阴性结果,因此首先使测试失败很有用。提供上面的 HTML 并使用它来确认测试失败,然后删除fetch(),测试应该通过。
我也尝试过,但在路线更改发生后,cy.spy()很难避免应用程序中出现任何延迟。cy.wait()
const spy = cy.spy()
cy.intercept('**/api/things', spy)
cy.visit('/things2')
cy.wait(2000)
.then(() => expect(spy).not.to.have.been.called)
Run Code Online (Sandbox Code Playgroud)
在 100 次迭代的燃烧测试中运行,这似乎没问题,但在我看来,这种方法仍然有可能出现片状测试。
更好的方法是递归地轮询间谍:
const spy = cy.spy()
cy.intercept('**/api/things', spy)
cy.visit('/things2')
const waitForSpy = (spy, options, start = Date.now()) => {
const {timeout, interval = 30} = options;
if (spy.callCount > 0) {
return cy.wrap(spy.lastCall)
}
if ((Date.now() - start) > timeout) {
return cy.wrap(null)
}
return cy.wait(interval, {log:false})
.then(() => waitForSpy(spy, {timeout, interval}, start))
}
waitForSpy(spy, {timeout:2000})
.should('eq', null)
Run Code Online (Sandbox Code Playgroud)
附加包cypress-if可以更改默认命令行为。
cy.get(selector)
.if('exist').log('exists')
.else().log('does.not.exist')
Run Code Online (Sandbox Code Playgroud)
假设您的 API 调用是在触发它们的操作后 1 秒内进行的 - cy.visit().
cy.visit('/things2')
cy.wait('@alias', {timeout:1100})
.if(result => {
expect(result.name).to.eq('CypressError') // confirm error was thrown
})
Run Code Online (Sandbox Code Playgroud)
您将需要覆盖该cy.wait()命令来检查链接.if()命令。
Cypress.Commands.overwrite('wait', (waitFn, subject, selector, options) => {
// Standard behavior for numeric waits
if (typeof selector === 'number') {
return waitFn(subject, selector, options)
}
// Modified alias wait with following if()
if (cy.state('current').attributes.next?.attributes.name === 'if') {
return waitFn(subject, selector, options).then((pass) => pass, (fail) => fail)
}
// Standard alias wait
return waitFn(subject, selector, options)
})
Run Code Online (Sandbox Code Playgroud)
到目前为止,只有cy.get()和cy.contains()被默认覆盖。
如果if()语法感觉不正确,可以在自定义命令中使用相同的逻辑
Cypress.Commands.add('maybeWaitAlias', (selector, options) => {
const waitFn = Cypress.Commands._commands.wait.fn
// waitFn returns a Promise
// which Cypress resolves to the `pass` or `fail` values
// depending on which callback is invoked
return waitFn(cy.currentSubject(), selector, options)
.then((pass) => pass, (fail) => fail)
// by returning the `pass` or `fail` value
// we are stopping the "normal" test failure mechanism
// and allowing downstream commands to deal with the outcome
})
cy.visit('/things2')
cy.maybeWaitAlias('@alias', {timeout:1000})
.should(result => {
expect(result.name).to.eq('CypressError') // confirm error was thrown
})
Run Code Online (Sandbox Code Playgroud)