Testing React Hooks with Confidence

Rate this content

The talk will be presented as a refactoring story - will start from the messy untestable component, cover it with a brittle smoke test, and then show how to move all our react component logic into a custom hook and test this hook. Will present patterns to test things like - useState, effects, and Apollo.

7 min
15 Jun, 2021

AI Generated Video Summary

The Talk discusses testing hooks in a React application. The speaker starts by showing an untested React application and begins testing with a simple placeholder test. The importance of refactoring and testing custom hooks is emphasized, with the recommendation to use the React hooks library and achieve full test coverage. Unit testing React components may not be valuable, as the complexity lies in the hook code. Instead, end-to-end testing with tools like Cypress is recommended.

1. Introduction to Testing Hooks

Short description:

Hello, everybody. My name is Radoslav Stankov. Today we're going to talk about testing hooks with confidence. I'm going to show you this untested react application. We can start with just a simple small test. This is just a placeholder test to make sure when I refactoring, I don't break something.

Hello, everybody. My name is Radoslav Stankov. You can find me online over here. I'm head of engineering at Product Hunt, and currently I'm located in Bulgaria. If you want to check out my presentations, they're over here. All the slides and code are linked to this page so you can check them later.

Today we're going to talk about testing hooks with confidence. There is this big divide between test-driven development and automated testing as you might see during this presentation. In my talk, I'm just going to mention how to automate testing. I won't go to test-driven and stuff around that. Again, talk is cheap and I don't have much of it, so let's show you some code.

I'm going to show you this untested react application. This is just a small calculator app. This is the code of the app. If you notice, there is a lot of it. It's a pretty simple app, but there is a lot of code. How would we test? How do we know that it works? What we can start with is, we can start with just a simple small test. For the small test, we can just add those test data attributes, so we can select the elements, we can use the React testing library and we can create this very simple small test where we get the React testing library. Usually when I do tests, I like to have those helpers because overall I hate writing five functions with each other. So I just say, okay, click this data ID. And for my test, this is another small trick I do if I need to rename the component and I want to go back and rename the test. So here I just created a very simple small test. It just works. So I'm just testing, empty zeros, clicking plus one, one, plus two, remove, two, evaluate, and reset. Basically making sure that this component works. This is something that I will do normally to test if things work manually. This is just a placeholder test. This is not like a real good test. Like, I'm going to remove this in the end, but this just makes me sure when I refactoring, I don't break something. It's not a very good test because it doesn't follow the four phases of good testing.

2. Refactoring and Testing Custom Hooks

Short description:

So where should we start now? The first thing we can do is clean up the code through refactoring. We can extract the big fat logic into a simple hook and test it using the React hooks library. After thorough testing, we can refactor the hook to use useReducer and achieve full test coverage. Unit testing React components may not be valuable, as the complexity lies in the hook code. Instead, end-to-end testing with tools like Cypress is recommended.

So where should we start now? So the first thing we can do is to clean up the code. What we can do is a refactoring. I like to call extract custom hooks. This is one of my favorite features of hooks is that you can actually boot hooks from other hooks and they create these very nice interfaces.

So here all these big fat logic can just be extracted into a simple hook, and this hook can give you, okay, that's what's the memory of the calculator and what are the actions. And again, the code for the hook is just copy paste, it works. So how do we going to test this custom hook? This is the next step we needed to do.

So for testing this custom hook, there is this nice library called React hooks from React testing library, which allows you to very easy test the hook and what I like to do is I want to have a function called emit hook, which basically hides the boilerplate setting up the hook. And for example, I want to test the add action. So for the add action, it's just setting up the hook, adding cut value and checking that after the hook is reloaded, we have updated our value and we can basically test, okay, if I have two digits, they're added, and you can go through all the tests for that, for remove is very similar. You set up the hook, you just call it, you have this nice call function where you encapsulate this and you have all of this. And again, it's a bit long and I would link you to the slides in the end so you can dig through more.

