close icon
daily.dev platform

Discover more from daily.dev

Personalized news feed, dev communities and search, much better than what’s out there. Maybe ;)

Start reading - Free forever
Start reading - Free forever
Continue reading >

React JS Jest: Beginner's Guide

React JS Jest: Beginner's Guide
Author
Nimrod Kramer
Related tags on daily.dev
toc
Table of contents
arrow-down

🎯

Learn how to test your React apps with Jest using this beginner's guide. Explore Jest basics, React Testing Library, mocking, advanced techniques, best practices, and common challenges.

Testing your React apps with Jest is a crucial step in ensuring your code is robust and error-free. Here's a quick guide to get you started:

  • Prerequisites: Familiarity with React, Node.js, and basic JavaScript testing principles.
  • Setting Up: Use Create React App for easy setup or configure Jest manually in your project.
  • Jest Basics: Learn about describe and it blocks for organizing tests, and expect matchers for making assertions.
  • React Testing Library: Utilize tools like render, screen, and userEvent for interacting with your components in tests.
  • Writing Tests: Start with simple tests checking if components render correctly, then move on to simulating user interactions and testing state changes.
  • Mocking: Use mocking to isolate components and replace complex dependencies with simpler versions for testing.
  • Advanced Techniques: Explore snapshot testing, testing props and state, and more sophisticated mocking strategies.
  • Best Practices: Keep tests independent, use clear naming, simplify tests, and employ helper functions for repeated actions.
  • Common Challenges: Learn how to tackle issues like mocking complex dependencies, finding DOM elements, and testing asynchronous logic.

With practice, testing with Jest will become an integral part of your development process, helping you catch bugs early and improve the quality of your React apps.

Step 1: Setting Up Your React Application

Creating a New React App

To begin testing your React app with Jest, first, you need to set up a new React project. Here's how you do it with something called Create React App:

npx create-react-app my-app
cd my-app

This command creates a new project for you, and it's already set up to work with Jest for testing.

Here's what you get with Create React App:

  • Jest - This is what runs your tests.
  • React Testing Library - This helps you test your React components easily.

Installing Jest

Even though Create React App comes with Jest, you still need to add something called the React Testing Library:

npm install --save-dev @testing-library/react @testing-library/jest-dom

Or, if you're using Yarn:

yarn add --dev @testing-library/react @testing-library/jest-dom

By doing this, you can:

  • Use tools from React Testing Library to test your components.
  • Make use of special checks (assertions) from Jest DOM.

Now, you're all set to start creating test files for your React components with Jest.

Step 2: Understanding Jest Basics

Jest is a tool for testing JavaScript code, making it perfect for checking if your React apps are working right. Let's look at some basic things you need to know to start testing your React components with Jest.

describe and it Blocks

Jest uses describe and it blocks to organize tests:

  • describe blocks group tests that are related. You can think of it like a folder that holds all tests for a specific component. For instance:
describe('MyComponent', () => {

  // Tests for MyComponent go here

});
  • it blocks are for individual tests. It's like saying, "It should do this or that." For example:
it('renders correctly', () => {

  // Here's where you write what the test should do

});

So, describe blocks are for grouping tests, and it blocks are for single tests.

expect Matchers

Jest uses expect matchers to check if the test results match what you expect. Some common ones are:

  • toBe() - checks basic values or if two things are the same
  • toEqual() - checks if objects have the same content
  • toBeInTheDocument() - makes sure an element is actually on the page
  • toHaveTextContent() - checks if an element has certain text
  • toHaveLength() - checks how long something is, like an array or string

For instance:

expect(result).toBe(3); 
expect(array).toHaveLength(3);

There are a lot more matchers you can use, so it's a good idea to look at Jest's documentation to learn about them.

React Testing Library

The React Testing Library helps you test React components. Here are some tools it gives you:

  • render() - puts a component on the page
  • screen - helps you find elements
  • userEvent - lets you pretend to do things like clicking

For example:

render(<MyComponent />);

userEvent.click(screen.getByRole('button')); 

expect(screen.getByText(/Clicked/i)).toBeInTheDocument();

So, the React Testing Library makes it easier to check elements, pretend to interact with them, and see if everything is working as expected. With Jest matchers and React Testing Library tools, you've got what you need to test React components thoroughly.

Step 3: Writing Your First Test

Creating the Test File

To check if a React component works correctly with Jest, you need to make a test file. Name it after your component, like ComponentName.test.js, and put it where your component file is.

Start by adding React and the render function from React Testing Library at the top. Also, bring in the component you're testing:

import React from 'react';
import { render } from '@testing-library/react';
import MyComponent from './MyComponent'; 

Structuring the Test Case

Wrap your tests for the component in a describe block. Inside, use an it block for each test you want to run:

describe('MyComponent', () => {

  it('shows up correctly', () => {

    render(<MyComponent />);
  
  });

}); 

This simple test makes sure the component appears without any trouble.

Running and Interpreting

To run your test, type:

npm test

