Cypress disabled button is somehow clicked anyway without waiting

Viewed 46

This is not how I would expect cypress to behave: I have a button which is only enabled when to checkboxes are checked in the table below. Before the checking of the 2 rows, the button is greyed out with:

button[data-e2e-button][disabled=true]

Now cypress checks the 2 rows and the button becomes enabled. i.e. the "[disabled=true]" disappears. My code looks like this:

Non Working Code:

cy.contains(`[data-e2e-button]`, buttonLabel, BUTTON_OPTS).should('not.be.disabled').should('be.visible').click...

When it clicks on this element, it seems like it did not wait until the button is enabled.

Only if I have a separate wait for the disabled=true to disappear it works:

Working Code:

cy.contains('[data-e2e-button][aria-disabled="true"]', buttonLabel, BUTTON_OPTS).should('not.exist');
cy.contains(`[data-e2e-button]`, buttonLabel, BUTTON_OPTS).should('not.be.disabled').should('be.visible').click...

This seems kind of ugly to me, as it ensures twice for disabled to disappear.

Here is the html code: ENABLED:

<span role="tooltip">
<a class="MuiMenuItem-root MuiMenuItem-dense MuiMenuItem-gutters MuiButtonBase-root css-brjsa3" tabindex="-1" role="menuitem"><span>
<span class="MuiBox-root css-1jjwf1f">Two Checkbox button</span>
</span>
<span class="MuiTouchRipple-root css-w0pj6f"></span>
</a>
</span>

DISABLED

<span role="tooltip">
<a class="MuiMenuItem-root MuiMenuItem-dense Mui-disabled MuiMenuItem-gutters MuiButtonBase-root Mui-disabled css-brjsa3" tabindex="-1" aria-disabled="true" role="menuitem"><span>
<span class="MuiBox-root css-1jjwf1f">Two Checkbox button</span>
</span></a></span>
3 Answers

Be careful when using negative assertions, they are often less reliable. Instead of using .should('not.be.disabled') before clicking the element, make sure the element is disabled before meeting the enabled condition.

cy.contains(`[data-e2e-button]`, buttonLabel, BUTTON_OPTS)
  .should('be.visible')
  .and('be.disabled')
// actions to meet enabled condition
cy.contains(`[data-e2e-button]`, buttonLabel, BUTTON_OPTS)
  .should('be.visible')
  .and('be.enabled')
  // now we know for sure the button is enabled and click on it
  .click()

If your attribute is aria-disabled="true" as shown here

<a class="MuiMenuItem-root MuiMenuItem-dense Mui-disabled MuiMenuItem-gutters MuiButtonBase-root Mui-disabled css-brjsa3" 
  tabindex="-1" 
  aria-disabled="true"                 // this is the attribute being checked
  role="menuitem">
  <span>
    <span class="MuiBox-root css-1jjwf1f">Two Checkbox button</span>
  </span>
</a>

then .should('be.disabled') and .should('not.be.disabled') do not work with that attribute.

They would only work with attribute disabled="true" which does not seem to be present.

It explains why this works

cy.contains('[data-e2e-button][aria-disabled="true"]', buttonLabel, BUTTON_OPTS).should('not.exist');
cy.contains(`[data-e2e-button]`, buttonLabel, BUTTON_OPTS).should('not.be.disabled').should('be.visible').click...

because in the first line does check that attribute.

Try either of these

cy.contains(`[data-e2e-button]`, buttonLabel, BUTTON_OPTS)
  .should('not.have.attr', 'aria-disabled')
  .click()

or

cy.contains(`[data-e2e-button]`, buttonLabel, BUTTON_OPTS)
  .should('have.attr', 'aria-disabled', 'false')
  .click()

You can do something like this. You can come up with a different selector as well, if this doesn't work, the idea remains the same.

cy.get('a.MuiMenuItem-root').should('exist').and('be.disabled')
//code to click the checkboxes
cy.get('a.MuiMenuItem-root').should('exist').and('be.enabled').click()

In case cy.get() doesn't work, you can use contains with selector and button label, something like:

cy.contains('a', 'button label').should('exist').and('be.disabled')
//code to click the checkboxes
cy.contains('a', 'button label').should('exist').and('be.enabled').click()
Related