And now when we have this test, which very thoroughly test our hook with all its edge cases, with all its workarounds, we can actually start refactoring this hook. The thing we are going to end up in the end from this big ball of mud is basically refactor this hook to use just a simple useReducer where we say, okay, we have a reducer function and in the end we have the same actions add, remove, reset, evaluate. And this is again the reducer scope. It's a bit more complex. It's a bit more split, but this actually tests our calculator and we actually have like a full test coverage. And again, the code for this presentation is leaving this address so we can click it and go to the details. I actually split into steps so you can see all the refactoring steps. And a couple of the final notes I want to say here is in the end, I'm actually removing all that code from the smoke test. I don't need it. What I have found in practice is usually when I write React components, they're either very dumb, like they get some data and render stuff, so there's not much value adding to test them as a unit test. Or the biggest logic and the biggest thing I have in my test is the hook code. Like usually, that's the place where a lot of the complexity of my system is. So I generally stopped doing React unit tests. And what I try to do on the unit test level is to just unit test the simple function, like for example, I could just as the reducer, I can just test the hook by itself and not test the React components. The way I'm sure that the React components work is through doing end to end testing with something like Cypress or something like Capybara, which actually tests my whole workflow because I very rarely have found bugs in my system, which were regarded to just the React component itself. Usually the bugs come from very complex hooks or when we have class components, class components. So yeah, that's basically what I wanted to share with you today.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

TestJS Summit 2021TestJS Summit 2021
31 min
Test Effective Development
Developers want to sleep tight knowing they didn't break production. Companies want to be efficient in order to meet their customer needs faster and to gain competitive advantage sooner. We ALL want to be cost effective... or shall I say... TEST EFFECTIVE!But how do we do that?Are the "unit" and "integration" terminology serves us right?Or is it time for a change? When should we use either strategy to maximize our "test effectiveness"?In this talk I'll show you a brand new way to think about cost effective testing with new strategies and new testing terms!It’s time to go DEEPER!
TestJS Summit 2023TestJS Summit 2023
32 min
The Art of ‘Humble Views’: Testing React Native Apps the Smart Way
In this talk, we explore the divisive world of testing, where developers often find themselves torn between writing no tests and striving for 100% test coverage. Learn how to navigate these polarizing positions and adopt a more nuanced strategy that makes testing efficient and effective.We'll dive into the concept of 'Humble Views,' where we minimize untestable objects by extracting logic from UI elements into test-friendly parts of the codebase. This approach simplifies testing, focusing on business logic instead of UI complexities. Discover how the Model-View-Presenter (MVP) architecture helps achieve this, with presenters serving as a logical layer for testing and hooks aiding in separating logic from UI components.Throughout the talk, we'll discuss the trade-offs of this approach, the role of End-to-End (E2E) tests, and how to strike the perfect balance between too much and too little testing. Join us as we delve into the art of creating 'Humble Views,' ensuring that our React Native apps are scalable, maintainable, and effectively tested!
TestJS Summit 2023TestJS Summit 2023
29 min
Component Testing With Vitest
Testing is important. Proper unit tests can eliminate the chance for bugs to appear. But which testing framework will be suitable? Let’s explore how we can develop a reliable and efficient strategy for component development and testing with Vitest
TestJS Summit 2021TestJS Summit 2021
20 min
It's a (Testing) Trap! - Common Testing Pitfalls and How to Solve Them
It’s a trap” - a call or feeling we all might be familiar with, not only when it comes to Star Wars. It’s signalizing a sudden moment of noticing imminent danger. This situation is an excellent allegory for an unpleasant realization in testing. Imagine having the best intentions when it comes to testing but still ending up with tests failing to deliver you any value at all? Tests who are feeling like a pain to deal with?
When writing frontend tests, there are lots of pitfalls on the way. In sum, they can lead to lousy maintainability, slow execution time, and - in the worst-case - tests you cannot trust. But it doesn’t have to be that way. In this session, I will talk about developers’ common mistakes (including mine), at least from my experience. And, of course, on how to avoid them. Testing doesn’t need to be painful, after all.
TestJS Summit 2022TestJS Summit 2022
24 min
Unit Testing Angular Applications
Angular offers many things out of the box, including various testing-related functionalities. This presentation will demonstrate how we can build on Angular's solid unit testing fundamentals and apply certain patterns that make testing easier. Topics covered include: test doubles, testing module pattern, harnesses, "recipes" on how to test some common cases, and more!