Search code examples
clickcypresspaginator

Cypress - Click on an element only if it is clickable


Is there a method in Cypress to simulate the paginator functionality of a webpage?

An example scenario for this would be the paginator functionality of a webpage. So this function or method would enable me to click on the 'next page' or 'previous page' icons until I can go no further.

An example of what code I am requesting information on would be:

while (cy.get(<locator string>).isClickable()) {
     cy.get(<locator string>).click();
     //and some other instructions to follow;
}

Hope I was able to portray it correctly! ;)


Solution

  • The while loop part can be handled with a recursive function,

    function clickUntilDisabled(selector, callback, pageNo = 0) {
    
      if (pageNo === 100) {
        throw 'Too many clicks'                          // avoid runaway recursive calls
      }
    
      cy.get(selector).then($clickable => {
        if ($clickable.prop('disabled')) return;         // exit
    
        $clickable.click()
        callback(pageNo)                                 // other stuff to do
        clickUntilDisabled(selector, callback, ++pageNo) // repeat
      })
    }
    
    clickUntilDisabled('my-button', (pageNo) => {
      cy.get('row').should(...);                         // testing page here
    })
    

    Proof of concept

    Example app

    <div>
      <button onclick="nextpage()">Next Page</button>
      <p>Page no: _</p>
    
      <script>
        let count = -1
        function nextpage() {
    
          count++
          console.log('Click handler nextpage', count)
    
          setTimeout(() => {                           // some async change
            const p = document.querySelector('p')      // to make sure the loop 
            p.innerText = `Page no: ${count}`          // waits for fetch
          }, 2000)
    
          if (count < 3) return  
    
          // disable after 3rd click
          const button = document.querySelector('button')
          button.disabled = true
        }
      </script>
    </div>
    

    Test

    function clickUntilDisabled(selector, callback, pageNo = 0) {
      if (pageNo === 100) {
        throw 'Too many clicks'                      
      }
      cy.get(selector).then($clickable => {
        if ($clickable.prop('disabled')) return;       
        $clickable.click()
        callback(pageNo)                                
        clickUntilDisabled(selector, callback, ++pageNo) 
      })
    }
    
    clickUntilDisabled('button', (pageNo) => {
      console.log('Callback pageNo', pageNo)
      cy.get('button')
        .then($button => {
          const assertion = pageNo < 3 ? 'not.be.disabled' : 'be.disabled';
          cy.wrap($button).should(assertion)                                  // passes
        })
      cy.contains('p', `Page no: ${pageNo}`)                                  // passes
    })
    

    Log

    Click handler nextpage 0
    Callback pageNo 0
    Click handler nextpage 1
    Callback pageNo 1
    Click handler nextpage 2
    Callback pageNo 2
    Click handler nextpage 3
    Callback pageNo 3