This video is available to students only

Testing React hooks and components

This lesson introduces many things — React Testing Library, Jest, MSW, and we'll get a sneak peek of testing React Components and React hooks.

We implemented a custom React hook in the previous lessons and tested it manually from within a sample application. However, we want to ensure that it's working as expected without trying it manually after every change to the front-end application. We want to make sure that the development of the application won't break existing functionality. That's why we're going to cover testing React components in this lesson.

We can find the following recommendation in theReact docs:

If you need to test a custom Hook, you can do so by creating a component in your test and using your Hook from it. Then you can test the component you wrote. To reduce the boilerplate, we recommend usingReact Testing Library which is designed to encourage writing tests that use your components as the end-users do.

The React Testing Library allows us to test React components smoothly. It comes with utility functions that empower us to write maintainable and thorough tests. As Testing Library is only a testing utility, we also need a test runner. We'll use Jest for that.

Installing dependencies#

So, let's get to the setup part. We need to install a few things:

  • jest — the test runner.

  • @types/jest — type declarations for Jest.

  • ts-jest:

    ts-jest is a Jest transformer with source map support that lets you use Jest to test projects written in TypeScript.

    https://kulshekhar.github.io/ts-jest/

  • @testing-library/react — testing utilities for React components. Docs:https://react-hooks-testing-library.com/.

  • @testing-library/user-event — it provides an advanced simulation of browser interactions.

  • node-fetch — our tests will be run by node, but the Fetch API is not implemented there. Thus, we need an external module to handle fetch requests.

We're also going to add a new script in the package.json so that we can typeyarn test in the terminal, and Jest will run all the tests:

The last step for setting the test runner is adding a Jest configuration. For that, we'll create a jest.config.js file in the root directory, and we'll set the following settings:

  • preset: 'ts-jest,

  • testEnvironment: 'jsdom' — The default environment in Jest is the node environment. However, we have a web application, so we need a browser environment.

  • globals: { 'ts-jest': { tsconfig: { jsx: 'react-jsx' }}} — we're going to use JSX in our test, so we need to let ts-jest know how it should transform JSX syntax.

  • setupFilesAfterEnv: ['./test/setup.ts'], — we want Jest to run a custom setup steps before running the tests.

We also need to create thesetup.ts file. In there, we'll put the following code:

As we mentioned before, fetch doesn't exist in node, so we need to declare that it should use the node-fetch module instead.

Testing React Hooks#

When you look at the useComments hook we implemented, you may notice that it'sjust a function. It may be tempting to call it and test the result. However, we can't do that for the following reasons:

  • It's not a pure function. Our hook has side effects (API calls), so the test result is not solely dependant on the parameter, but it relies on the outside world — the API.

  • We would break the rules of hooks — hooks are only supposed to be called inside of a function component. If we call it outside of a component, we'll get an error:

What's more — the hook is intended to be used inside a component, so testing it outside won't cover its functionality. Ideally, we should always test things in the way they are used.

We will test the whole comments section in this course — we'll write a test for both the hook behavior and the component behavior.

Previously, we wrote the whole code in [slug].tsx file. Let's extract the comments section to a separate component. It will accept the postSlug prop and call the useComments hook.

We'll use it in the Post component in place of the previous code:

Start a new discussion. All notification go to the author.