simjohan
simjohan

Reputation: 73

React testing library vs cypress query philosophies

I'm currently in the process of setting up Cypress for my project. Currently we're only using testing library for frontend tests. And reading the Cypress documentation has gotten me a bit confused as the two libraries seem to have opposite philosophies in regards to how you're supposed to query for elements.

Testing library basically says test what the user can see/touch and only use data-testid if all else fails. Cypress on the other hand states that best practice is that you should query elements by data-testid / data-cy attributes.

I feel conflicted between the two approaches. I get the point about we should test what the user actually sees (testing library). But I do also get that those things often change (cypress) and we need to spend time updating tests whenever we make small changes (i.e "Ok" -> "Done"). And when testing with data-cy attributes, are we not also ignoring accessibility / screen readers?

What are your thoughts on this?

Upvotes: 4

Views: 1114

Answers (2)

Advena
Advena

Reputation: 2233

React Testing library(RTL) is specifically made to write tests from a user perspective. From their Guiding Principles:

The more your tests resemble the way your software is used, the more confidence they can give you.

Meaning, RTL wants you to use accessibility queries like getByRole and only fallback to getByTestId for cases where you can't match by role or text, or it doesn't make sense (e.g. the text is dynamic).

However, thanks to the render method allowing us to specify props (compared to Cypress), we have much more flexibility and may entirely omit dynamic text.


Cypress, on the other hand, runs with all dependencies. In case of dynamic content from a C.M.S or multi-language application, things are not that easy using getByRole("heading", {name: /welcome/i }). In this case, the recommendation of testId's make sense.


My personal recommendation is to use accessibility query selectors in both Cypress and RTL, unless the text is dynamic. Then testId's in Cypress and a combination of testId's & accessibility query selectors provide the best solution.


It should also be noted that Playwright and Cypress test-generator tools select by accessibility query selectors.

Upvotes: 4

Caíque Coelho
Caíque Coelho

Reputation: 459

I thought a lot for a few days before answering this question and I even got to do some tests, and after that time I came to the conclusion that the Cypress approach is the best.

The main reason that led me to this answer was that when the testing library says that we should test what the user actually sees, it is already applicable in Cypress even when we use a data-testid, because let's suppose you have a button that exists in the DOM, but it is not visible when you select this button, with the data-testid when you try to click in this button Cypress will return an error saying that the button is not visible and if you really want to do this action you must apply force:true. The same happens if the button is not clickable or if there is another element in front of the button.

Cypress already checks by default in click and type actions if the element:

  • element is into view
  • it is visible
  • it is not disabled
  • it is not detached
  • it is not readonly
  • it is not animating
  • it is not covered
  • fire the event at a descendent

Also if you fetch the element by text, placeholder, or class, this does not guarantee that the element is actually visible to the user, as the element can be in the DOM and not be visible to the user for various reasons.

So the best way to make tests easier to maintain, easier to read, and avoid flaky tests is to use the data-testid and whenever possible or necessary combine the location of the element with an assertion to ensure that the element is visible. Example: cy.get('[data-testid="button"]').should('be.visible')

I hope I had contributed to the discussion and would love to hear other people's points of view.

Upvotes: 0

Related Questions