The console will show if your test passed or failed. If everything's good, you'll see something like:

PASS  src/MyComponent.test.js
  ✓ shows up correctly (3 ms)

If there's a problem, the console will give you details to help fix it, like:

● shows up correctly

    TypeError: Cannot read properties of undefined (reading 'foo')

Use this feedback to sort out any issues and think about what other tests you might need.

Step 4: Testing React Components

Simulating User Interactions

Testing how your components react to user actions, like clicks or typing, is crucial. With tools like fireEvent from React Testing Library, we can mimic these user actions in our tests.

For instance, if you want to see what happens when someone clicks a button in your component:

import { render, screen, fireEvent } from '@testing-library/react';

test('increments counter on button click', () => {
  render(<MyCounter />);
  
  const button = screen.getByRole('button');
  
  fireEvent.click(button);
  
  expect(screen.getByText(/1/i)).toBeInTheDocument(); 
});

And for typing into a text box:

fireEvent.change(input, { target: { value: 'Test' }});

expect(input.value).toBe('Test');

fireEvent and userEvent give us ways to simulate all sorts of actions users might take.

Asserting DOM Updates

After we pretend to do things like clicking or typing, we need to check that our page changes the way we expect. With React Testing Library, we can find elements and see if they're showing the right things.

For example, to check if a button click shows some text:

fireEvent.click(button);

expect(screen.getByText('Clicked')).toBeInTheDocument(); 

Or to make sure typing in a box changes its content:

fireEvent.change(input, { target: { value: 'Test' }});

expect(input.value).toBe('Test');

We can check lots of things, like if something is there or not, if it has the right text, or if a list got longer after adding something to it.

The idea is to test our components like real users would use them. We mimic what a user does and then make sure the page reacts correctly.

Step 5: Mocking in Jest

Why Mocking is Used

Mocking is a technique we use in testing React components with Jest that comes with a lot of perks:

  • It lets us test just the component we're interested in: By pretending other parts of the app (like functions or modules our component uses) are something simpler, we can focus on the component itself without worrying about the rest.
  • We don't have to make real API calls: Making actual API calls can slow down tests and make them unreliable. By using mocks, we can pretend to get responses back instead.
  • Makes tests run quicker: Since we're not making real API calls, our tests can run a lot faster.
  • Simplifies setting up tests: Instead of dealing with the complex setup of functions or modules, we can use mocks to make things easier.
  • Lets us test tricky situations: Mocking lets us control the outcomes of functions, making it easier to test how our component handles different scenarios.

Overall, mocking makes our tests simpler, faster, and more focused.

Manual Mocks

To mock something manually, you just create a fake version of it in a __mocks__ folder next to your test.

For instance, if you want to mock utils.js:

src/
  __tests__/  
    Component.test.js
  __mocks__/
    utils.js 
  utils.js

In your mock file, you'd provide fake versions of the functions:

// __mocks__/utils.js

export const getUser = jest.fn(() => ({ 
  id: 1,
  name: 'John' 
}));

Now, when your tests run, they'll use these fake functions instead of the real ones.

Manual mocks are great for controlling how functions behave in your tests. They help you focus on testing the component without distractions from other code.

sbb-itb-bfaad5b

Step 6: Advanced Testing Techniques

Snapshot Testing

Snapshot testing is like taking a photo of your component after it's rendered to check it looks right. If you change something later, you can compare the new "photo" to the old one to make sure nothing unexpected happened.

Here's a simple way to do it:

import { render } from '@testing-library/react';
import Component from './Component';

it('matches snapshot', () => {
  const { asFragment } = render(<Component />);
  expect(asFragment()).toMatchSnapshot();  
});

This code renders your component and checks if it matches the "photo" it took before. If you change your component on purpose, you'll need to take a new "photo":

npm test -- -u

This updates the snapshot to match your latest changes.

Testing Props and State

To check if your component shows the right info from props, just give it those props when you render it:

it('displays user data', () => {
  const user = { 
    name: 'John',
    age: 25
  };
  
  const { getByText } = render(<UserData user={user} />);
  
  expect(getByText(/John/i)).toBeInTheDocument();
  expect(getByText(/25/)).toBeInTheDocument();
});

This makes sure the component shows the user's name and age correctly.

For state, pretend to do something that should change the state, like clicking a button, then see if the component updates the way it should:

it('increments counter on click', () => {
  const { getByText, getByRole } = render(<MyCounter />);
  
  fireEvent.click(getByRole('button'));
  
  expect(getByText(/1/i)).toBeInTheDocument(); 
}); 

This means you test state changes by acting like a user, doing things like clicking, and then checking if things on the page update correctly.

Best Practices

When testing your React components with Jest, it's important to keep things straightforward and easy to manage. Here are some tips to help you out:

Keep Tests Independent

Make sure each test stands on its own and checks for one thing only. This way, tests don't rely on each other.

Do:

it('displays greeting text', () => {

  // Check for greeting text
  
});

