When you are writing a test using React Native Testing Library, you can easily get confused on what function you can use. getBy
, findBy
, and queryBy
are all used to get a specific element on the screen you’re testing. They may be similar, but their purpose and the way they can be used are actually pretty different.
getBy
returns the first matching node for a query, and throws an error if there’s zero or multiple element matches.
If you want to make sure there is a specific element on the screen you’re testing, you can use getBy
to get an element and use expect(...).toBeTruthy()
to make sure there’s a match for it.
There is also a matcher called toBeOnTheScreen()
in the @testing-library/jest-native
library that can replace toBeTruthy()
. It is more explicit than toBeTruthy()
and make the tests more readable. You can follow this documentation to use additional matchers.
The return type for getBy
functions is the generic type T
, so you can also use the element you’re getting as a return value from the function to fire actions on it.
queryBy
is actually similar to getBy
because it also returns the matching node for a query. However, it returns null
if there’s no element match, and throws an error if there are multiple matches.
With that difference, queryBy
can be used to make sure a specific element is not on the screen you’re testing.
Although you can achieve an equivalent result with getBy
by using expect(...).toThrow()
, using expect(...).toBeFalsy()
with queryBy
makes the code more explicit, easier to read and provides better error messages. But, similarly to what was explained for getBy
, you can use the toBeOnTheScreen()
matcher from @testing-library/jest-native
to get an even more explicit code. You just have to use not
in combination with toBeOnTheScreen()
.
Unlike getBy
and queryBy
, findBy
returns a promise, which resolves to a matching node when the element is found. The promise is rejected if no element is found after a 1000ms timeout, which can be overwritten in the third parameter of the method. It will also be rejected if there are multiple element matches.
It can be useful if you’re making API calls in your app and have to wait for the call to be over to make sure you have a specific element.
All of these functions throw an error if more than one match is found… Unless you use the key word All
in them. That means you can use getAllBy
, queryAllBy
and findAllBy
.
By doing so, instead of getting one matching node, you get an array of them. You can use that array to check if you have the expected amount of a specific element and/or fire actions on some of them.
There is a lot a information in this article and it can get confusing. So, here is a table that sums up how and when to use each of these functions:
For the reasons stated before, using queryBy
to make sure an element is not present is actually part of good practices when it comes to writing tests. ESLint rules are available to enforce these good practices. Here is an an example of a ESLint rule you can use:
This rule will ensure the linter throws an ESLint error each time a getBy
is used for a null element, as explained in the documentation here. Check out more available rules and how to install them on this GitHub repository.
To learn more good practices when it comes to writing tests, check out our article on Refactoring Tests.
React Native Testing Library has many more queries and features. You can visit the official website of their documentation here.