# Traversal

Examples of traversing DOM elements in Cypress, for a full reference of commands, go to docs.cypress.io (opens new window)

# .children() (opens new window)

To get children of DOM elements, use the .children() command.

<ol class="traversal-breadcrumb breadcrumb">
  <li class="breadcrumb-item"><a href="#">Home</a></li>
  <li class="breadcrumb-item"><a href="#">Library</a></li>
  <li class="breadcrumb-item active">Data</li>
</ol>
cy.get('.traversal-breadcrumb')
  .children('.active')
  .should('contain', 'Data')

You can get the number of children and check it using have.length assertions. Even hidden elements are counted.

<ol id="fruit-cart">
  <li>Oranges</li>
  <li>Grapes</li>
  <li style="display:none">Apples (sold out)</li>
</ol>
  1. Oranges
  2. Grapes
  3. Apples (sold out)
// confirm the total number of children
cy.get('#fruit-cart').children().should('have.length', 3)
// confirm the number of visible children
cy.get('#fruit-cart')
  // use the jQuery pseudo selector ":visible"
  .children(':visible')
  .should('have.length', 2)
// confirm the number of hidden children
cy.get('#fruit-cart')
  // use the jQuery pseudo selector ":hidden"
  .children(':hidden')
  .should('have.length', 1)
// get the number of hidden children
// using "not visible" pseudo selectors
cy.get('#fruit-cart')
  .children(':not(:visible)')
  .should('have.length', 1)

# .closest() (opens new window)

To get the closest ancestor DOM element, use the .closest() command.

<ul class="list-group">
  <li class="list-group-item">
    <span class="badge">14</span>
    Events
  </li>
  <li class="list-group-item">
    <span class="badge traversal-badge">54</span>
    Friends
  </li>
</ul>
  • 14 Events
  • 54 Friends
cy.get('.traversal-badge')
  .closest('ul')
  .should('have.class', 'list-group')

# .eq() (opens new window)

To get a DOM element at a specific index, use the .eq() command.

<ul class="traversal-list">
  <li>tabby</li>
  <li>siamese</li>
  <li>persian</li>
  <li>sphynx</li>
  <li>burmese</li>
</ul>
  • tabby
  • siamese
  • persian
  • sphynx
  • burmese
cy.get('.traversal-list>li').eq(1).should('contain', 'siamese')

# .filter() (opens new window)

To get DOM elements that match a specific selector, use the .filter() command.

<ul class="traversal-nav nav nav-tabs">
  <li class="nav-item">
    <a class="nav-link" href="#">Home</a>
  </li>
  <li class="nav-item">
    <a class="nav-link active" href="#">About</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" href="#">Services</a>
  </li>
</ul>
cy.get('.traversal-nav > li a')
  .filter('.active')
  .should('contain', 'About')

# Elements with an attribute

Let's grab all row elements, but then keep only the elements with an attribute line present:

<table id="filter-attribute">
  <tbody>
    <tr>
      <td>No line</td>
    </tr>
    <tr>
      <td>No line</td>
    </tr>
    <!-- attribute line has no value at all -->
    <tr line>
      <td>line</td>
    </tr>
    <tr line="up">
      <td>line</td>
    </tr>
    <tr line="down">
      <td>line</td>
    </tr>
    <tr>
      <td>No line</td>
    </tr>
  </tbody>
</table>
No line
No line
line
line
line
No line
cy.get('#filter-attribute tr')
  // only interested in the elements
  // that have the attribute "line"
  .filter('[line]')
  .should('have.length', 3)

# Visible elements

You can use .filter to find visible elements using jQuery selector :visible

<ul class="visible-items">
  <li>first</li>
  <li style="display:none">second</li>
  <li style="display:none">third</li>
  <li>fourth</li>
</ul>
  • first
  • second
  • third
  • fourth
cy.get('.visible-items li')
  .should('have.length', 4) // all LI items
  // from all found elements, find only the visible ones
  .filter(':visible')
  .should('have.length', 2) // only 2 visible LI items

Tip: you can make the test more robust against flake by merging the two commands cy.get + .filter into a single one following the advice given in the Cypress Retry-ability (opens new window) guide.

cy.log('**single :visible selector query**')
// use a single CSS + :visible jQuery selector
cy.get('.visible-items li:visible')
  // only 2 visible LI items
  .should('have.length', 2)

# Using a callback function

You can filter elements using a predicate callback function.

Let's find all list items with the text "cat" or class "pet".

<ul id="animals">
  <li class="pet">Puppy</li>
  <li>Small cat</li>
  <li>Large cat</li>
  <li>Pet tarantula</li>
  <li class="pet">Hamster</li>
