skip to Main Content

I am having trouble finding documentation that explains how Cypress assertions work when cy.get() matches multiple elements. For example:

Markup:

<div>
  <button>one</button>
  <button class='green'>two</button>
  <button disabled>three</button>
</div>

Test:

cy.get('button').should('be.disabled');

Does Cypress assert that:

  1. the first matched element passes?
  2. all matched elements pass?
  3. at least one of the elements pass?

From experience I am guessing it is option 3 but I haven’t been able to find this explicitly addressed in the documentation.

Whereas

cy.get('button').click();

clicks… only the first button? All of them?

On the assertions, I’m afraid we are unintentionally writing tests that pass in cases where our selector incidentally matches more than one element, and one of those elements happens to match the assertion criteria.

Obviously this can be avoided with well written selectors, or use of .first() or .last() if we expect to return more than one, or .each() if we want to explicitly assert multiple elements. I’m primarily looking for confirmation on what the behavior is so I understand how Cypress works in these situations where multiple elements are selected (intentionally or otherwise.)

2

Answers


  1. For the assertions in .should(), I believe that Cypress operates in the same way that ChaiJQuery operates, which switches between validating the first element meets the criteria, or that any element meets the criteria.

    For example, attr

    Assert that the first element of the selection has the given attribute, using .attr(). Optionally, assert a particular value as well. The return value is available for chaining.

    vs. hidden

    Assert that at least one element of the selection is selected, using .is(‘:selected’).

    For other Cypress commands, you’ll have to investigate their behaviors. For an example with cy.click():

    By default, Cypress will error if you’re trying to click multiple elements. By passing { multiple: true } Cypress will iteratively apply the click to each element and will also log to the Command Log multiple times.

    So, the tl;dr answer is each chained command behaves differently.

    Login or Signup to reply.
  2. It depends on the assertion.

    There is an example here Multiple elements

    <ul id="greetings">
      <li>Hello</li>
      <li>Hi</li>
      <li>Aloha</li>
    </ul>
    
    cy.get('#greetings li')
      .should('include.text', 'Hello')
      .and('include.text', 'Hi')               // "include" allows any one 
      .and('include.text', 'Aloha')
      .and('have.text', 'HelloHiAloha')
      // let's check the jQuery text() method
      .invoke('text')
      .should('equal', 'HelloHiAloha')         // must match all 3 texts
    

    The include.text will apply to any one of the elements, but the have.text applies to all elements combined.

    cy.get('#greetings li')
      .should('have.text', 'Hello')    // fails
    

    What about be.disabled?

    From chai-jquery

    disabled

    Assert that at least one element of the selection is disabled, using .is(‘:disabled’).

    As an opposite example,

    attr(name[, value])

    Assert that the first element of the selection has the given attribute, using .attr(). Optionally, assert a particular value as well. The return value is available for chaining.

    In general, Cypress follows the rules set down by the library it uses, so this documentation is a good reference for your question.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search