Conditional Tests in Cypress using data-cy attributes as selectors

633 Views Asked by At

I see some posts about this exact topic, but none of them using data classes like I am as selectors, so it makes this conditional test a bit harder to write.

The idea is that I have a table with pagination on it. My idea is to check if the [data-cy-pagination-next] has or doesn't have the disabled attribute on it, which would mean there's more than one page and therefore the test can continue.

Most posts I see use a syntax like this:

cy.get('my-button')
  .then($button => {
    if ($button.is(':enabled')) {
      cy.wrap($button).click()
    }
  })

But I don't have the $button like they described. What I would be clicking on is a button, but does that really matter? It doesn't seem like I can write

cy.get('[data-cy=pagination-next]')
  .then('[data-cy=pagination-next]' => {
    if ('[data-cy=pagination-next]'.is(':enabled')) {
      cy.wrap('[data-cy=pagination-next]').click()
    }
  })

How can I get this conditional to work? If there is more than one page, this test works great, but in the cases that there is no second page, I just want the test to end there. Any tips would be greatly appreciated!

Cheers!

Here is the test currently

 it('Data Source has Pagination and test functionality', () => {
    cy.get('[data-cy=pagination]').should('exist')
    // assert that we are at the first page and the start and back button is disabled
    cy.get('[data-cy=pagination-page-list]').contains('Page 1 of')
    // If there are multiple pages then do the following tests
  
    // click next button and assert that the current page is page 2
    cy.get('[data-cy=pagination-next]').click()
    cy.get('[data-cy=pagination-page-list]').contains('Page 2 of')
    // click end button and assert that the end and next buttons are disabled
    cy.get('[data-cy=pagination-end]').click()
    cy.get('[data-cy=pagination-next]').should('be.disabled')
    cy.get('[data-cy=pagination-end]').should('be.disabled')
    // click start button button and assert that the current page is page 1 and next and start buttons are disabled
    cy.get('[data-cy=pagination-start]').click()
    cy.get('[data-cy=pagination-page-list]').contains('Page 1 of')
    cy.get('[data-cy=pagination-start]').should('be.disabled')
    cy.get('[data-cy=pagination-back]').should('be.disabled')
  })

enter image description here

3

There are 3 best solutions below

2
On BEST ANSWER

I think you're misunderstanding how yielding and callbacks work. The reason there is $button in the .then() is because it is yielded by cy.get(). It could be named anything, so long as it is a valid name (note: a string literal, like you are trying to do, is not valid).

So, $button is just the yielded element from your cy.get('my-button'). Which is why we can then use JQuery functions and Chai assertions on it.

cy.get('[data-cy=pagination-next]')
  .then($el => { // naming the yielded object from `cy.get()` to $el
    if ($el.is(':enabled')) { // using JQuery function `.is` to check if the element is enabled
      cy.wrap($el).click() // Cypress requires the JQuery element to be wrapped before it can click it.
    }
  })
2
On

You can use the page indicator to split the test logic

it('Data Source has Pagination and test functionality', () => {
    cy.get('[data-cy=pagination]').should('exist')

    cy.get('[data-cy=pagination-page-list]')
    .then($pageList => {

      if ($pageList.text() === 'Page 1 of 1')  

        // single page assertions

        cy.get('[data-cy=pagination-next]').should('be.disabled')
        cy.get('[data-cy=pagination-end]').should('be.disabled')
        cy.get('[data-cy=pagination-start]').should('be.disabled')
        cy.get('[data-cy=pagination-back]').should('be.disabled')

      } else {

        // multi page assertions
  
        cy.get('[data-cy=pagination-next]').click()
        cy.get('[data-cy=pagination-page-list]')
          .should('contain', 'Page 2 of')            // assert on second page

        cy.get('[data-cy=pagination-end]').click()
        cy.get('[data-cy=pagination-next]').should('be.disabled')

        cy.get('[data-cy=pagination-start]').click()
        cy.get('[data-cy=pagination-page-list]').contains('Page 1 of')
        cy.get('[data-cy=pagination-start]').should('be.disabled')
        cy.get('[data-cy=pagination-back]').should('be.disabled')
     }
  })

Better still, control the test data so that only a single page exists, then run two tests under known conditions and eliminate flaky conditional testing.

1
On

You can do something like this. You can use an each to loop over all the pagination elements. So in case, you don't have only 2 buttons the loop will check for only 2 buttons and then terminate.

cy.get('[data-cy=pagination-page-list]').should('contain.text', 'Page 1 of')
cy.get('[data-cy=pagination-next]').each(($ele, index) => {
  if ($ele.is(':enabled')) {
    cy.wrap($ele).click()
    cy.wrap($ele).should('contain.text', `Page ${index + 2} of`) //index starts from 0
  }
})