</ul>
  • Puppy
  • Small cat
  • Large cat
  • Pet tarantula
  • Hamster
cy.get('#animals li')
  // ensure we have all items
  .should('have.length', 5)
  // find the items we are interested in
  .filter((k, el) => {
    // k is the 0-based index
    // el is the DOM element
    return (
      el.classList.contains('pet') ||
      el.innerText.includes('cat')
    )
  })
  .should('have.length', 4)

Watch the video Use cy.filter For Complex Element Filtering (opens new window). Find another example in the recipe Computed style for example.

# Skip an element with certain text

Let's say we want to grab the list of job options from the list below. Notice that one of the entries has the descriptive text and should be skipped.

<ul id="jobs">
  <li>(Pick your current job)</li>
  <li>Teacher</li>
  <li>Nurse</li>
  <li>Driver</li>
</ul>
  • (Pick your current job)
  • Teacher
  • Nurse
  • Driver

We can skip the non-job list item in several ways.

// 1. skip using the cy.filter(callback)
cy.get('#jobs li')
  .filter((k, el) => !el.innerText.includes('Pick'))
  .should('have.length', 3)
// 2. skip using the cy.filter(callback) using the index
cy.get('#jobs li')
  // filter out the very first element
  .filter((k) => k > 0)
  .should('have.length', 3)
// 3. filter using the text and jQuery
// :not and :contains selectors
cy.get('#jobs li')
  .filter(':not(:contains("Pick"))')
  .should('have.length', 3)

# .find() (opens new window)

To get descendant DOM elements of the selector, use the .find() command.

<ul class="pagination traversal-pagination">
  <li class="page-item">
    <a class="page-link" href="#">
      <span>&laquo;</span>
    </a>
  </li>
  <li class="page-item">
    <a class="page-link" href="#">1</a>
  </li>
  <li class="page-item">
    <a class="page-link" href="#">2</a>
  </li>
  <li class="page-item">
    <a class="page-link" href="#">3</a>
  </li>
  <li class="page-item">
    <a class="page-link" href="#">4</a>
  </li>
  <li class="page-item">
    <a class="page-link" href="#">5</a>
  </li>
  <li class="page-item">
    <a class="page-link" href="#">
      <span>&raquo;</span>
    </a>
  </li>
</ul>
// 5 individual links plus "prev" and "next" links
cy.get('.traversal-pagination')
  .find('li.page-item')
  .find('a')
  .should('have.length', 7)

# Finds all elements

The .find() command is a child command. For every element yielded by the parent command, .find finds the elements matching the selectors.

<ul id="a-list">
  <li>first</li>
  <li>second</li>
  <li>third</li>
</ul>
  • first
  • second
  • third
cy.get('ul#a-list').find('li').should('have.length', 3)

Now imagine we grab the <LI> elements and try to find elements in each one.

<ul id="anchors">
  <li><a>link A</a>, <a>link B</a></li>
  <li><a>link C</a>, <a>link D</a></li>
  <li><a>link E</a>, <a>link F</a></li>
</ul>
cy.get('ul#anchors li')
  .should('have.length', 3)
  // inside each LI element, find the A elements
  .find('a')
  .should('have.length', 6)

If we want to find every child element with href attribute:

<ul id="links">
  <li><a href="a">link A</a>, <a>link B</a></li>
  <li><a>link C</a>, <a href="d">link D</a></li>
  <li><a href="e">link E</a>, <a href="f">link F</a></li>
</ul>

Notice how only some of the <A> elements have href attribute

cy.get('ul#links li')
  .should('have.length', 3)
  // inside each LI element, find the elements with href attribute
  .find('[href]')
  .should('have.length', 4)
<ul id="incomplete-links">
  <li><a href="a">link A</a>, <a>link B</a></li>
  <li><a>link C</a>, <a href="d">link D</a></li>
  <li><a href="e">link E</a>, <a href="f">link F</a></li>
</ul>

Let's find LI elements, then inside each find A elements without href attribute. We can use the jQuery selector :not to search for elements without an attribute.

cy.get('ul#incomplete-links li')
  .should('have.length', 3)
  .find('a:not([href])')
  // only two links are missing "href" attribute
  .should('have.length', 2)

# .first() (opens new window)

To get the first DOM element within elements, use the .first() command.

<table class="table traversal-table">
  <thead>
    <tr>
      <th>#</th>
      <th>First Name</th>
      <th>Last Name</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>Jane</td>
      <td>Lane</td>
    </tr>
    <tr>
      <td>2</td>
      <td>John</td>
      <td>Doe</td>
    </tr>
  </tbody>
