Search code examples
cypressvirtualscroll

How to test an infinite scroll component in Cypress


I have an dynamically loaded table based on an infinite-scroll component. I can test the loaded items as follows, but only 20 items are loaded at a time.

How can I repeat until the 500th item comes into view without repeating the code 100 times?

cy.get('div.infinite-scroll-component')
  .children()
  .should('have.length', 20)
  .last()
  .scrollIntoView()

cy.contains('Loading')
  .should('be.visible')
<div class="infinite-scroll-component" style="height: auto; overflow: auto;">List:
  <div style="height: 30px; border: 1px solid green; margin: 6px; padding: 8px;">Item #0</div>
  <div style="height: 30px; border: 1px solid green; margin: 6px; padding: 8px;">Item #1</div>
  <div style="height: 30px; border: 1px solid green; margin: 6px; padding: 8px;">Item #2</div>
  <div style="height: 30px; border: 1px solid green; margin: 6px; padding: 8px;">Item #3</div>
  ...

Solution

  • To repeat an action until a certain element appears on the page, use a recursive function.

    You must be careful to only take the next step after the action is complete.

    In your case the "Loading" indicator has appeared, and then wait for the load to complete (timing may need adjusting).

    const findItem = (item, attempt = 1) => {
      if (attempt === 100) throw 'Not found'
      return cy.get('div.infinite-scroll-component')
        .children()
        .then($els => {
          const found = [...$els].some(el => el.innerText === item)
          if (!found) {
            // trigger load with scroll
            cy.get('div.infinite-scroll-component')   
              .children()
              .last()
              .scrollIntoView()
            cy.contains('Loading')
              .should('be.visible')
              .then(() => {
                cy.wait(100)                       // wait for loading
    
                // OR check the list length 
                const expectedListLength = (attempt +1) * 20
                cy.get('div.infinite-scroll-component').children()
                  .should('have.length', expectedListLength)     
    
                return findItem(item, ++attempt)   // next step
              })
          }
          return cy.get('div.infinite-scroll-component')
            .children(`:contains(${item})`)
        })
    }
    
    findItem('div - #100').should('have.length', 1)  // just one item
      .and('contain.text', 'div - #100')             // verify it's text