OpenReplay
Navigate back to the homepage
BLOG
Browse Repo
Back

An Easy Guide to Testing React Hooks

Nwose Lotanna Victor
December 18th, 2020 · 4 min read

In this post, we will be looking at an overview of React hooks and then an easy way to test them independently with a React Hooks testing library.

What are React Hooks?

Hooks in React are basically functional components with the powers of classes, this means that the application and advantages of lifecycle methods can now be accessed in a functional component without being in a class.

Types of Hooks

Some of the hooks that exist in React are UseState for handling simple changes in state and acting like Lifecycle hooks in React class components would act in a functional component. There is also UseEffect used to handle effects like timers, listeners, and persistent connections. UseReducer acts like Redux for complex state changes and you can even create your own custom hooks in React too so these are not the only hooks you have access to.

Why Hooks?

Classes are still very much supported in React but there are few reasons behind the new and shiny kid on the block, hooks. One of which is how difficult it is to re-use stateful logic and all the ways we deal with higher-order components. Another reason is readability, with hooks in place you are guaranteed to write fewer lines of code and thereby impacting readability very positively. Classes can be confusing, a lot of developers still struggle with how ‘this’ works in JavaScript and it still differs from one language to another. You can take a look at the hooks documentation here to get started with using it. A hook looks something like this:

1import React, { useState } from 'react';
2 function Example() {
3 // Declare a new state variable, which we'll call "count"
4 const [count, setCount] = useState(0);
5 return (
6 <div>
7 <p>You clicked {count} times</p>
8 <button onClick={() => setCount(count + 1)}>
9 Click me
10 </button>
11 </div>
12 );
13 }

You might be new to hooks and wondering how to test them just like you can test other React components. This post will take you through a very easy process.

Testing in React

For a good engineer, testing is important for so many reasons and some of them are to ensure you write quality code that does exactly what you expect it to do. It is also important so you save time debugging later, because more tests means less errors in general. Hooks are tested like other functions are tested in React with robust libraries like:

Jest

Jest is hands down the most popular testing library for React components and it was build by the Jest team at Facebook and used by Uber and even Airbnb to name a few companies. React recommends it as the testing library of choice and it works with JavaScript projects like create-react-app to Vue and even Babel. The UI snapshot testing is probably one of the most amazing things about Jest, it can also do parallel testing based on predefined processes and with optional priority that can be set for failed tests.

Enzyme

Enzyme is a JavaScript testing library that was designed by the team at Airbnb to easily test React components. It lets you do shallow rendering of particular components and access the business implementations of the components. You can also perform DOM rendering with enzyme and even test hooks.

Jasmine

Jasmine is popularly known as the testing framework for Node and browsers. It is a behaviour-driven testing library for JavaScript projects and so it does not necessarily depend on the structure of the project or even the browser. Ut is mostly used for Angular projects but it is great for testing React components too. With Babel and Enzyme, you can test a React component using Jasmine

Today we would use something new and easy to start with.

React hooks testing library

This library was built and maintained by over 35 React community members as a beginner-friendly testing library for React hooks. It has great documentation and anyone can easily follow it to test their Hooks, the contributors did a great job. It allows you to test hooks and provides you with even more utility functions to play with. You might have gotten this error before:

1Invariant Violation: Hooks can only be called inside the body of a function component.

But still want to call tests within the body of your functional components, keep reading.

Getting started

The first thing to do is to create a new React project, let us call it my-app so in your terminal navigate to your preferred file location and run these:

1npx create-react-app my-app
2 cd my-app
3 npm start

Next, you have to install the library and its dependencies so run the following commands:

1npm install --save-dev @testing-library/react-hooks
2 npm install --save-dev react-test-renderer@^16.9.0

What we will build

We are going to build a small counting game that would use the useState React hook to hold state.

Game Hooks

Navigate to the root folder and change the content inside the app.js file to the code block below:

