如何使用Cypress.io检查元素是否存在

89

如何检查元素是否存在,以便在元素存在时执行特定步骤。否则,如果元素不存在,则执行不同的步骤。

我尝试了下面的代码,但它没有起作用:

Cypress.Commands.add('deleteSometheingFunction', () => {
  cy.get('body').then($body => {
    if ($body.find(selectors.ruleCard).length) {
      let count = 0;
      cy.get(selectors.ruleCard)
        .each(() => count++)
        .then(() => {
          while (count-- > 0) {
            cy.get('body')
            // ...
            // ...
          }
        });
    }
  });
  });

我正在寻找一个简单的解决方案,可以与简单的JavaScript中的if else块或promise的then()部分结合使用。

类似于Webdriver协议下面的实现:

  1. driver.findElements(By.yourLocator).size() > 0
  2. 在等待中检查元素是否存在

请给予建议。谢谢。


2
这个回答解决了你的问题吗?如何使用Cypress检查可能不存在的元素 - Michael Freidgeim
12个回答

127

我只想补充一点,如果您决定通过检查cy.find命令的.length属性来执行if条件语句,您需要遵守Cypress的异步特性。

例如:即使appDrawerOpener按钮存在,以下条件的结果将被评估为false。

    if (cy.find("button[data-cy=appDrawerOpener]").length > 0)    //evaluates as false

但这个条件判断会被视为 true,因为 $body 变量已经在 promise 的 .then() 部分解析完成:

    cy.get("body").then($body => {
        if ($body.find("button[data-cy=appDrawerOpener]").length > 0) {   
            //evaluates as true
        }
    });

阅读Cypress文档中关于条件测试的更多信息


8
这应该是正确的答案。 - Realdinho
4
文档中说 cy.find('.progress') // 错误,无法从 'cy' 链接. 你是不是想说 if (cy.get("button[data-cy=appDrawerOpener]")...? (这并不改变答案的正确性)。 - user14783414
12
if语句中的.length不再起作用。 - Ashok kumar Ganesan
2
@AshokkumarGanesan 已经为我工作很长时间了 :) ,这仍然是一个好的解决方案。 - harmider
2
我不明白你的解决方案与问题中的解决方案有何不同。在问题中,作者也使用了cy.get('body').then( <find with $body tag>),而你也是这样做的。你能否解释一下为什么你的解决方案是正确的? - AnandShiva
显示剩余2条评论

14

之前曾有人提出过疑问:Cypress中的条件语句

因此,你基本上可以尝试这样做:

cy.get('header').then(($a) => { 
        if ($a.text().includes('Account')) {
            cy.contains('Account')
            .click({force:true})
        } else if ($a.text().includes('Sign')) { 
            cy.contains('Sign In')
            .click({force:true})  
        } else {
            cy.get('.navUser-item--account .navUser-action').click({force:true})
        }
    })

8

Cypress的所有步骤都是异步的,因此您应该在命令文件或页面对象文件中创建公共函数。

    export function checkIfEleExists(ele){
    return new Promise((resolve,reject)=>{
        /// here if  ele exists or not
        cy.get('body').find( ele ).its('length').then(res=>{
            if(res > 0){
                //// do task that you want to perform
                cy.get(ele).select('100').wait(2000);
                resolve();
            }else{
                reject();
            }
        });
    })
}


// here check if select[aria-label="rows per page"] exists
cy.checkIfEleExists('select[aria-label="rows per page"]')
.then(e=>{
        //// now do what if that element is in ,,..
        })
.catch(e=>{
    ////// if not exists...
    })

6
我找到了一个解决方案,希望能对你有所帮助! 你可以使用以下方法:
cy.window().then((win) => {
        const identifiedElement = win.document.querySelector(element)
        cy.log('Object value = ' + identifiedElement)
    });

你可以将此代码添加到 Cypress 的 commands.js 文件中。
Cypress.Commands.add('isElementExist', (element) => {

    cy.window().then((win) => {
        const identifiedElement = win.document.querySelector(element)
        cy.log('Object value = ' + identifiedElement)
    });
})

