Testing React Hooks with Confidence

Rate this content
Bookmark

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.

This talk has been presented at TestJS Summit - January, 2021, check out the latest edition of this JavaScript Conference.

FAQ

Radoslav Stankov is the head of engineering at Product Hunt and is currently located in Bulgaria.

The main topic of Radoslav Stankov's presentation was about testing hooks with confidence, focusing on automating testing without delving into test-driven development.

The simple small test demonstrated by Radoslav was used as a placeholder to ensure that the basic functionalities of a component work correctly during refactoring, even though it doesn't follow the four phases of good testing.

Radoslav Stankov suggests using the React hooks testing library to easily set up and test custom hooks, demonstrating how to test actions like 'add' and 'remove' within the hooks.

Radoslav favors the technique of extracting complex logic into simpler, custom hooks to clean up the code, which he then further refactors using useReducer for managing state and actions.

Radoslav Stankov has shifted from unit testing React components to focusing on end-to-end testing using tools like Cypress or Capybara, particularly because he finds that the most complex and bug-prone parts of his systems are within the hooks or class components.

The code and slides from Radoslav Stankov's presentation can be accessed through a link he provides during the talk, which includes detailed steps of the refactoring process and testing examples.

Radoslav Stankov
Radoslav Stankov
7 min
15 Jun, 2021

Comments

Sign in or register to post your comment.

Video Summary and Transcription

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.
Available in Español: Probando React Hooks con Confianza

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

Test Effective Development
TestJS Summit 2021TestJS Summit 2021
31 min
Test Effective Development
Top Content
This Talk introduces Test Effective Development, a new approach to testing that aims to make companies more cost-effective. The speaker shares their personal journey of improving code quality and reducing bugs through smarter testing strategies. They discuss the importance of finding a balance between testing confidence and efficiency and introduce the concepts of isolated and integrated testing. The speaker also suggests different testing strategies based on the size of the application and emphasizes the need to choose cost-effective testing approaches based on the specific project requirements.
The Art of ‘Humble Views’: Testing React Native Apps the Smart Way
TestJS Summit 2023TestJS Summit 2023
32 min
The Art of ‘Humble Views’: Testing React Native Apps the Smart Way
This Talk discusses the challenges of testing in React and React Native applications, particularly with regards to barcode scanning. It explores the violation of separation of concerns in React and proposes the use of the HumbleObject model to simplify testing and improve code cleanliness. The MVP model is also introduced as a way to separate UI state and logic from the component. The importance of following patterns, standardization, and teaching principles is emphasized, along with the benefits of using custom hooks to share business logic. The potential of AI tools in code refactoring is mentioned as well.
We May Not Need Component Testing
Vue.js Live 2024Vue.js Live 2024
26 min
We May Not Need Component Testing
Component testing is a gray area between integration and unit testing. The demo app focuses on the cart component and writing test cases for Playwright component test and VTest. The first cart test encounters a bug with the invisible method in View Test.
Component Testing With Vitest
TestJS Summit 2023TestJS Summit 2023
29 min
Component Testing With Vitest
This Talk explores the challenges of choosing and learning testing frameworks, emphasizing the importance of planning, automation, and prioritizing unit testing. The VTEST framework is introduced as a fast and stable option for unit testing JavaScript and TypeScript code, with a focus on logic and mocking external dependencies. The Talk also covers testing React hooks, integration testing with TestingLibraryReact, component testing, and achieving code coverage. Best practices include performing accessibility tests, planning tests before coding, and using data test IDs for stability.
It's a (Testing) Trap! - Common Testing Pitfalls and How to Solve Them
TestJS Summit 2021TestJS Summit 2021
20 min
It's a (Testing) Trap! - Common Testing Pitfalls and How to Solve Them
This Talk explores the pain points and best practices in software testing, emphasizing the importance of simplicity and comprehensibility in test design. It discusses techniques such as the three-part rule for test titles, the triple-A pattern for test structure, and the use of clear and descriptive names in tests. The Talk also highlights the traps of testing implementation details and using fixed waiting times. The speaker encourages teamwork and learning from experience to improve testing practices.
How to Catch a11y Defects During Unit and E2E Testing
TestJS Summit 2021TestJS Summit 2021
7 min
How to Catch a11y Defects During Unit and E2E Testing
This Talk provides ways to catch accessibility defects during testing, including adding accessibility testing to a website for Studio Ghibli using React, NX, Jazz, JazzX, Cypress, and CypressX. The importance of unitizing components and conducting end-to-end testing with Cypress and CypressX is emphasized to ensure accessibility. The process of setting up CypressX testing is explained, highlighting the use of typings and the CypressX support file. These tools make it easier for developers to avoid accessibility bugs during development.

Workshops on related topic

Learn To Use Composables: The Swiss Army Knife Of Vue Developers
Vue.js Live 2024Vue.js Live 2024
163 min
Learn To Use Composables: The Swiss Army Knife Of Vue Developers
Workshop
Juan Andrés Núñez Charro
Juan Andrés Núñez Charro
Composables (composition functions) are stateful/stateless functions that can leverage Vue's reactivity API, decoupling it from components.This shift in perspective opens the possibility for tackling common scenarios in a new and creative way. In this workshop, you will learn how to solve typical problems every Vue developer faces, using composables:
- Data store;- Component cross-communication;- Utility functions (DOM, API, etc);And more.
Introduction to React Native Testing Library
React Advanced Conference 2022React Advanced Conference 2022
131 min
Introduction to React Native Testing Library
Workshop
Josh Justice
Josh Justice
Are you satisfied with your test suites? If you said no, you’re not alone—most developers aren’t. And testing in React Native is harder than on most platforms. How can you write JavaScript tests when the JS and native code are so intertwined? And what in the world are you supposed to do about that persistent act() warning? Faced with these challenges, some teams are never able to make any progress testing their React Native app, and others end up with tests that don’t seem to help and only take extra time to maintain.
But it doesn’t have to be this way. React Native Testing Library (RNTL) is a great library for component testing, and with the right mental model you can use it to implement tests that are low-cost and high-value. In this three-hour workshop you’ll learn the tools, techniques, and principles you need to implement tests that will help you ship your React Native app with confidence. You’ll walk away with a clear vision for the goal of your component tests and with techniques that will help you address any obstacle that gets in the way of that goal.you will know:- The different kinds React Native tests, and where component tests fit in- A mental model for thinking about the inputs and outputs of the components you test- Options for selecting text, image, and native code elements to verify and interact with them- The value of mocks and why they shouldn’t be avoided- The challenges with asynchrony in RNTL tests and how to handle them- Options for handling native functions and components in your JavaScript tests
Prerequisites:- Familiarity with building applications with React Native- Basic experience writing automated tests with Jest or another unit testing framework- You do not need any experience with React Native Testing Library- Machine setup: Node 16.x or 18.x, Yarn, be able to successfully create and run a new Expo app following the instructions on https://docs.expo.dev/get-started/create-a-new-app/