1import React from 'react';
2 import {Count} from './Count'
3 import './App.css';
4 function App() {
5 const {counter, add, remove} = Count()
6 return (
7 <div className="App">
8 <h1>
9 This is a counter game
10 </h1>
11 <button onClick={add}>Add one</button>
12 <button onClick={remove}>Remove one</button>
13 <h3>{counter}</h3>
14 </div>
15 );
16 }
17 export default App;

You can see that our app file is a functional component that returns the counting game. However, the logic for the addition and subtraction is being imported into the file. To set that up, create a new file in the same root directory and call it count.js and copy the code block below into it

1import React from 'react';
2 export const Count = () => {
3 const [counter, setCounter] = React.useState(0);
4
5 const add = ()=>{
6 setCounter(counter + 1)
7 };
8 const remove = ()=>{
9 setCounter(counter - 1)
10 };
11 return { counter, add, remove}
12 };

You can see that the useState hook is used here to simply hold the state of the counter as it changes by increase or decrease.

Testing the hook

Now that we have the testing library installed we can test for two outcomes

  1. That the addition actually works
  2. That the subtraction also works too.

Create a test file that React recognizes and that would be count.test.js and inside it copy the code block below:

1import {Count} from './Count'
2 import {act, renderHook} from '@testing-library/react-hooks'
3 import expect from 'expect'
4 describe("Adding one", () => {
5 it("Adds one to counter", () => {
6 const { result } = renderHook(Count)
7 act(()=> {
8 result.current.add()
9 })
10 expect(result.current.counter).toBe(1)
11 });
12 })

So we use “describe” to explain what we are to test in one test suite and then have the “it” blocks for each test. Inside the block, you will specify the action which in our case is to add, and then you will state what the expected outcome should be. Just like any logical test, you will preset conditions to be tested. Remember we are testing for two outcomes so go back to your count.js and update the code block to contain the subtract side of the test like this:

1import {Count} from './Count'
2 import {act, renderHook} from '@testing-library/react-hooks'
3 import expect from 'expect'
4 describe("Adding one", () => {
5 it("Adds one to counter", () => {
6 const { result } = renderHook(Count)
7 act(()=> {
8 result.current.add()
9 })
10 expect(result.current.counter).toBe(1)
11 });
12 it("Removes one from counter", () => {
13 const { result } = renderHook(Count)
14 act(()=> {
15 result.current.remove()
16 })
17 expect(result.current.counter).toBe(-1)
18 })
19 })

If you want to run the test, you can have to use a command for your specific package manager, if NPM

1npm test

and if you use Yarn then:

1yarn test

If you did everything correctly, your two tests should pass like mine.

null

Wrapping up

In this article, you have been given a brief overview of React Hooks and how important they can be. You have also been taken through easily testing your React hooks with the React hooks testing library.

Observability for Production React Apps

Debugging React apps in production may be challenging and time consuming. OpenReplay is an open-source session replay stack for developers. It helps you replay everything your users do and shows how your app behaves and renders for every issue. It’s like having your browser’s inspector open while looking over your user’s shoulder.

OpenReplay Frontend Monitoring

OpenReplay helps to quickly get to the root cause by reproducing issues as if they happened in your own browser. It also monitors your frontend performance by capturing key metrics such as page load time, memory consumption and slow network requests as well as Redux actions/state.

Happy debugging, for modern frontend teams - Start monitoring your web app for free.

More articles from OpenReplay Blog

How to Use Props to Pass Data to Child Components in React.js

Learn how to make your React components reusable by using props. Props are a powerful feature that enables the component-based approach.

December 14th, 2020 · 3 min read

How to Make HTTP Requests with Axios

Get started with Axios and learn how to make HTTP requests like a pro with the most popular libraries, while keeping security in mind.

December 10th, 2020 · 5 min read
© 2021 OpenReplay Blog
Link to $https://twitter.com/OpenReplayHQLink to $https://github.com/openreplay/openreplayLink to $https://www.linkedin.com/company/18257552