Current section: Hooks 4 exercises

Testing React Hooks

Loading solution


00:00 The first step here is we need to make a test component. So let's make this function called testComponent. And then we're going to need to manage some state to communicate to the outside world what the current state of our internal state is. So we are going to get our double check

00:18 from useDoubleCheck, but then we need to maintain some state to determine the stuff that we need to assert on. And so if we look at our hook test, the biggest thing we're asserting on is whether or not default was prevented and also the double check value as well.

00:38 And so while we do want to kind of resemble the real world scenario, we also have this default prevented contract that we have with this hook. And so we're going to actually track that specifically with the useState. So this will be default prevented. Prevented.

00:59 And the initial, this is going to be like an enum string state. So initially we're going to say idle, where idle is kind of like, well, default hasn't been prevented. Nothing has been prevented. It's not even started yet. So we're going to bring in useState and we're going to specify idle

01:18 as one of the possible options, or no, or yes, as in no, it has not been prevented yet, or yes, it has been. And then we can return our output that says default prevented and then default prevented right there.

01:37 And then on top of that though, we need to have something we can interact with. So we're going to render a button and this button is going to just say, yeah, click me, or we can actually just double up here a little bit and say, double check, you sure, or click me. And so that will give us all the information

01:57 that we need to know about how useDoubleCheck is supposed to be used, as well as some of the things that are going on inside of it. And so here when we have this, our getButtonProps, we have our own onClick and we can determine whether the default was prevented based on E.defaultPrevented. So if it was, then we'll say yes,

02:17 otherwise we'll say no. And that is everything we need for our test component. So now we are going to render our test components. So render, coming from testing library React, the test component, we'll await that. And then we're also going to use another utility called UserEvent

02:37 that will simulate what it's like for a user to actually click on buttons and different things like that. So we're going to make a user object called UserEvent, get that from UserEvent.setup. UserEvent is going to come from testing library UserEvent. And with that, then we can first verify the initial state.

02:58 So let's actually get our output, or actually the role of an output element is called status. So we'll call this status. Screen, getByRole, by role, and that's status. Screen, of course, needs to come from testing library React. There we go.

03:18 And then our button is getByRoleButton. Okay, so then we can expect the status. At first, it should have the text content default prevented as idle. And the button should have the text content of click me. And then we can click on the button.

03:36 So we'll await user.clickButton. And that will trigger a rerender and all of that. So we can assert that the default was prevented. So that's going to be a yes right there. Thanks, Copilot. That's why you always review your AI assistants. They are the assistant for the foreseeable future.

03:57 Hopefully forever. Okay, so then we're going to click on the button again and verify the state was updated properly. So now the default prevented should be no. And actually the way that our component or our hook is implemented,

04:17 it actually doesn't ever unset the default or the double check variable. That's just the way that it works. So our are you sure is still what it's going to be rendered there. So we save this. The test passes. That's kind of anticlimactic because it was passing already. So let's make sure that it can fail. In fact, so if we change this,

04:36 then yep, that's going to blow up. It's not happy about that. If we change, actually even better would be to change the implementation here. We change this to false. That should also blow up on our tests, both of our tests. So we are in fact testing what we think we are

04:53 and we're getting the value out of this that we want. So in review, the idea of a test component is just to create a component that kind of resembles the way that you expect your hook to be used. And also ensuring that any of the API contracts that are a part of your component

05:13 are also given some mechanism for output inside the test component. You can do some pretty wacky things in here. And this is actually totally a place where a data test ID attribute makes a ton of sense too. Now you don't typically want to do that in your source code but doing that in a test code situation makes sense too. So there you go.

05:33 That is a test component. Between the two of these, I like the way that this reads a lot better. It just like makes more sense to me but some people might like this nonsense. I don't know. Some people might. Not me, but some people maybe. So I prefer the test component

05:51 and at least for this specific hook. And that is how you test hooks.