</table>
# First Name Last Name
1 Jane Lane
2 John Doe
cy.get('.traversal-table td').first().should('contain', '1')

# :first selector

You can also use :first CSS selector to merge the cy.get and .first commands into a single one for better retry-ability (opens new window)

<table class="table traversal-table">
  <thead>
    <tr>
      <th>#</th>
      <th>First Name</th>
      <th>Last Name</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>Jane</td>
      <td>Lane</td>
    </tr>
    <tr>
      <td>2</td>
      <td>John</td>
      <td>Doe</td>
    </tr>
  </tbody>
</table>
# First Name Last Name
1 Jane Lane
2 John Doe
// get the first table cell using the :first CSS selector
cy.get('.traversal-table td:first').should('have.text', '1')
// get the first row
cy.get('.traversal-table tbody tr:first').contains('td', 'Lane')

# .last() (opens new window)

To get the last DOM element within elements, use the .last() command.

<div class="traversal-buttons">
  <a class="btn btn-default" href="#" role="button">Link</a>
  <button class="btn btn-default" type="submit">
    Button
  </button>
  <input class="btn btn-default" type="button" value="Input" />
  <input class="btn btn-default" type="submit" value="Submit" />
</div>
Link
cy.get('.traversal-buttons .btn')
  .last()
  .should('contain', 'Submit')
// you can also use the CSS selector :last to avoid
// using a separate .last() command
cy.get('.traversal-buttons .btn:last').should(
  'contain',
  'Submit',
)

# .next() (opens new window)

To get the next sibling DOM element within elements, use the .next() command.

<ul class="traversal-ul">
  <li>apples</li>
  <li class="second">oranges</li>
  <li>bananas</li>
</ul>
  • apples
  • oranges
  • bananas
cy.get('.traversal-ul')
  .contains('apples')
  .next()
  .should('have.class', 'second')
  .and('contain', 'oranges')

See also Sibling element recipe.

# .next() (opens new window) with selector

Given the previous element (or several), we can find the next element matching the given selector.

<ul id="next-selector">
  <li>apples</li>
  <li>oranges</li>
  <li>bananas</li>
  <li class="selected">pineapples</li>
</ul>
  • apples
  • oranges
  • bananas
  • pineapples
// currently does not work due to bug 19724
cy.get('#next-selector li')
  .first()
  .next('.selected')
  .should('have.text', 'pineapples')

Workaround while #19724 (opens new window) is open

// currently does not work due to bug 19724
cy.get('#next-selector li')
  .first()
  .nextAll()
  .filter('.selected')
  .should('have.text', 'pineapples')

See the video How To Report A Cypress Bug (opens new window).

# .nextAll() (opens new window)

To get all of the next sibling DOM elements within elements, use the .nextAll() command.

<ul class="traversal-next-all">
  <li>apples</li>
  <li class="second">oranges</li>
  <li>bananas</li>
  <li>pineapples</li>
  <li>grapes</li>
</ul>
  • apples
  • oranges
  • bananas
  • pineapples
  • grapes
cy.get('.traversal-next-all')
  .contains('oranges')
  .nextAll()
  .should('have.length', 3)

# .nextUntil() (opens new window)

To get all of the next sibling DOM elements within elements until another element, use the .nextUntil() command.

<ul class="healthy-foods">
  <li id="fruits" class="header">Fruits</li>
  <li>apples</li>
  <li>oranges</li>
  <li>bananas</li>
  <li id="veggies" class="header">Vegetables</li>
  <li>cucumbers</li>
  <li>carrots</li>
  <li>corn</li>
  <li id="nuts" class="header">Nuts</li>
  <li>walnuts</li>
  <li>cashews</li>
  <li>almonds</li>
</ul>
<style>
  .header {
    font-weight: bolder;
  }
</style>
  • Fruits
  • apples
  • oranges
  • bananas
  • Vegetables
  • cucumbers
  • carrots
  • corn
  • Nuts
  • walnuts
  • cashews
  • almonds
cy.get('#veggies')
  .nextUntil('#nuts')
  .should('have.length', 3)
  .and(($veggies) => {
    expect($veggies[0]).to.have.text('cucumbers')
    expect($veggies[1]).to.have.text('carrots')
    expect($veggies[2]).to.have.text('corn')
  })

# .not() (opens new window)

To remove DOM element(s) from the set of elements, use the .not() command.

<div class="traversal-disabled">
  <button
    type="button"
    class="btn btn-default"
    disabled="disabled"
  >
    Disabled
  </button>
  <button type="button" class="btn btn-default">Button</button>
</div>
cy.get('.traversal-disabled .btn')
  .not('[disabled]')
  .should('not.contain', 'Disabled')