执行“querySelector”时失败:“[object Object]”不是有效的选择器。 - user9347168
这个解决方案是有效的,我尝试过其他的但都没有起作用。 - Mohamed FAIDA

4

Cypress官方文档提供了一个解决方案,可以解决确切的问题。

如何检查元素是否存在

// click the button causing the new
// elements to appear
cy.get('button').click()
cy.get('body')
  .then(($body) => {
    // synchronously query from body
    // to find which element was created
    if ($body.find('input').length) {
      // input was found, do something else here
      return 'input'
    }

    // else assume it was textarea
    return 'textarea'
  })
  .then((selector) => {
    // selector is a string that represents
    // the selector we could use to find it
    cy.get(selector).type(`found the element by selector ${selector}`)
  })

4

对我来说,以下命令可用于在Code server内测试VS code扩展:

Cypress.Commands.add('elementExists', (selector) => {
  return cy.window().then($window => $window.document.querySelector(selector));
});

我在我的 Code Server 扩展的 E2E 测试中这样使用它:

cy.visit("http://localhost:8080");
cy.wait(10000); // just an example here, better use iframe loaded & Promise.all
cy.elementExists("a[title='Yes, I trust the authors']").then((confirmBtn) => {
    if(confirmBtn) {
        cy.wrap(confirmBtn).click();
    }
});

请确保在所有内容加载完毕后再调用此检查。

如果您使用的是TypeScript,请将以下内容添加到全局类型定义中:

declare global {
  namespace Cypress {
    interface Chainable<Subject> {
      /**
       * Check if element exits
       * 
       *  @example cy.elementExists("#your-id").then($el => 'do something with the element');
       */
      elementExists(element: string): Chainable<Subject>
    }
  }
}

附言

VS Code server 严重依赖于 Iframes,这使得测试变得困难。以下博客文章将为您提供一个想法 - 使用 Cypress 测试 Iframes

如果显示了“信任模态框”,则需要上述代码来关闭它。一旦特性 disable-workspace-trust 发布后,可以将其作为 CLI 选项禁用。


1

0

对我来说,这些解决方案起作用:
cy.get('body').then($body => {
    if ($body.find("mat-option[aria-selected='true']").length) {
        //Do something if exist
    }
    else{
        //do if not exist
    }
})

1
如果有人正在寻找一种使用cy.contains来查找元素并根据结果与之交互的方法,请参阅this post以获取有关条件测试的更多详细信息。
对我来说,使用情况是当用户被提示选择时,但当选项过多时,需要在“显示更多”按钮上额外点击一次,然后才能点击“所需选项”。
命令:
Cypress.Commands.add('clickElementWhenFound', (
    content: string,
) => {
    cy.contains(content)
        // prevent previous line assertion from triggering
        .should((_) => {})
        .then(($element) => {
            if (!($element || []).length) {
                /** Do something when element was not found */
            } else {
                cy.contains(content).click();
            }
        });
});

使用方法:

// Click button with 'Submit' text if it exists
cy.clickElementWhenFound('Submit');

你的网址有问题 - ksugiarto
@ksugiarto 谢谢,我已经更新了URL。 - xab

1
这个命令如果元素不存在不会报错,如果存在则返回实际的元素。
cypress/support/commands.js
elementExists(selector) {
  cy.get('body').then(($body) => {
    if ($body.find(selector).length) {
      return cy.get(selector)
    } else {
      // Throws no error when element not found
      assert.isOk('OK', 'Element does not exist.')
    }
  })
},

使用方法:

cy.elementExists('#someSelectorId').then(($element) => {
  // your code if element exists
})

1
这不是你编写自定义命令的方式,如果这是你的意图。 - Pablo

1

我曾经遇到过类似的问题,就是无法在网页中显示按钮。我使用了以下代码来解决它。

export function clickIfExist(element) {
cy.get('body').then((body) => {
cy.wait(5000).then(() => {
  if (body.find(element).length > 0) {
    cy.log('Element found, proceeding with test')
    cy.get(element).click()
  } else {
    cy.log('Element not found, skipping test')
  }
})
})
}

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