Coded ui tests io:contains()未等待元素

Coded ui tests io:contains()未等待元素,coded-ui-tests,cypress,Coded Ui Tests,Cypress,我们正在用cypress编写UI测试,它通常使用起来非常简单。但我一次又一次地被一个乏味的等待问题绊倒 情况非常简单。用户单击搜索按钮。然后,他选择一个元素,其中包含特定的文本。代码如下: cy.get('#search-button').click(); cy.contains('Test item 1').click(); cy.get('#cheapest-offer-button').click(); 第三次单击事件失败,因为已经cy.contains('testitem 1')没有等

我们正在用cypress编写UI测试,它通常使用起来非常简单。但我一次又一次地被一个乏味的等待问题绊倒

情况非常简单。用户单击搜索按钮。然后,他选择一个元素,其中包含特定的文本。代码如下:

cy.get('#search-button').click();
cy.contains('Test item 1').click();
cy.get('#cheapest-offer-button').click();
第三次单击事件失败,因为已经
cy.contains('testitem 1')
没有等待页面和元素被呈现。从我在测试步骤中可以看到的,它只是在页面中间点击,基本上什么都没有。因此,所有后续步骤当然都失败了

但是,如果在调用之间添加一个
wait()
,如下所示:

cy.get('#search-button').click();
cy.wait(2000);
cy.contains('Test item 1').click();
cy.get('#cheapest-offer-button').click();    
cy.get('#search-button').click();
waitForBrowser();
cy.contains('Test item 1').click();
cy.get('#cheapest-offer-button').click();
页面正确呈现后,
测试项目1
出现,单击,所有后续步骤成功


根据说明,
wait()
调用应该是不必要的,因此应该避免。我做错了什么?

看起来这是一个常见的问题

解决方案是强制cypress等待所有异步操作,就像在基于SeleniumWebDriver的框架中一样。比赛快多了。等等 执行方法:

function waitForBrowser() { 
   cy.window().then(win => {
      return new Cypress.Promise(resolve => win['requestIdleCallback'](resolve));
   });
}
就像这样使用它:

cy.get('#search-button').click();
cy.wait(2000);
cy.contains('Test item 1').click();
cy.get('#cheapest-offer-button').click();    
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();
        }));
      });
  });
}
tl;博士 为
包含的内容提供更大的超时时间

cy.get(“#搜索按钮”)。单击();
cy.contains('testitem1',{timeout:4000})。单击();
cy.get(“#最便宜的优惠按钮”)。单击();
解释 尽可能多的Cypress命令,它接受一个选项对象。您可以在
timeout
键中传递命令应等待的毫秒数,如下所示:

cy.get('#search-button').click();
cy.wait(2000);
cy.contains('Test item 1').click();
cy.get('#cheapest-offer-button').click();    
cy.get('#search-button').click();
waitForBrowser();
cy.contains('Test item 1').click();
cy.get('#cheapest-offer-button').click();
.contains('Stuff',{timeout:5000})//5秒后超时
这样,命令的行为将类似于在它之前添加了一个
wait
,但是如果命令成功,它不会像
wait
那样一直等待

本文解释了这种技术:它是如何工作的,应该如何做,以及它如何影响链式断言


如果无法单击该项的原因是可见性,则可以尝试
。单击({force:true})
,尽管这应该是最后的手段,因为它可能隐藏实际的错误。

我在尝试达到具有特定值的范围时遇到了相同的问题。 我通过提供指向span的更具体路径而不是获取页面中的所有span元素来修复它

cy.get('span').contains('Round ID') //not working
cy.get('.details span').contains('Round ID') //worked
因此,在获取要针对的类型的元素时,可以尝试更加具体。
另一个选项是wait()…

上面发布的另一个替代方法是使用

cy.contains('Test item 1').should('exist').click()
或 cy.contains('testitem 1')。应('be.visible')。单击()

我不知道为什么会这样,但它确实起作用了,它不需要设置特定的超时

或者,没有其他人建议使用

cy.server()
cy.route()


但是这需要比OP中更多的信息,您可能已经知道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();
});

很难想象会发生什么,可以展示DOM吗?(或者描述点击背后的元素和你知道发生了什么)。通常,您可以将
cy.wait()
替换为
cy.contains(选择器,newContent)
,其中newContent是一段表示提取已完成的文本。
cy.contains('testitem 1')
正在查找某个内容,尽管它尚未可见。如果cypress找不到元素,它将抛出异常并使测试失败。查看左侧的命令输出,查看调用返回的内容。您可能需要更改定位该元素的方式以使其更具体,或者添加一个
。should(“be.visible”)
将使其工作。发布命令日志和HTML的屏幕截图将帮助我们更容易地解决问题。我相信它也可以像
cy.get(selector.contains('Expected text')一样使用。
我尝试过使用这种方法,但没有得到好的结果。很抱歉工作:)太糟糕了,我们必须手动执行此操作。。。对我来说,它在Cypress 3.8.2中运行良好,现在在4.4.0中,我不得不等待。