Sibling element

In the example below we do not have a good selector for the warning below the user name. How do we find it?

<div class="user">
  <div class="name">Joe Smith</div>
  <p>Email not verified</p>
</div>
<style>
  .name {
    font-size: x-large;
  }
</style>

By using a CSS sibling selector +

cy.get('.name')
  .should('include.text', 'Joe')
  .find('+ p')
  .should('have.text', 'Email not verified')
// we can use the combined selector right away
cy.contains('.name + p', 'Email not verified').should(
  'be.visible',
)

You can also use the cy.nextopen in new window command

cy.get('.name')
  .should('include.text', 'Joe')
  .next('p') // cy.next allows using a selector
  .should('have.text', 'Email not verified')

Multiple elements

The sibling CSS selector returns multiple elements, one for each of the initial elements.

<div class="person">Employee 1</div>
<p>Joe</p>
<p>hourly</p>
<p class="age">27</p>
<div class="person">Employee 2</div>
<p>Anna</p>
<p>fulltime</p>
<p class="age">25</p>

Let's say we want to select just the names. Each name p is a sibling of the .person element.

cy.get('.person + p')
  .should('have.length', 2)
  .spread((first, second) => {
    expect(first, 'first name').to.have.text('Joe')
    expect(second, 'second name').to.have.text('Anna')
  })

The above can be expressed using cy.next command

cy.get('.person')
  .next() // immediate sibling
  .spread((first, second) => {
    expect(first, 'first name').to.have.text('Joe')
    expect(second, 'second name').to.have.text('Anna')
  })
  .next()
  .next()
  .should('have.class', 'age')

General sibling CSS selector

There is the general sibling CSS selector ~. Here is how we can find the .age siblings of the elements selected using the .person selector.

cy.get('.person')
  .find('~ .age')
  .should('have.length', 2)
  .spread((first, second) => {
    expect(first).to.have.text('27')
    expect(second).to.have.text('25')
  })