203

I'm starting to learn Cypress. I have a 4 row table (with a class of datatable). I can verify the number of rows this way:

cy.get('.datatable').find('tr').each(function(row, i){
        expect(i).to.be.lessThan(4)
})

This is fine, but it seems awkward, since I just want to count the length and don't really need to access the stuff in the rows, and I assume it's faster to do one thing than do 4 things.

If I log the selection (not sure what else to call it):

cy.log(cy.get('.datatable').find('tr'))

it comes out as [object Object] and I'm not quite sure how to deconstruct that, which suggests to me that I'm thinking about this all wrong.

If I try:

expect(cy.get('.datatable').find('tr')).to.have.lengthOf(4)

I get AssertionError: expected { Object (chainerId, firstCall) } to have a property 'length'

If I try:

expect(Cypress.$('.datatable > tr')).to.have.lengthOf(4)

I get AssertionError: expected { Object (length, prevObject, ...) } to have a length of 4 but got 0 so at least it has a length here?

If I log that method of selection I get Object{4}. I'm not sure where to go from here. It seems like this would be a very common thing to deal with.

AdrienW
  • 3,092
  • 6
  • 29
  • 59
Katharine Osborne
  • 6,571
  • 6
  • 32
  • 61
  • My client uses only Chrome (it's not a public facing app). We have moved away from Cypress as we are converting the app to Angular and are now using Karma and Jasmine (which are inbuilt with the framework). I found Cypress quite easy to work with but I didn't choose it (nor did I choose Angular); however I would have to say that the extensive documentation for Cypress is probably very attractive. When testing is not your ken and more of a chore, having extensive docs with good examples helps you get up and running quicker. – Katharine Osborne Nov 15 '18 at 12:59
  • Thanks, so much for your feedback Katharine – alexrogers Nov 15 '18 at 13:57

11 Answers11

272

Found a solution, This works to check a count of items:

cy.get('.datatable').find('tr').should('have.length', 4)

This does not work with the Cypress.$() method of notation.

Reference: https://docs.cypress.io/guides/references/assertions.html#Length

Katharine Osborne
  • 6,571
  • 6
  • 32
  • 61
  • 7
    This is a good way to test length, but you can't return the length this way. To return you need to use the Promise chain `.then(elm => elm.length)` – png Jul 03 '19 at 20:40
  • Looks like .should('have.length', 4) checks for “at least 4”. The other solution, using .its('length').should('eq', 4), checks for exact equality. – NPC Feb 07 '20 at 17:40
  • 5
    the question was "how to count a selection of items and get the length?" and NOT "how to check" - the goal is to return count outside of the chaining.... – Sasha Bond Sep 11 '20 at 16:22
  • For `Cypress.$` approach, you could try `expect(Cypress.$(".datatable").find('tr').length === 4)` Though Katarine's suggestion would be better choice. Using `Cypress.$` would be best used more in a combination with other checks in Cypress. – InvisibleExo Oct 29 '22 at 19:47
  • @png Do you mean we can get length like this? `eleLength = cy.get(selector).should('have.length.greaterThan', 0).then(elm => elm.length);` – paul Mar 31 '23 at 08:23
124

You can also get the length of a selection of items through its property, for example:

cy.get('.datatable').find('tr').its('length').should('eq', 4)
cy.get('.datatable').find('tr').its('length').should('be.gte', 4)

In addition to should('have.length', 4)

enter image description here I tested with Cypress version 3.1.0 and 3.2.0.

Yuci
  • 27,235
  • 10
  • 114
  • 113
  • tried these & get an error: TypeError: $table.find(...).its is not a function – Steve Staple Mar 21 '19 at 15:25
  • @SteveStaple I tried again with the current latest version of Cypress, v3.2.0, it still works. See my updated answer with a screenshot. – Yuci Mar 22 '19 at 10:24
  • 6
    For flexibility reasons I prefer this solution over the `.should('have.length', length)` expectation, because `.its('length')` provides **greater flexibility on your assertions**, e.g. greater than or less than. – Mobiletainment Apr 08 '19 at 21:14
  • 6
    Just an FYI, you can also use greater than or less than with `should` like this: `should('have.length.gte', length)` – Matan Bobi Aug 10 '20 at 09:00
43

if you want more flexible and have a dynamic result use this.

cy.get('.listings-grid')
  .find('.listing')
  .then(listing => {
    const listingCount = Cypress.$(listing).length;
    expect(listing).to.have.length(listingCount);
  });
  • 3
    this gets filled listingCount internally only, cannot return it outside of .then()... .its('length') also returns chaining object, not an integer – Sasha Bond Sep 11 '20 at 16:08
  • 1
    This test is going to be flaky because only the last then will be retried throughout the timeout. – Muhammad bin Yusrat Feb 24 '21 at 01:54
  • @SashaBond why not make a variable higher in scope, then modify it in your .then(). that should fix the scope issue. – sao Oct 29 '21 at 15:10
20

One option is to use "have.length" ...

cy.get('.datatable tr').should('have.length', 4)

...another option is to use should

cy.get('.datatable tr').should(($tr) => {
    expect($tr).to.have.length(4)
})

...or then (synchronous queries)

cy.get('.datatable').then(($table) => {
  // synchronously query to find length of elements
  expect($table.find('td').length).to.equal(4)
})
0x4a6f4672
  • 27,297
  • 17
  • 103
  • 140
  • Thie first one is the best solution if you have dynamic content - otherwise .get will work immediately and return the wrong amount of find, which is waited on even though the real number changed. This solution will wait on the correct number. – James Cameron Apr 16 '20 at 12:07
5

From the cypress API docs .should() section, using an arrow function:

cy.get('.datatable').find('tr').should(($listOfElements) => {
   expect($listOfElements).to.have.length(4)
   // any other assertions, for example the below one
   // expect($listOfElements).to.have.any.keys('key1', 'key2')
})

This approach will allow you to use Chai BDD notation and assert more than one thing on your list of elements.

lauri108
  • 1,381
  • 1
  • 13
  • 22
  • Other assertions can be chained with `.and()` see [should.html#Multiple-Assertions](https://docs.cypress.io/api/commands/should.html#Multiple-Assertions). Less noise IMO. –  Aug 29 '18 at 10:40
3
cy
  .get('ul[data-qa="qa-navbar"] li')      // selector 
  .should('have.length', 5)               //  Assertion
Dharman
  • 30,962
  • 25
  • 85
  • 135
Sajid Ali
  • 31
  • 1
  • 6
    Generally, answers are much more helpful if they include an explanation of what the code is intended to do, and why that solves the problem without introducing others. – DCCoder May 20 '21 at 17:06
1

My use case was to compare that, say no. of "i" icons on the page should match the no. of table rows. So, this solution worked for it i.e. when I wanted to compare the no. of elements of one selector vs the other

cy.get('first element').its('length').then((val)=>{
     cy.get('second element).its('length').should('eq',val)
})

Writing then after its captures the requested property (in this case, length) and within the first then block, we do a compare by getting the length of the second element

Rahul Singh
  • 374
  • 4
  • 13
0
  • .children (selector(byId, class, custom attribute) yields DOM elements and retry untill defaultCommandTimeout exceeds.

    cypress config defaultCommandTimeout

  • once DOM elements exists and yielded added length assertion.

<ul data-qa="qa-navbar">
  <li>Home</li>
  <li>About</li>
  <li>Services</li>
  <li>Our Team</li>
  <li>Contact Us</li>
</ul>

    cy
      .get('[data-qa="qa-navbar"]') // selector
      .children() // get direct decendents 
      .should('have.length', 5); // add assertion to have lenght of 5

khizer
  • 1,242
  • 15
  • 13
0

to get the length you need to use cypress commands:

    cy.get('[ng-repeat="item in catalog"]').then(($el) => { 
        const itemCount = Cypress.$($el).length;
        cy.log(itemCount)
    })
Wari
  • 1
0
 - In the element locator "aria-setsize" property to find the "number of items in the current set of listitems or treeitems" can be used.
 - Within ".then" function, for the previously yielded element. Use ".length" jquery as below.
 - To find the list of: Best Sellers in Computers & Accessories, in "Amazon.in" home screen.

it('test', () => {
        cy.visit('https://www.amazon.in/ref=nav_logo')
        cy.wait(3000)
        cy.get('#desktop-5 li[aria-setsize]')
        .then(($el) => {
         const count= $el.length
         cy.log(count)
        })

    })
BalajiK
  • 1
  • 2
-3

Body variable is already resolved as you're in .then() part of the promise:

cy.get("body").then($body => {
    cy.log($body.find(".datatable tr").length);
});`
Ivan Valadares
  • 869
  • 1
  • 8
  • 18