如何等待元素可见?

59

是否有可能等待直到某个元素可见?

cy.get('[data-test=submitIsVisible]').should('be.visible');

如果提交按钮不可见,那么这应该会出错。我想等待提交按钮变为可见。

主要用例是视觉测试,即对页面进行截图。


4
你是说这个不起作用吗?看起来应该可以。你能提供更多的上下文信息,比如页面HTML是什么,以及导致按钮从不可见到可见的原因是什么。 - user12697177
2
@MarionMorrison 我刚刚误读了文档,如果下面的答案是正确的(我还没有完全测试),那就太好了。 - KayakinKoder
1
我仍然觉得惊人的是,多年之后这个问题被发布,并且显然帮助了很多人,竟然有人决定关闭这个问题。这是又一个例子,说明为什么许多人认为 SO 是“有毒”的。 - KayakinKoder
4个回答

117
您可以像这样等待元素可见:
// Give this element 10 seconds to appear
cy.get('[data-test=submitIsVisible]', { timeout: 10000 }).should('be.visible');

根据Cypress文档: 基于DOM的命令将在失败之前自动重试并等待其对应的元素存在。
Cypress为您提供了许多强大的查询DOM的方法,所有这些方法都包含了重试和超时逻辑。
另一种等待元素在DOM中出现的方法是通过超时。 Cypress命令默认超时时间为4秒,但大多数Cypress命令都有可定制的timeout选项。超时可以在全局或每个命令的基础上进行配置。 在此处查看可定制的timeout选项列表here

有些情况下,你的DOM元素可能无法被执行。Cypress为你提供了一个强大的{force:true}选项,你可以将其传递给大多数动作命令。

警告:

正如Anthony Cregan所指出的那样,.should('be.visible')断言检查一个元素是否在页面上可见,但不一定在视口中。这意味着即使在测试运行时元素不在屏幕的可见区域内,该断言也会返回true。

更多推荐阅读:


6
我已经测试过一次负面的结果,而.should('be.visible')似乎意味着该元素在页面上可见(并不一定是在视口中可见)。我认为值得指出这点,因为我正在测试一个scrollIntoView实现,即使元素不在视口中,这个实现也会返回true。 - Anthony Cregan
我还使用了{timeout: xxxxx}作为第二个参数。 - Wirat Leenavonganan

57

已更新至Cypress v12

如果你想了解Cypress如何等待某个元素变得可见,可以参考以下示例。

通过这段代码,你可以测试delaytimeout如何影响.should('be.visible')断言的结果。

步骤

  1. Add a simple page to a VSCode project containing Cypress v12.1.0 Call it index.html

    <html>
      <body>
        <h2>API fetched data</h2>
        <span>will become visible here</span>
      </body>
      <script>
        fetch('https://jsonplaceholder.typicode.com/posts/1')
          .then(response => response.json())
          .then(data => document.querySelector('span').innerText = data.title )
      </script>
    </html>
    
  2. Right-click index.html and choose "Open with Live Server" to activate the page.

  3. Add this test to see how Cypress waits for the API data

    describe('test the waiting of API data', () => {
    
      const timings = [
        { delay: 0, timeout: 4000 },     // default, passes
        { delay: 2000, timeout: 4000 },  // passes 
        { delay: 4000, timeout: 4000 },  // flaky
        { delay: 5000, timeout: 4000 },  // fails
        { delay: 5000, timeout: 10000 },  // passes
      ]
    
      timings.forEach(timing => {
    
        const {delay, timeout} = timing;
    
        it(`delayed API by ${delay} ms, command timout is ${timeout} ms`, () => {
    
          cy.intercept('https://jsonplaceholder.typicode.com/posts/1', (req) => {
            req.continue((res) => res.setDelay(delay))
          })
    
          cy.visit('http://127.0.0.1:5500/index.html')
    
          cy.contains('sunt aut facere', {timeout})
            .should('be.visible')
        })
      })
    })
    

结果

enter image description here

这表明接收数据的延迟越长,可见性断言所需的超时时间就越大。


为什么呢?这样做有什么意义呢?(很明显,如果你的超时时间比延迟时间短,它就会失败 - 如果没有出现,那就是看不见的。) - Apollo
但为什么?这样做有什么意义吗?(很明显,如果你的超时时间比延迟时间短,它就会失败——如果它不存在,就看不见它。) - undefined
8
我喜欢它,这是一个很好的可重复测试Cypress等待元素可见的方式。 - Lyonne
@lola lchingbola,我们可以使用cypress-wait-until插件来覆盖默认的命令超时时间吗? - Deepak
1
不,它们在不同的地方实现。将超时视为一个循环,当条件满足时停止 - Cypress实现了命令超时,而插件有自己的循环来处理超时。 - Lola Ichingbola

2

您也可以通过将以下脚本传递到cypress.config.js文件中来完成此操作

e2e: {
    defaultCommandTimeout: 25000,
}

根据您的需求传递defaultCommandTimeout


-2
尝试使用 element.should('have.length.greaterThan', 0).and('be.visible')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接