Selector changes by an index in Mobile vs Desktop. How to handle assertion in Cypress

Viewed 78

I have a selector that changes when running in mobile. For example:

Desktop: div[data-test-id="popup"] div:nth-child(2) Mobile: div[data-test-id="popup"] div:nth-child(3)

My idea is to check the size of the window and if it's below 375 use the Mobile selector else Desktop.

I have the following working solution but I dont want to have repeated code and rather would like to pass 2 or 3 as a parameter:

cy.get('body').then( (body) => {
       if ( body.width() <= 375 ) {
           cy.get('div[data-test-id="popup"] div:nth-child(3)')
               .children().eq(0)
               .should('exist')
               .should('have.text', time);
       }
       else {
           cy.get('div[data-test-id="popup"] div:nth-child(2)')
               .children().eq(0)
               .should('exist')
               .should('have.text', time);
       }
    });

Is there a better way to rewrite it?

Also, the above code, even though it runs and the tests pass, the build fails with a Typescript error due to body.width() --> TS2532: Object is possibly 'undefined'.

2 Answers

I would be testing both desktop and mobile using viewport to explicitly set the width

const widths = [500, 350]
widths.forEach(width => {

  // You are looking for a way to parameterize the selector,
  // do it using a template literal
  const param = width === 350 ? 3 : 2
  const selector = `div[data-test-id="popup"] div:nth-child(${param})`

  beforeEach(() => {
    cy.viewport(width, 800)
  })

  it(`tests the width of ${width}px`, () => {
    cy.get(selector)
      .children().eq(0)
      .should('exist')
      .should('have.text', time)
  })
})

It looks like you need to use viewport in a somewhat restricted way, either

  • in beforeEach() hook
  • before a page cy.visit()
  • before a page cy.reload()

The typescript error

body.width() --> TS2532: Object is possibly 'undefined'

can be fixed by using the non-null assertion operator

body!.width()   // telling typescript that we know body exists

You can simplify your code by using the .contains() command instead of the all the .get()s.

Assuming you don't have any other elements with data-test-id="popup" with the time text or any nested data-testid="popup" within the div[data-test-id="popup" one, then this will work for both desktop and mobile and here is what it will look like.

cy.contains('[data-test-id=popup]', time) 
  .should('exist')
  .should('have.text', time);
Related