TheTesting Library family of libraries is a very light-weight solution for testing without all the implementation details. The main utilities it provides involve querying for nodes similarly to how users would find them. In this way, testing-library helps ensure your tests give you confidence in your UI code.
You want to write maintainable tests for your React components. As a part ofthis goal, you want your tests to avoid including implementation details of yourcomponents and rather focus on making your tests give you the confidence forwhich they are intended. As part of this, you want your testbase to bemaintainable in the long run so refactors of your components (changes toimplementation but not functionality) don't break your tests and slow you andyour team down.
The React Testing Library is a very light-weight solution for testing Reactcomponents. It provides light utility functions on top of react-dom andreact-dom/test-utils, in a way that encourages better testing practices. Itsprimary guiding principle is:
So rather than dealing with instances of rendered React components, your testswill work with actual DOM nodes. The utilities this library provides facilitatequerying the DOM in the same way the user would. Finding form elements by theirlabel text (just like a user would), finding links and buttons from their text(like a user would). It also exposes a recommended way to find elements by adata-testid as an "escape hatch" for elements where the text content and labeldo not make sense or is not practical.
This library encourages your applications to be more accessible and allows youto get your tests closer to using your components the way a user will, whichallows your tests to give you more confidence that your application will workwhen a real user uses it.
This library is a replacement for Enzyme. While youcan follow these guidelines using Enzyme itself, enforcing this is harderbecause of all the extra utilities that Enzyme provides (utilities whichfacilitate testing implementation details). Read more about this inthe FAQ.
Hi there ? I created React Testing Library because I wasn't satisfied with thetesting landscape at the time. It expanded to DOM Testing Library and now wehave Testing Library implementations (wrappers) for every popular JavaScriptframework and testing tool that targets the DOM (and even some that don't).
As time has gone on, we've made some small changes to the API and we'vediscovered suboptimal patterns. Despite our efforts to document the "better way"to use the utilities we provide, I still see blog posts and tests writtenfollowing these suboptimal patterns and I'd like to go through some of these,explain why they're not great and how you can improve your tests to avoid thesepitfalls.
The name wrapper is old cruft from enzyme and we don't need that here. Thereturn value from render is not "wrapping" anything. It's simply a collectionof utilities that (thanks to the next thing) you should actually not often needanyway.
The benefit of using screen is you no longer need to keep the render calldestructure up-to-date as you add/remove the queries you need. You only need totype screen. and let your editor's magic autocomplete take care of the rest.
The only exception to this is if you're setting the container or baseElementwhich you probably should avoid doing (I honestly can't think of a legitimateuse case for those options anymore and they only exist for historical reasons atthis point).
I see people wrapping things in act like this because they see these "act"warnings all the time and are just desperately trying anything they can to getthem to go away, but what they don't know is that render and fireEvent arealready wrapped in act! So those are doing nothing useful.
Most of the time, if you're seeing an act warning, it's not just something tobe silenced, but it's actually telling you that something unexpected ishappening in your test. You can learn more about this from my blog post (andvideos):Fix the "not wrapped in act(...)" warning.
We maintain a page called"Which query should I use?"of the queries you should attempt to use in the order you should attempt to usethem. If your goal is aligned with ours of having tests that give you confidencethat your app will work when your users use them, then you'll want to query theDOM as closely to the way your end-users do so as possible. The queries weprovide will help you to do this, but not all queries are created equally.
We want to ensure that your users can interact with your UI and if you queryaround using querySelector we lose a lot of that confidence, the test isharder to read, and it will break more frequently. This goes hand-in-hand withthe next sub-section:
As a sub-section of "Using the wrong query", I want to talk about why Irecommend you query by the actual text (in the case of localization, Irecommend the default locale), rather than using test IDs or other mechanismseverywhere.
If you don't query by the actual text, then you have to do extra work to makesure that your translations are getting applied correctly. The biggest complaintI hear about this is that it leads to content writers breaking your tests. Myrebuttal to that is that first, if a content writer changes "Username" to"Email" that's a change I definitely want to know about (because I'll need tochange my implementation). Also, if there is a situation where they breaksomething, fixing that issue takes no time at all. It's easy to triage and easyto fix.
As a sub-section of "Using the wrong query" I want to talk about *ByRole. Inrecent versions, the *ByRole queries have been seriously improved (primarilythanks to great work bySebastian Silbermann) and are now thenumber one recommended approach to query your component's output. Here are someof my favorite features.
The name option allows you to query elements by their"Accessible Name" which is what screenreaders will read for the element and it works even if your element has itstext content split up by different elements. For example:
One reason people don't use *ByRole queries is because they're not familiarwith the implicit roles placed on elements.Here's a list of Roles on MDN.So another one of my favorite features of the *ByRole queries is that if we'reunable to find an element with the role you've specified, not only will we logthe entire DOM to you like we do with normal get* or find* variants, but wealso log all the available roles you can query by!
Slapping accessibility attributes willy nilly is not only unnecessary (as in thecase above), but it can also confuse screen readers and their users. Theaccessibility attributes should really only be used when semantic HTML doesn'tsatisfy your use case (like if you're building a non-native UI that you want tomake accessiblelike an autocomplete). If that'swhat you're building, be sure to use an existing library that does thisaccessibly or follow the WAI-ARIA practices. They often havegreat examples.
@testing-library/user-eventis a package that's built on top of fireEvent, but it provides several methodsthat resemble the user interactions more closely. In the example above,fireEvent.change will simply trigger a single change event on the input.However the type call, will trigger keyDown, keyPress, and keyUp eventsfor each character as well. It's much closer to the user's actual interactions.This has the benefit of working well with libraries that you may use which don'tactually listen for the change event.
We're still working on @testing-library/user-event to ensure that it deliverswhat it promises: firing all the same events the user would fire when performinga specific action. I don't think we're quite there yet and this is why it's notbaked-into @testing-library/dom (though it may be at some point in thefuture). However, I'm confident enough in it to recommend you give it a look anduse it's utilities over fireEvent.
The purpose of waitFor is to allow you to wait for a specific thing to happen.If you pass an empty callback it might work today because all you need to waitfor is "one tick of the event loop" thanks to the way your mocks work. Butyou'll be left with a fragile test which could easily fail if you refactor yourasync logic.
Let's say that for the example above, window.fetch was called twice. So thewaitFor call will fail, however, we'll have to wait for the timeout before wesee that test failure. By putting a single assertion in there, we can both waitfor the UI to settle to the state we want to assert on, and also fail faster ifone of the assertions do end up failing.
waitFor is intended for things that have a non-deterministic amount of timebetween the action you performed and the assertion passing. Because of this, thecallback can be called (or checked for errors) a non-deterministic number oftimes and frequency (it's called both on an interval as well as when there areDOM mutations). So this means that your side-effect could run multiple times!
This also means that you can't use snapshot assertions within waitFor. If youdo want to use a snapshot assertion, then first wait for a specific assertion,and then after that you can take your snapshot.
This one's not really a big deal actually, but I thought I'd mention it and givemy opinion on it. If get* queries are unsuccessful in finding the element,they'll throw a really helpful error message that shows you the full DOMstructure (with syntax highlighting) which will help you during debugging.Because of this, the assertion could never possibly fail (because the query willthrow before the assertion has a chance to).
For this reason, many people skip the assertion. This really is fine honestly,but I personally normally keep the assertion in there just to communicate toreaders of the code that it's not just an old query hanging around after arefactor but that I'm explicitly asserting that it exists.
As maintainers of the testing library family of tools, we do our best to makeAPIs that lead people to use things as effectively as possible and where thatfalls short we try to document things correctly. But this can be reallydifficult (especially as APIs change/improve/etc). Hopefully this was helpful toyou. We really just want to make you more successful at shipping your softwarewith confidence.
3a8082e126