it('changes button color on hover', () => {

  // Check button color when hovered
  
}); 

Don't:

it('displays greeting', () => {

  // Renders component
  
});

it('changes button color on hover', () => {
  
  // Depends on previous test rendering component
  
});

This approach makes your tests more trustworthy and avoids them messing with each other.

Use Good Naming Conventions

Name your tests clearly to show what they're checking:

// Good
it('displays user name'); 

// Bad 
it('displays name');

And use describe blocks for the component being tested:

describe('UserProfile', () => {

  // Tests for UserProfile component
  
});

This helps keep everything organized.

Keep Tests Simple

Split up tests into smaller pieces instead of trying to test too much at once:

Do:

it('calls function on button click', () => {

  // Click button
  
});

it('shows updated text after call', () => {

  // Check text element
  
});

Don't:

it('clicks button and checks text update', () => {

  // Click button  
  // Check text element
  
});

Smaller tests are easier to get and fix if something goes wrong.

Use Helper Functions

If you find yourself repeating the same steps in different tests, make a helper function:

function enterText(text) {

  fireEvent.change(input, { target: { value: text }});
  
}

it('updates input on change', () => {

  enterText('Hello');
  
  expect(input.value).toBe('Hello');
  
});

it('shows error on invalid input', () => {

  enterText('');
  
  expect(screen.getByText(/error/i)).toBeInTheDocument();
  
}); 

This way, you avoid repeating yourself in your tests.

Following these simple practices will make your tests better and easier to handle. Keeping your tests clear, well-organized, and focused on small, specific tasks is the way to go. Happy testing!

Common Challenges and Solutions

When you start testing your React apps with Jest, you might run into a few tricky spots. Here's a look at some common problems and how to fix them:

Mocking Complex Dependencies

The Issue: Sometimes, components depend on other parts of your app or need to make API calls. Pretending these parts are something simpler (mocking) can get complicated.

Solutions:

  • Create fake versions of these complex parts yourself.
  • Make reusable mock functions for logic you use often.
  • Consider using tools like MSW to handle API calls in tests.

Finding the Right DOM Elements

The Issue: It can be hard to find elements in your tests, especially if their IDs change every time you render them.

Solutions:

  • Use getByRole and other search methods from React Testing Library.
  • Mark elements with data-testid for easy access.

Testing Asynchronous Logic

The Issue: Dealing with actions that happen over time, like waiting for data, needs special care in tests.

Solutions:

  • Make your test wait for these actions by using promises or async/await.
  • Check out tools like jest-async for help.

Avoiding Fragile Snapshot Tests

The Issue: Small changes, like a space added, can cause snapshot tests to fail.

Solutions:

  • Use tools that ignore minor changes.
  • Snapshot only the most important parts, not the whole component.

Preventing Test Pollution

The Issue: Sometimes, what happens in one test can affect another, leading to confusing results.

Solutions:

  • Use cleanup from React Testing Library to reset after each test.
  • Keep tests separate with Jest's describe.
  • Reset mocks and spies after each test.

Debugging Failing Tests

The Issue: It's tough to fix a test when the error message doesn't help much.

Solutions:

  • Use debug() to take a closer look at what's happening.
  • Turn on detailed error reports in Jest.
  • Keep an eye on how things change during your test.

Getting past these hurdles can make testing with Jest a lot smoother. Remember, keeping your tests simple and focused can help avoid many of these issues.

Conclusion

Testing your React apps with Jest helps you find mistakes and make sure your code is solid. Think of it like double-checking your work. When you test your app properly, you can trust it to work well, which means you can make changes or add features without worrying too much.

Starting with tests can seem tough, but it really helps in the long run. You end up with safer code and can make updates more quickly. This guide showed you the basics, but learning to test well takes time and practice. Try it out on your own projects, look up more info on testing, and don’t worry about making mistakes as you learn.

Here’s a quick summary of what we talked about:

  • Organize your tests with describe and it blocks
  • Use tools like screen and userEvent from React Testing Library
  • Keep your tests simple by pretending complex parts of your app are easier versions
  • Focus on testing one thing at a time
  • Stick to good habits for tests that are easy to read and work with

Testing might not be the most thrilling part of coding, but it’s super important. With Jest and other testing tools, you can catch bugs early and make building your React app smoother. It’s definitely worth the effort.

Additional Resources

Here are some helpful links to learn more about testing React apps with Jest:

Official Documentation

  • Jest docs - This is where you can find everything you need to know about Jest, from the basics to more advanced stuff.
  • React Testing Library - This guide has all you need to know about using React Testing Library to test your components.

Tutorials

Tools

  • React Testing Playground - A place to try out testing React components with interactive examples.
  • MSW - A tool for handling network requests in your tests without having to make real API calls.

These resources can help you get better at testing your React apps with Jest. They offer a deeper dive into Jest and testing techniques, so make sure to check them out!

Related posts

Why not level up your reading with

Stay up-to-date with the latest developer news every time you open a new tab.

Read more