Testing a Custom useBoolean Hook With React Testing Library
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
This lesson preview is part of the The newline Guide to Creating a React Hooks Library course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to The newline Guide to Creating a React Hooks Library, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

[00:00 - 13:47] All right, so first of all we need to install all needed required dependencies to test our hooks Plus we need to delete this useless index test type script file Okay, let's just delete it. All right, so the dependencies we were going to install Will be the testing library react hooks And testing library react And also react dumb Because this one is needed in order to render Something to our fake G has dumb think it's a requirement here and let's just sort this thing nicely Good and run the installation so yarn or NPM install All right, let's clear the console All right, let's give us more space here. Okay, so why these two libraries, right? So first of all about testing library If you're not familiar with testing library set of libraries They are basically a set of wrappers around dumb select There's another custom selectors that make testing more user behaviors centric by user behaviors centric, I mean It's API design in a way that if you select your components, you're not doing that by you know react display name or playing good old CSS selector But by using more user land terms like find by label or find by text So all tests are really look like a real high-level user interaction scenario This scenarios are way more important to the user and has hence the developer Then the implementation details that are not really that important For you to sleep calmly, right on this Friday evening production deploy So in other words It's focusing on making your tests give you some confidence and actually that's the main purpose of the test to You know give you confidence that your code is still Not degrading to any sense and working perfectly also since implementation details are not actually Important for us, right because we are testing the user scenario and we select stuff using user land selectors and stuff like that We can even change the our underlying framework. So let's say react it to change it to swaddle or swelt swelt I think Or to the view or whatever of course you'll have to change some You know beginning of the test how you render it, but the rest of your select ors You will be able to just you know keep them as this and if you do one-to-one application It will just continue to be correct and all your test cases will be kind of logically correct And only few things will be will will have to be changed And it's it's really great. It's golden and if you're still using enzyme For testing react components. I really recommend you to move towards testing library act Okay, so although if we're testing the functions meaning we make unit testing right and not integration testing that we've been mentioning before We need to go down to the role variables reference comparisons, etc. In case of hooks When you test them the problem is that you have to render your you have to use your hooks inside of your Components react components and for that purpose at the very beginning of hooks when it's only was released You had to create a dummy components and do some Tricky stuff to actually check whether stuff got changed etc. And it's super compsie So to avoid all that and avoid rendering dummy components. We're going to use testing library react hooks Package which is essentially a set of helpers to test hooks in isolation like the unit does them I recommend as well as the authors of the library recommend that to use it only for highly reusable hooks or hooks Libraries like the one that we're trying to do right now like the copy of react hanger now So in all the scenarios you should test whole component instead By just using whole testing library act because you really care about what is getting Rendered and not the actual you know implementation of the hook itself that is used in some particular component Okay, so I think I cleared everything up here and let's start actually writing the tests Okay, so let me create a file named use boolean test gs use All right, and let's actually put it in the test test directory, so it's nice and Beautiful, okay, and let's start with our describe block first All right Okay, now let's write our first case inside the describe block right so Let's check that if we call the set true function it will actually set true our state right so Let me just do that all right, so and let's just import reender hook and use boolean from our beautiful Array use boolean function and act Let's import it from react hooks as well All right, so this how it all looks and let me explain step by step right So first we render our hook right using the helper function render hook from react from testing library act hooks It then returns the result Here which is basically as you can see is a boolean use boolean action. So exactly what we called here will be Returned, but it will be returned because as you can see it's wrapped wrapped in the hook result generic function generic type it will be a rough basically so in order to access these These two things that our use boolean thing is getting returned we need to Call the current thing so okay, we ignored the The state here and we just care about the Actions and what we are doing here we say like expect result current zero so our state to be false and Then we do set true so we wrap it all in act which is important and then we assert that Our state has changed the true You may ask Why Am I not just here have a state right and then assert Against it and the reason is because then the state will be you know It will not change it will be if it was false. Let's say at this stage. It will stay false at that stage too But if we're using current we actually using a ref and ref will be changing after the acts etc So if we will call it like that we will get the actual value of our state Okay, so it may be confusing why I'm wrapping stuff in act but It's really hard to explain maybe but ensure if any action or function call Like that you're going to call Inside your test is going to change the react state Then you have to wrap it in the act What it does is basically tells to the react that all state changes should be flashed Back flashed back to your dumb before doing any assertions So because the react currently is absolutely synchronous and it's a lot of magic happening here underneath you You know, they they created few helper functions to actually aid your test Running and all these processes the synchronous processes in some way so you can actually Can him like can you please flush all the state changes before I run any other code and he said like okay surely everything is flushed you can Continue executing your assertions and then you check it and everything if Everything is rendered it will the changes will be here okay, so very important to mention also is that most of the functions that are Inside the testing library react are already wrapped in act so stuff like fire change or all kind of you know interactions, etc And they are automatically wrapped in act Just in case so it will be you know, not sure without all these callbacks, etc But sometimes you have to just use the act explicitly and it's absolutely fine All right, so let's test the rest of our functionality So let me copy paste a little bit Here we go so pretty much the same function that will check that false will be set Nothing different much and the toggle one again, we start with the true Then we double check that it's still true after we render this then we act the toggle It changes changes to false then we act and toggle again. It changes to true So let me run the test So you can clearly see that everything is green so far so npm test Okay failed in the problem with all that it's cannot find react test vendor great, so I forgot one dependency, so let's edit It's pure dependency of testing library react, let's install it It and sort beautiful okay, let's run it again Great something failed Cannot find module area use Boolean next total sense. Let's just call it like that two things call it again All right, so everything is great everything is green Next step would be to actually check something really important the one thing that we've been discussing in the last lesson is all these reference to quality, so we Are avoiding all these unnecessary rerenders for no reason so Let me do that All right, so here we go. Let's do another describe block inside here And Let me explain what's happening here. Let me just make this Terminal smaller so here we go what's happening again? We are rendering our His book hook then we save our original original actions reference as you can see that's the original actions reference We then destructor all destructor all these actions and what we are doing we actually Check that Everything is matching that original is original and everything is great Then we act we do set false it could be you know set true to to be honest But set false will guarantee to change our state so it means that our Dummy component that is used under the hood and this render hook will be re rendered and if something is getting rerendered Then you're not handling your references properly you will have a different references hence unneeded renders or Use effect will be triggered for no reason etc. So you need to minimize properly and then what we're doing we take our original References here and we just basically compare Them to what is actually there in our reference in our ref in our current After this render and if they are matching means our minimization is correct and the references are the same So let me run the test and see if everything is great. So let me clear this mass and let's run the test Everything's green. So let me break it just so we are sure that we We actually testing something right?
[13:48 - 15:40] So let me do it like that. Let's remove the callback. So false should actually Get broken All right now complaints Yeah, it's actually tells me that it's going to be to be change every every single render It's actually nice that it's immediately tells me that yes, but Let's run the test. So I will prove you. Yeah, as you can see it's failed. Well , it says that Object equality so they serialized the same string, right? Exactly the same but their reference Is different. That's why this assertion is failing and you can see it's failing exactly on our original sections reference because our original actions reference is actually changing every render because here this thing is Getting changed it. So the actions are getting changed for no reason. So it's actually failed even before the set false thing so let's revert it and run it again Everything is beautifully And everything is running and as you can see we can save a lot of time by not going to a code sandbox and you know check our how our dummy component will behave with different set of actions or just functions or just stay it etc. So it saves you a lot of time so That's it for Our usable and testing and next up we will implement our use map hook which will be the wrapper around the map default JavaScript data structure And yeah, we will be using tdd so test driven development first we will implement the tests And then we will implement our use map function That's it for this lesson. Go to the next one