Transcript
00:00 Sometimes you've got low-level hooks that you want to test because they're pretty complicated or they're just really critical to the business or something, and so you want to have a couple of tests that are specific for this hook. And so there are actually two approaches that we can take, and they both make sense in some scenarios. So we're going to go through both of them.
00:17 The first is just here is an example using UseCounter, pretty simple thing. But the first is to use the RenderHook utility from Testing Library React. What this does is it accepts a callback, and then you return whatever is returned from your hook.
00:35 And then it's actually going to create a little mini-component, and it will manage making sure that this gets re-rendered anytime a re-render needs to happen, and it always ensures that you have the latest value that was returned from your hook. And you access that on this result, and you have result.current. There are a couple of other things that are returned from here.
00:55 You don't typically really need to use them. There's like a re-render and other things. But yeah, so our result.current is what you're mostly going to be using. It's very important that you always use result.current to access the current value of anything that you've got in the return value of your hook. And this is just the way that JavaScript works.
01:14 But if you try to destructure the increment and decrement from current, you're going to have a hard time. Just that's how JavaScript works. We've got to access the latest version so that the render hook utility can update that current version with whatever the current thing is. So just remember that.
01:32 Always use result.current. The other thing that you might notice here is this act utility. This is actually a re-export from React, and it has a couple other bits and pieces to it with React Testing Library. But the act utility is a mechanism to let React know that, hey, I'm going to do something that's going to update some states.
01:52 So here this increment is calling setCount. And React is going to, whenever state updates happen, it just kind of batches them up. It puts them in like this list. And then when it says, okay, I think they're all done, I'm going to run through all of these and then update the DOM. This is just for performance reasons.
02:09 And so if we don't wrap things in act, then React doesn't know if we're going to say, hey, I want to increment like 12 times. It doesn't know what's going to happen next. And so it's just going to batch all these things up, and then it's going to wait until it says, okay, I guess they're all done, and I'll execute all of those.
02:26 And so for that reason, we use this act utility that will ensure that once the callback is finished, it tells React, okay, we're all done. You can go ahead and re-render, and then it re-renders, and we can continue from there. So that's why we have to use act. What a pain.
02:44 But, you know, it actually is pretty simple. And most of the time, you actually don't need to use act, as is the case in our test components version. So with the test component version, you're going to be using regular render, and we're going to be using this user event to fire events.
03:04 So we have this example component that has use counter, and we get all the values. So we're just using our hook the way that we typically would. And we also output some stuff here. There are actually not many rules when it comes to your test component. You can do whatever you want to.
03:22 Just use the hook the way that it's typically used, and make sure you're exporting or exposing buttons for updating state, and some sort of output so that you can make assertions on that state. And then you just test it like a regular component. So we're going to render the component. We get the status. That's what the output role is, by the way.
03:41 It's an implicit role called status. So we're going to get that text content and verify that. Then we can get the button and click on that and verify the text content again, and all of that stuff. It all works really nicely. And yeah, and actually, we won't have a result.current. That was a typo. Get rid of that thing.
03:59 So we actually will always just be able to use our utilities here. So that is correct. There you go. Watching the creation of this workshop in real time. So by the way, there will probably be other mistakes.
04:18 In fact, I'm going to tell you there is a mistake that I saw as we were scrolling through this in this code sample. And if it's still there, then you can make a pull request to fix it. So I will hold off on fixing it to give you an opportunity to make a pull request if you'd like to. It's not a big mistake.
04:35 If it was a big mistake, I wouldn't put you people through that. But it's a pretty simple, harmless mistake that one of you is going to fix, and that'll be kind of fun for you and for me. It's fun for all of us. Open source rocks. Okay, so the last thing I want to talk about is this user event.
04:51 So user event, let me take a step back. Testing library has built in a mechanism for firing events on DOM elements. This is called fire event. And it takes all of the different events that are browser-based events and gives you a nice API to say,
05:11 hey, this is my DOM node, fire a click event on that thing. The thing is that when a user clicks on a DOM node, they're firing more than just one event. They're firing a mouse over and a mouse down and a mouse up and a click. Or maybe they're using a keyboard, and so it's a tab, and then they're hitting space.
05:29 And then there's also what was the active element before? That element is going to get a blur event. And so there are just a ridiculous number of events going on all at the same time. And so while fire event is really useful for firing just discrete events, it's not the complete story,
05:47 and you're not going to get everything out of that that you should. So the user event actually uses fire event to ensure that you fire all of the events that a user typically would perform
06:01 when the user performs a particular action, like clicking or typing in a keyboard input or an input or all of that stuff. So that's why we recommend you always use user event as much as possible.
06:16 Fire event is useful sometimes, and user event doesn't have all of the different actions that a user can perform, but it does a pretty good job. And so if you're using testing library in a JS DOM environment or in a framework that doesn't support firing events from a user,
06:34 then user event is what you use. In Playwright, we actually have a whole suite of different actions that you can perform, and they do a really, really good job, even better than user event. And so don't use user event over in Playwright, but yeah, in here, you definitely want to.
06:50 OK, I think that's everything you need to know about hooks and testing them. So I think it's time for you to get started and try out these two different approaches for testing a hook. Have a good time.