我们正在使用cypress编写UI测试,这通常很容易使用。但是我一次又一次地发现了一个乏味的等待问题。
场景非常简单。用户单击搜索按钮。然后,他选择具有特定文本的元素之一。这是代码:
cy.get('#search-button').click();
cy.contains('Test item 1').click();
cy.get('#cheapest-offer-button').click();
第三次点击事件失败,因为已经cy.contains('Test item 1')
不再等待页面和元素的呈现。根据我在测试步骤中看到的内容,它只需单击页面中间的按钮,实际上什么也没做。因此,所有后续步骤当然都会失败。
但是,如果我在这样的调用之间添加wait()
:
cy.get('#search-button').click();
cy.wait(2000);
cy.contains('Test item 1').click();
cy.get('#cheapest-offer-button').click();
页面呈现正确,出现Test item 1
,单击并完成所有后续步骤。
根据best practices,wait()
调用不是必需的,因此应避免。我在这里做什么错了?
答案 0 :(得分:1)
上面发布的内容的另一种替代方法是使用类似的
cy.contains('Test item 1').should('exist').click()
或 cy.contains('测试项目1')。应该('be.visible')。click()
我不确定为什么会这样,但确实可以,不需要设置特定的超时时间。
或者没有其他人建议使用
cy.server()
cy.route()
和
cy.wait('@routeAlias')
但这需要比OP中更多的信息
答案 1 :(得分:0)
这似乎是常见的问题https://github.com/cypress-io/cypress/issues/695。
解决方案是强制cypress等待所有异步操作,例如在基于Selenium Webdriver的框架中。它比cy.wait()快得多 执行方法:
function waitForBrowser() {
cy.window().then(win => {
return new Cypress.Promise(resolve => win['requestIdleCallback'](resolve));
});
}
然后像这样使用它:
cy.get('#search-button').click();
waitForBrowser();
cy.contains('Test item 1').click();
cy.get('#cheapest-offer-button').click();
如果使用 Angular ,最好使用 waitForAngular 代替 waitForBrowser
function waitForAngular() {
return cy.window().then(win => {
return new Cypress.Promise((resolve, reject) => {
let testabilities = win['getAllAngularTestabilities']();
if (!testabilities) {
return reject(new Error('No testabilities. Check Angular API'));
}
let count = testabilities.length;
testabilities.forEach(testability => testability.whenStable(() => {
count--;
if (count !== 0) return;
resolve();
}));
});
});
}
答案 2 :(得分:0)
在cypress.json文件中添加以下内容并进行检查。它应该可以正常工作。
{
"execTimeout": 60000,
"taskTimeout": 60000,
"defaultCommandTimeout": 20000,
"pageLoadTimeout": 200000,
"responseTimeout": 10000
}
答案 3 :(得分:0)
为contains
提供更大的超时时间:
cy.get('#search-button').click();
cy.contains('Test item 1', { timeout: 4000 }).click();
cy.get('#cheapest-offer-button').click();
与许多赛普拉斯命令contains
have a second argument一样,它接受一个选项对象。您可以像这样在timeout
键中传递命令应等待的毫秒数:
.contains('Stuff', { timeout: 5000 }) // Timeout after 5 secs
通过这种方式,命令的行为就像您在其前面添加了wait
一样,但是如果命令成功执行,则不会一直像wait
那样一直等待。
official Cypress docs on timeouts解释了这种技术:它是如何工作的,应该如何做以及如何影响链接的断言。
如果您不能单击该项目的原因是可见性,则可以尝试.click({ force: true })
,尽管这应该是最后的选择,因为它可能会隐藏实际的错误。
答案 4 :(得分:0)
当尝试达到某个值时,我遇到了同样的问题。 我通过提供跨度的更具体路径而不是获取页面中的所有跨度元素来修复它。
cy.get('span').contains('Round ID') //not working
cy.get('.details span').contains('Round ID') //worked
因此,在获取要定位的类型的元素时,您可以尝试更加具体。 另一种选择是wait()...
答案 5 :(得分:0)
您可能已经知道Cypress命令是异步的。因此,如果某个命令依赖于另一个动作,那么最好将其写入依赖动作的子例程中。
cy.get('#search-button').click().then(() => {
cy.contains('Test item 1').should('be.visible').click();
cy.get('#cheapest-offer-button').should('be.visible').click();
});