How to override 'data-testid' in the 'findByTestId function from Cypress Testing Library

5.1k views Asked by At

Most of my existing codebase uses a 'id' only in few places 'data-testId' attribute present. tried this code

import { configure } from '@testing-library/cypress';

configure({ testIdAttribute: ['data-testId','id'] });

But, still its not working.

Is there any way to use 'id' value in any of the testing-library functions.

My HTML code is something like:

<div class="some random class name" id="userprofile-open" role="button">SB</div>

I want click that element with this code:

cy.findByTestId("userprofile-open", { timeout: 120000 }).click();
2

There are 2 answers

2
Rosen Mihaylov On

The usual cypress way - which has an inherent check on the element visibility and existence as well as included retries for a period of time is using cy.get()

If you want to select element using property like data-id you need this sintax: cy.get('[propertyName="propertyValue"]')

If you want select an element by CSS selector you just pass CSS selector like this: cy.get('#id')

0
AudioBubble On

I don't think you can configure testing-library with an array of ids, ref API configuration,

import { configure } from '@testing-library/cypress'
configure({ testIdAttribute: 'id' })

But even this fails. Instead you have to use the Cypress command to change the attribute name (only one name is allowed).

cy.configureCypressTestingLibrary({ testIdAttribute: 'id' })

To use either/or attribute name you can change the attribute name on the fly, wrapping it in a custom command (based on Custom Queries)

Cypress.Commands.add('findByTestIdOrId', (idToFind) => {
  
  let result;

  const { queryHelpers } = require('@testing-library/dom');
  let queryAllByTestId = queryHelpers.queryAllByAttribute.bind(null, 'data-testId');

  result = queryAllByTestId(Cypress.$('body')[0], idToFind)
  if (result.length) return result;

  queryAllByTestId = queryHelpers.queryAllByAttribute.bind(null, 'id');
  result = queryAllByTestId(Cypress.$('body')[0], idToFind);
  if (result.length) return result;

  throw `Unable to find an element by: [data-test-id="${idToFind}"] or [id="${idToFind}"]`

})

cy.findByTestIdOrId('my-id')
  .should('have.attr', 'id', 'my-id')  
// passes and logs "expected <div#my-id> to have attribute id with the value my-id"

Note this custom command works only for synchronous DOM.


If you need to have Cypress retry and search for either/or attribute, don't use testing-library in the custom command.

Instead use Cypress .should() to enable retry

Cypress.Commands.add('findByTestIdOrId', (selector, idToFind) => {
  cy.get(selector)
    .should('satisfy', $els => {
      const attrs = [...$els].reduce((acc, el) => {
        const id = el.id || el.getAttribute('data-test-id')  // either/or attribute
        if (id) {
          acc.push(id)
        }
        return acc
      }, [])
      return attrs.some(attr => attr === idToFind); // retries when false
    })
    .first();                                       // may be more than one
})

cy.findByTestIdOrId('div', 'my-id')
  .should('have.attr', 'id', 'my-id')  
// passes and logs "expected <div#my-id> to have attribute id with the value my-id"