简体   繁体   English

Cypress:尝试通过多个选择器获取一个元素

[英]Cypress: Try to get an element by multiple selectors

The Problem问题

I need a way to cy.get elements by trying multiple selectors with retries/timeouts.我需要一种通过重试/超时尝试多个选择器来cy.get元素的方法。 I'm aware this is not really the intended way to use Cypress and I've read Conditional Testing but unfortunately this is a requirement.我知道这并不是使用赛普拉斯的真正预期方式,我已经阅读了条件测试,但不幸的是这是一个要求。 It's intended to provide fallback identifiers.它旨在提供后备标识符。

My attempts so far haven't worked well.到目前为止,我的尝试效果不佳。 I've tried using 'normal' javascript promises with async/await but then cypress complains about mixing promises and commands.我尝试使用带有async/await的“正常” javascript 承诺,但随后赛普拉斯抱怨混合承诺和命令。

I've commented some test cases below with my expectations and what actually happens.我用我的期望和实际发生的情况在下面评论了一些测试用例。

Example HTML示例 HTML

<!-- example.html -->
<button id="button-1" onclick="this.style.color='red'">my button</button>

Test Cases / My Function测试用例/我的Function

beforeEach(() => {
    cy.visit('./example.html')
})

function getWithMultipleSelectors(selectors) {
    return new Cypress.Promise(resolve => {
        cy.wrap(selectors).each(selector => {
            getWithRetries(selector).then(element => {
                if (element) resolve(element)
            })
            // how do I exit out of this .each() early?
            // I only know if I found something inside .then() so I can't just do `return false`
        })
    })
}

function getWithRetries(selector, retries = 3) {
    return new Cypress.Promise(resolve => {
        cy.wrap([...Array(retries).keys()]).each(attempt => {
            cy.log(`attempt nr ${attempt}`)
            const element = cy.$$(selector)
            cy.log(element, selector)
            if (element.length === 1) {
                resolve(element[0])
                return false // ends .each()
            }
            cy.wait(1000) // wait before next attempt
        })
    })
}

// just a sanity check that the button can indeed be found
it('normal get function finds #button-1', () => {
    cy.get('#button-1').should('exist').click()
})

// to see what happens if you check existence of null or undefined
// as expected they are considered to not exist
it('cy.wrap() null and undefined', () => {
    cy.wrap(undefined).should('not.exist')
    cy.wrap(null).should('not.exist')
})

// ends with "expected undefined to exist in the DOM" which somehow passes
// but fails when trying to click()
it('finds the button with one selector', () => {
    getWithMultipleSelectors(['#button-1']).then(element => {
        cy.wrap(element).should('exist').click()
    })
})

// ends with "expected undefined to exist in the DOM" which somehow passes
// but fails when trying to click()
it('finds the button with two selectors', () => {
    getWithMultipleSelectors(['#does-not-exist', '#button-1']).then(element => {
        cy.wrap(element).should('exist').click()
    })
})

// this test should FAIL but it doesn't
it('fails if no selector matches', () => {
    getWithMultipleSelectors(['#does-not-exist']).then(element => {
        cy.wrap(element).should('not.exist').click()
    })
})

Versions Used使用的版本

Cypress package version: 7.5.0
Cypress binary version: 7.5.0
Electron version: 12.0.0-beta.14
Bundled Node version:
14.15.1

Added this function that seems to be working for me for getting an element by any of the selectors in an array.添加了这个 function 似乎对我有用,可以通过数组中的任何选择器获取元素。

Cypress.Commands.add('getMulti', (selectors) => {
    cy.document().then(($document) => {
        selectors.forEach(selector => {
          if($document.querySelector(selector)){
              return cy.get(selector).first()
          }
        })
    })
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM