Filter elements
Watch this recipe explained in the video Filter Elements Using jQuery Pseudo-Classes.
<ul>
<li>Apples</li>
<li>Grapes</li>
<li>Pears</li>
<li>Kiwi</li>
</ul>
We can get all LI
elements and then pick a particular element using its index and cy.eq command
// using the cy.eq command to pick one element
cy.get('li').eq(2).should('have.text', 'Pears')
filter using :odd pseudo-selector
How would you pick several LI
elements? You can use jQuery pseudo-classes. For example, to pick items 1, 3, 5, etc from the list yielded by the cy.get
command you should use the jQuery :odd pseudo-class with cy.filter command.
// using jQuery :odd pseudo-class
cy.get('li')
.filter(':odd')
.should('have.length', 2)
.first()
.should('have.text', 'Grapes')
Note: jQuery has deprecated the :odd
in favor of the method odd()
, thus you would write the equivalent test as
// using jQuery odd() method
cy.get('li')
.invoke('odd')
.should('have.length', 2)
.first()
.should('have.text', 'Grapes')
filter using :even pseudo-selector
You can select elements 0, 2, 4, etc using :even
jQuery pseudo-class or by invoking the jQuery even()
method
// using jQuery :even pseudo-class
cy.get('li')
.filter(':even')
.should('have.length', 2)
.last()
.should('have.text', 'Pears')
// using jQuery even() method
cy.get('li')
.invoke('even')
.should('have.length', 2)
.last()
.should('have.text', 'Pears')
filter using :eq pseudo-selector
What if you want to select the 2nd and the 3rd elements? You can use the jQuery :eq(index)
pseudo-class to pick individual elements and combine them using the CSS ,
operator.
// select the 2nd and the 3rd elements
// using jQuery :eq(index) pseudo-class
cy.get('li')
.filter(':eq(1), :eq(2)')
.should('have.length', 2)
.and('include.text', 'Grapes')
.and('include.text', 'Pears')
filter using :gt and :lt pseudo-selector
To select all elements after a certain index or before it, you can use jQuery :gt()
and :lt()
pseudo-classes with a zero-based index.
// select the elements after the first two
// using jQuery :gt(index) pseudo-class
cy.get('li')
.filter(':gt(1)')
.should('have.length', 2)
.and('include.text', 'Pears')
.and('include.text', 'Kiwi')
// select the first two elements
// using jQuery :lt(index) pseudo-class
cy.get('li')
.filter(':lt(2)')
.should('have.length', 2)
.and('include.text', 'Apples')
.and('include.text', 'Grapes')
// select the middle two elements out of 4
// using a combination of :gt() and :lt()
cy.get('li')
.filter(':gt(0)')
.should('have.length', 3)
.filter(':lt(2)')
.should('have.length', 2)
.and('include.text', 'Grapes')
.and('include.text', 'Pears')
filter using custom callback
We can write custom filtering logic by passing a callback to cy.filter(callback)
command. For example, let's only select elements with the text starting with the letter "k".
cy.get('li')
// cy.filter(callback) where the callback
// receives the index and the element reference
.filter((k, el) => {
return el.innerText.toLowerCase()[0] === 'k'
})
.should('have.text', 'Kiwi')
filter using attributes
📺 Watch this example explained in the video Cypress cy.filter Command Attribute Examples.
<ul>
<li data-price="1">Apples</li>
<li data-price="3">Grapes</li>
<li data-price="3">Pears</li>
<li data-price="10">Kiwi</li>
<li>Potatoes</li>
</ul>
Let's find all elements with price "1" using the data-price
attribute
cy.get('li')
.filter('[data-price=1]')
.should('have.length', 1)
.and('have.text', 'Apples')
Let's find all elements with price "3". I will use the "should read" assertion from cypress-map plugin.
cy.get('li')
.filter('[data-price=3]')
.should('read', ['Grapes', 'Pears'])
Find all elements that have the data-price
attribute
cy.get('li').filter('[data-price]').should('have.length', 4)
Find all elements without the data-price
attribute; there should be just potatoes.
cy.get('li').not('[data-price]').should('read', ['Potatoes'])
// same as
cy.get('li')
.filter(':not([data-price])')
.should('read', ['Potatoes'])
The cy.filter query command has the built-in existence assertion. If there are no elements after the cy.filter
step, the test retries.
// will retry and fail, since none of the elements
// has this high of a price
cy.get('li').filter('[data-price=99]')
We can confirm there are no filtered elements by adding the "should not exist" assertion.
cy.get('li').filter('[data-price=99]').should('not.exist')
filter elements with specific elements inside
📺 This example is explained in the video Use cy.filter Command To Filter Elements By Child Element Presence.
Imagine if some elements have "New" labels inside. Can we find all LI
elements that have the .new
children element present?
<ul>
<li>Apples <span class="new">New</span></li>
<li>Grapes</li>
<li>Pears</li>
<li>Kiwi <span class="new">New</span></li>
</ul>
.new {
background-color: blue;
border-radius: 5px;
padding: 5px;
color: white;
font-weight: bold;
font-size: small;
}
Let's confirm that there are 2 new items on sale.
cy.get('li').filter(':has(.new)').should('have.length', 2)
How about confirming the names of the items that are not new? We can combine the :not
and :has
pseudo-selectors. We can also extract the element's own text value (without the children text) to compare.
cy.get('li')
.filter(':not(:has(.new))')
// from each element get the element's own text node
.map('childNodes.0.nodeValue')
// remove leading and trailing spaces
.mapInvoke('trim')
.should('deep.equal', ['Grapes', 'Pears'])