# Find all incomplete items

Another example, showing the .not command vs jQuery :not(...) selector. Let's say we have several TODO items, and some of them are already completed.

<style>
  .todo.completed {
    text-decoration: line-through;
    color: gray;
  }
</style>
<ul id="todo-items">
  <li class="todo completed">Code apps</li>
  <li class="todo">Write tests</li>
  <li class="todo completed">Get paid</li>
</ul>
  • Code apps
  • Write tests
  • Get paid
cy.get('#todo-items').within(() => {
  // there are two completed items
  cy.get('.todo.completed').should('have.length', 2)
  // but how do we find the incomplete items?
  // 1. select all elements with class "todo"
  // 2. remove all elements with class "completed"
  cy.get('.todo').not('.completed').should('have.length', 1)
  // ALTERNATIVE: a slightly more robust way that does not split the query
  // commands; we can use the jQuery ":not" selector
  cy.get('.todo:not(.completed)').should('have.length', 1)
})

# .parent() (opens new window)

To get parent DOM element of elements, use the .parent() command.

<p>
  Morbi leo risus, porta ac consectetur ac,
  <mark class="traversal-mark">highlight</mark> vestibulum at
  eros.
</p>

Morbi leo risus, porta ac consectetur ac, highlight vestibulum at eros.

cy.get('.traversal-mark')
  .parent()
  .should('contain', 'Morbi leo risus')

# .parents() (opens new window)

To get parent DOM elements of elements, use the .parents() command.

<blockquote>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
  <footer>
    Someone famous in
    <cite class="traversal-cite">Source Title</cite>
  </footer>
</blockquote>

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Someone famous in Source Title
cy.get('.traversal-cite').parents().should('match', 'blockquote')

# .parentsUntil() (opens new window)

To get parents DOM element of elements until other element, use the .parentsUntil() command.

<ul class="nav clothes-nav">
  <li>
    <a href="#">Clothes</a>
    <ul class="menu">
      <li>
        <a href="/shirts">Shirts</a>
      </li>
      <li class="active">
        <a href="/pants">Pants</a>
      </li>
    </ul>
  </li>
</ul>
cy.get('.clothes-nav')
  .find('.active')
  .parentsUntil('.clothes-nav')
  .should('have.length', 2)

# .prev() (opens new window)

To get the previous sibling DOM element within elements, use the .prev() command.

<ul class="birds list-group">
  <li class="list-group-item">Cockatiels</li>
  <li class="list-group-item">Lorikeets</li>
  <li class="list-group-item active">Cockatoos</li>
  <li class="list-group-item">Conures</li>
  <li class="list-group-item">Eclectus</li>
</ul>
  • Cockatiels
  • Lorikeets
  • Cockatoos
  • Conures
  • Eclectus
cy.get('.birds')
  .find('.active')
  .prev()
  .should('contain', 'Lorikeets')

# .prevAll() (opens new window)

To get all previous sibling DOM elements within elements, use the .prevAll() command.

<ul class="fruits-list">
  <li>apples</li>
  <li>oranges</li>
  <li class="third">bananas</li>
  <li>pineapples</li>
  <li>grapes</li>
</ul>
  • apples
  • oranges
  • bananas
  • pineapples
  • grapes
cy.get('.fruits-list')
  .find('.third')
  .prevAll()
  .should('have.length', 2)

# .prevUntil() (opens new window)

To get all previous sibling DOM elements within elements until other element, use the .prevUntil() command.

<ul class="foods-list">
  <li id="fruits" class="header">Fruits</li>
  <li>apples</li>
  <li>oranges</li>
  <li>bananas</li>
  <li id="veggies" class="header">Vegetables</li>
  <li>cucumbers</li>
  <li>carrots</li>
  <li>corn</li>
  <li id="nuts" class="header">Nuts</li>
  <li>walnuts</li>
  <li>cashews</li>
  <li>almonds</li>
</ul>
  • Fruits
  • apples
  • oranges
  • bananas
  • Vegetables
  • cucumbers
  • carrots
  • corn
  • Nuts
  • walnuts
  • cashews
  • almonds
cy.get('.foods-list')
  .find('#nuts')
  .prevUntil('#veggies')
  .should('have.length', 3)

# .siblings() (opens new window)

To get all sibling DOM elements of elements, use the .siblings() command.

<ul class="nav nav-pills traversal-pills">
  <li class="active"><a href="#">Home</a></li>
  <li><a href="#">Profile</a></li>
  <li><a href="#">Messages</a></li>
</ul>
cy.get('.traversal-pills .active')
  .siblings()
  .should('have.length', 2)