Who doesn't love React Testing Library? If you write tests for React, you probably use it a lot. People even like to call it the successor of Enzyme, but React Testing Library and Enzyme are nothing alike. While React Testing Library already gives you superpowers — understanding its principles will help you write much better tests for your React UIs. I promise you will gain something out of this short read.
The idea & the principles
The user lives in the heart of the principles of React Testing Library. Everything that the library does, revolves around the user.
Good UI tests give you confidence that your components work for your users. They verify that your components look right and behave the right way. How you implement it behind the scenes is not important for the user. This is why good UI tests should never rely on the implementation details of a UI component.
If your tests rely on how a given component is implemented, those test cases will break when you re-factor your codebase. This makes your tests extremely hard to maintain and will slow you down. You don't want that.
Remember — you want your UI tests to verify the end result, not the internal implementation. This is the pivotal idea behind React Testing Library.
The more your tests resemble the way your software is used, the more confidence they can give you.
— testing-library.com
Enzyme gives you access to the component's state, props, children, etc. React Testing Library doesn't do that. It gives you the DOM instead because that's what your users will have. If your tests are good enough, you will never have to explicitly access the component's state or props to make any assertions. Just use the DOM.
Passing a backgroundColor
prop to a <Button />
? Render the button to the DOM and verify that the rendered button's background color. Don't access the props of the component and make an assertion. Make a visual assertion.
it('should apply the background color properly', async () => {
const bgColor = '#ccc222';
const text= 'hi';
const { getByText} = render(<Button backgroundColor={bgColor} text={text} />);
const button = getByText(text);
expect(button.style.backgroundColor).toEqual(bgColor);
})
Want to test the loading state of a component? Make an assertion on the way the component looks when it is loading. Don't verify whether the loading
state of the component is true
.
it('should render correctly while loading', async () => {
const src= '#';
const altText = 'hi';
const { getByAltText } = render(<Image src={src} alt={altText} />);
const image = getByAltText(altText);
expect(image.src).toEqual(loadingSrc);
// Note: you need to write fireEvent.load(image) in order to complete loading the image.
// Since we have not done that, the image is still 'loading'.
})
The benefits
React Testing Library is inspired by its love for great user experience. If you are writing good tests using React Testing Library, you can be assured that the experience you ship to your users will be what you wanted. It gives you that much-needed confidence when pushing to production and let me tell you, it feels good. Anything that relieves you of some stress is a blessing and React Testing Library is definitely one.
What about the developer experience? Well, React Testing Library excels at that, too. The syntax is extremely intuitive. You don't have to know any intricacies in order to get up and running. The querying methods like getByText
, getByAltText
, etc allow developers to query the DOM just like a real end-user. This is so important.
Another massive benefit this library offers to developers is that as long as you only re-factor your component's implementation (not functionality), your tests will not break. I might be repeating myself here, but this will save you a lot of time & headaches. And you will absolutely love it when you refactor the code and nothing breaks. Trust me.
Oh, and the documentation is everything a developer would want from a library. It's perfect.
Conclusion
All in all, React Testing Library helps you ship UIs which are optimized for your end-users. This is something no developer/team would say no to.
I listed a lot of pros of using the library here but if you think there are any cons, comment down below. Let's discuss!
If you gained anything from this article, please follow me here on DEV & on Twitter. I try to balance my Twitter content between knowledge & shitposts. I can promise you will not be disappointed!
Top comments (8)
Hi, I can understand the point you are trying to make with snapshots. But am I checking the internal state of the component in the post? I don't think I am. I don't think you can, actually. I am getting the component from the actual DOM and making some assertions (all about its HTML attributes, no internal state). Isn't that the same as comparing the rendered component to a pre-defined expected HTML? Would love to hear your thoughts. Thanks
Thanks for the reply!
I think we are on different pages here. I don't have any
loading
state in my component like you mentioned. By default, Testing Library doesn't actually load your image. It doesn't fire the 'onLoad' event. (That's what we are doing with fireEvent.load(), not updating any internal state.) Which is why you can test if the image is correctly displaying a loader using the code I mentioned.And all of these events are native, none are custom. 😁
Why should I use this library instead of Jest and Enzyme?
I don't need to check button's color because the snapshots will check that automatically.
I'm not hating on the testing library, I'm trying to understand why should I use it.
This library does not replace Jest. It's not a test runner.
And like I mentioned in the article, React Testing Library forces you to test your components from your user's perspective. I know you can do that with Snapshots, but the examples I put in my article are very very basic. The library allows you to do much more than these things.
With Enzyme, it’s common to find elements in the page by their class, which is not meaningful because users do not see those in the UI. With react-testing-library, you search directly by the actual text that the user sees without the overhead work of finding the element that contains that text.
In the first sniplet you have small typos. There isn't altText variable nor getByAltText function, so the test will fail
Corrected it. Thanks for pointing it out!
@lukeshiru
Hi,
Is there any you-tuber where I can learn react unit testing in depth from scratch?