There are a few mistakes that are incredibly easy to make in React Testing Library and I wish I'd watched out for these earlier. Recently I've fixed hundreds of these in a more extensive code base, so just making a remark here. Watch out for these!
1 - Await on synchronous queries
// β Incorrect code β
await screen.getByTestId('menu') // check for existence
// β Incorrect code β
const banner = await screen.queryByTestId('banner')
expect(banner).not.toBeInDocument() // check for non-existence
Here the problem is that we're awaiting on methods that are synchronous by default.
// β
Correct code
screen.getByTestId('menu') // check for existence
// β
Correct code
const banner = screen.queryByTestId('banner')
expect(banner).not.toBeInDocument() // check for non-existence
π‘ Remember, getBy..., queryBy..., getAllBy..., queryAllBy... methods are synchronous. Meaning they're only useful, if your component already rendered elements you want to find. (Probably not a good idea to use these, if your component is making a network request to get the data and just renders after.)
π‘ Check out this related eslint-plugin rule
2 - Not awaiting on asynchronous queries π
This problem is the inverse of the previous one. π
So let's say your component is only rendered after fetching some network data. In this case, synchronous methods are not helping, because they won't wait for the data to be rendered. In these cases you'll need to use findBy.../findAllBy...
However there is a problem with the code below β¬οΈ
// β Incorrect code β
screen.findByTestId('menu') // check for existence
Yep, there is no await
used here. This findBy... call gives us back a promise, because it's always async.
// β
Correct code
await screen.findByTestId('menu') // check for existence
π‘ Please always await
findBy..., findAllBy... queries.
π‘ Check out this related eslint-plugin rule
As an extra takeaway task, I leave this here for you to find out why this one will always get us fake results. π
// β Incorrect code β
expect(screen.findByTestId('menu')) // -> psst.. this will always pass
3 - Using queryBy.. to check existence
Okay, so we can easily decide when to use sync or async methods, but how about this one?
// β Incorrect code β
expect(screen.queryByText('A title')).toBeInTheDocument();
As per documentation, queryBy..
returns the matching node for a query, and return null if no elements match. This is useful for asserting an element that is not present.
π‘ Please only use queryBy..., queryAllBy... queries when you want to check that an element is NOT present.
π‘ Check out this related eslint-plugin rule
// β
Correct code
expect(screen.queryByText('A title')).not.toBeInTheDocument()
+1 - Use React Testing Library eslint plugins
You might have noticed already that I've included the related eslint-plugin rules for all the mentioned problems. I love automating rules because they're ensuring good code quality and consistency within the team.
π¨π¨ You must install eslint-plugin-testing-library and eslint-plugin-jest-dom if you're working heavily with RTL in your project.
If you have already a lot of tests (which you should π) eslint won't go easy on you after installing these plugins. However it worth fixing every recommendation it has πͺ
Happy testing!
Reference: Common mistakes with React Testing Library
Top comments (0)