Conditionally assert element values in DOM depending on it's value in backend with Cypress?

116 Views Asked by At

Trying to do Cypress Testing with my React app.

I'm retrieving an object with an attribute expirationDate from the backend. It's an integer with format YYYYMMDD. In my corresponding frontend in the <input> component, it's rendered as an YYYY-MM-DD string.

However the object may optionally not have an expiration date at all, which is instead represented as the attribute being -1 or -2. This is presented as an empty string '' in the <input>.

I thus need to conditionally check the value. How do I go about doing this with Cypress?

Closest I have right now is

cy.get('#input-expiration-date').should('have.value', expirationDate || '')

But this is not really an accurate test of the above conditions.

5

There are 5 best solutions below

0
On

Or if you want to check and further do some actions based on the value, you can do something like this:

cy.get('#input-expiration-date')
  .invoke('val')
  .then((val) => {
    if (val == expirationDate) {
      //Do something
    } else if (val == '') {
      // Do something
    } else {
      //Do something
    }
  })
0
On

Conditional testing can be done as follows, but this is bad practice.

cy.get('#input-expiration-date')
  .invoke('val')
  .then(val => {
    
    if (val === expirationDate) {     // fails because page is still fetching
      ...
    }
  })

The test runs faster than the value can be fetched from the server.

You can avoid the issue by waiting for the object fetch with cy.intercept() and do the conditional check then.

let expirationDate = 'YYYYMMDD'

cy.intercept(url).as('object')

cy.visit(...)

cy.wait('@object').then(object => {

  if (object.expirationDate) {
    cy.get('#input-expiration-date')
      .should('have.value', expirationDate)
  }
})
0
On

you can do:

cy.get('#input-expiration-date').then(element => {
//and here you can have conditions and access the DOM element

})
0
On

There a Chai method oneOf() you can use.

Cypress uses Chai internally, so the expression works inside .should().

cy.get('#input-expiration-date')
  .invoke('val')
  .should('have.oneOf', [expirationDate, ''])

Using Chai directly

cy.get('#input-expiration-date').then($input => {
  expect($input.val()).to.have.oneOf([expirationDate, ''])
})
0
On

Use cy.intercept() to get the value coming from the back-end.

General approach (may vary depending on response pattern):

cy.intercept('some-api-request').as('api')

// trigger the backend request/response
cy.get('button').click()


cy.wait('api').then(interception => {

  const obj = interception.response.body;     // extract object
  const expirationDate  = obj.expirationDate  // and it's expirationDate 
  const hasNoExpiration = expirationDate === -1 && expirationDate === -2

  cont expectedValue = hasNoExpiration ? '' : 
    `${expirationDate.slice(0,4)}-${expirationDate.slice(4,2)}-${expirationDate.slice(6,2)}`

  cy.get('#input-expiration-date').should('have.value', expectedValue)

})

You can also go one step further and eliminate any backend variation by stubbing

cy.intercept('some-api-request', {body: { expirationDate: -1 }).as('api')

// trigger the backend request/response
cy.get('button').click()

cy.wait('api')
cy.get('#input-expiration-date').should('have.value', '')
cy.intercept('some-api-request', {body: { expirationDate: '20220319' }).as('api')

// trigger the backend request/response
cy.get('button').click()

cy.wait('api')
cy.get('#input-expiration-date').should('have.value', '2022-03-19')