I want to find a clickable element using cypress. The clickable element always includes the text "Login" and is inside the container div. However, the catch is that I don't know if the clickable element is modeled using an <button>
, <a>
, or <input type="submit">
.
My HTML sometimes look like this:
<nav>
<button>Wrong Login Button</button>
</nav>
<div class='container'>
...
<div>
<h2>Login</h2>
...
<button>Login</button>
</div>
</div>
And sometimes like this example:
<div class='container'>
...
<div>
<h2>Login</h2>
...
<div>
<div>
<a>Login</a>
</div>
</div>
</div>
</div>
It is sometimes a <button>
, sometimes a <a>
or <input type="submit">
. And sometimes there are also more nested divs in there.
How can I find the clickable element (button, a or submit) element using cypress?
I only want to find the clickable element, so if there is a heading with the text "Login", it should be ignored.
This is nearly the answer:
cy.get('.container').contains('Login')
However, I somehow need to ignore all elements other than (button, a, and input[type=submit]). Because otherwise it would return the
Login
I need something like:
cy.get('.container').find('button OR a OR input[type=submit]').contains('Login')
I thought of writing a custom command that can be used as the example below:
cy.get('.container').findClickable('Login')
The implementation could look similar as the example below:
Cypress.Commands.add('findClickable', {prevSubject: ['element']}, (
subject: Cypress.Chainable<HTMLElement>,
text: string,
options?: Partial<Cypress.Loggable & Cypress.Timeoutable & Cypress.Withinable & Cypress.Shadow>,
) => {
const buttons = cy.wrap(subject).find('button').contains(text)
const links = cy.wrap(subject).find('a').contains(text)
const submits = cy.wrap(subject).find('input[type=submit]').contains(text)
if (buttons.length links.length submits.length !== 1) {
throw new DOMException(
`Didn't find exactly one element. Found ${buttons.length} buttons, ${links.length} links, and ${submits.length} submits.`)
}
if (buttons.length === 1)
return buttons[0]
else if (links.length === 1)
return links[0]
else
return submits[0]
})
I know that the code above does not work because of many reasons. First, there is no .length attribute and second, cypress would fail because of the timeout of the first find('buttons') method.
Does anyone know how to implement the custom command the right way?
CodePudding user response:
You can use the within
and contains
command with a combination of selector and text.
cy.get('.container').within(() => {
cy.contains('button', 'Login').click()
cy.get('input[type=submit]').click()
cy.contains('Login').click()
})
For Multiple Login, First we are checking the button is enabled or disabled, then we are clicking on it.
cy.contains('Login').each(($ele) => {
if($ele.is(":enabled")){
cy.wrap($ele).click()
}
})
You can also do, this is a more optimized code for the above snippet.
cy.contains('Login').filter(':enabled').click()