Testing React Apps Built with Vite: Setting up Jest and React Testing Library

Introduction to Testing React Applications with Jest and React Testing Library

Testing our React applications is essential for ensuring its functionality and reliability. With numerous modern testing frameworks available for React applications, selecting the right one depends on our preferences and project requirements. In this tutorial, we will utilize Jest and React Testing Library.

  • Jest is a JavaScript testing framework with a focus on simplicity. It seamlessly integrates with React applications and offers features such as snapshot testing, mocking, and coverage reports.

  • React Testing Library is a lightweight testing library for React applications that promotes writing tests closely resembling user interactions with our application.

Please note that this article does not extensively cover writing tests for React applications. Instead, it focuses on installing all required dependencies and showcasing a very simple test case. The build tool I am using for my React projects is Vite.

Installing All Necessary Dependencies

  1. To set up Jest with React Testing Library in our Vite project, we need to install the necessary dependencies: npm install --save-dev @testing-library/react @testing-library/jest-dom jest

  2. Next, we have to update our package.json file to include a test script that runs Jest. The modified scripts section:

     "scripts": {
       ...,
       "test": "jest"
     },
    
  3. Since Jest doesn't understand JSX out of the box, it needs to be transformed into standard JavaScript. To achieve that, we need to install the following dependency: npm install --save-dev @babel/preset-react

  4. Next, we're going to install @babel/preset-env to transpile ES6 modules to CommonJS: npm install --save-dev @babel/preset-env

  5. Create Babel config file named either .babelrc, or babel.config.json and add the following presets:

    
     {
       "presets": ["@babel/preset-env", "@babel/preset-react"]
     }
    
  6. Additionally, specify the test environment by installing jest-environment-jsdom: npm install --save-dev jest-environment-jsdom

  7. Update your Jest configuration, either in jest.config.js or package.json. The example below is in a package.json file:

     "jest": {
       "testEnvironment": "jest-environment-jsdom",
     }
    

    With this configuration, Jest will use jest-environment-jsdom as the test environment, providing a DOM implementation for running your tests.

  8. Configure Jest to use Babel for transforming files: npm install --save-dev babel-jest and update your Jest configuration in jest.config.js or package.json

     "jest": {
         "transform": {
           "^.+\\\\.[jt]sx?$": "babel-jest",
         }
     }
    

We also need to instruct Jest to ignore CSS files during testing, as they are not JavaScript files and should not be parsed as such. We can achieve this by specifying a custom transformation for CSS files. Install jest-transform-stub transformer: npm install --save-dev jest-transform-stub

Then, update your jest configuration to use jest-transform-stub for CSS files:

//package.json
"jest": {
  "transform": {
    "^.+\\\\.jsx?$": "babel-jest",
    "\\\\.(css|scss)$": "jest-transform-stub"
  }
}

package.json Overview

After installing all the required dependencies, our package.json should now be extended with the following dependencies and Jest setup. Please note that the exact versions might vary depending on when you're reading this article.

{
  ...
  "scripts": {
    ...
    "test": "jest"
  },
  "dependencies": {
    ...
  },
  "devDependencies": {
    "@babel/preset-env": "^7.24.0",
    "@babel/preset-react": "^7.23.3",
    "@testing-library/jest-dom": "^6.4.2",
    "@testing-library/react": "^14.2.1",
    "babel-jest": "^29.7.0",
    "jest": "^29.7.0",
    "jest-environment-jsdom": "^29.7.0",
    "jest-transform-stub": "^2.0.0",
  },
  "jest": {
    "testEnvironment": "jsdom",
    "transform": {
      "^.+\\\\.[jt]sx?$": "babel-jest",
      "\\\\.(css|scss)$": "jest-transform-stub"
    }
  }
}

Folder Structure

To start adding test files into our project, we first need to create a folder called __tests__ in the root directory. While this is my preferred folder structure, yours may differ based on personal preference. Here's an example of what the folder structure could look like:

├── src
│   ├── components
│   │   └── Button.jsx
│   ├── App.jsx
│   └── main.jsx
├── __tests__
│    ├── components
│       └── Button.test.js
├── babel.config.json
├── package.json
└── ...

In this structure:

  • The src directory contains our application source code.

  • Within src, we have a components directory housing our React components.

  • The Button.jsx file represents an example component.

  • The __tests__ directory, created in the root directory, is dedicated to storing our test files.

  • Inside __tests__, we create a components directory to mirror the structure of the src directory.

  • Within __tests__/components, we create test files following a naming convention: <ComponentName>.test.js, such as Button.test.js, which is a test file specifically for the Button.jsx component.

Creating Our First Test File

After creating our test file, we need to make sure React is imported into both the component we're testing and the test file itself. Without this import, JSX syntax won't be recognized, leading to the React is not defined error.

Let's consider an example component called Button.jsx:

import React from 'react';
import './Button.css';

const Button = (props) => {
  return (
    <button className="btn" type="button" onClick={props.generateMemeImg}>
      {props.text}
    </button>
  );
};

export default Button;

Additionally, we need to add import '@testing-library/jest-dom'; to the Button.test.js file.

Here's an example test for Button.jsx. This verifies that the button renders correctly and that the generateMemeImg function is called when the button is clicked:

import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import Button from '../src/components/Button'; //Adjust the path based on your folder structure
import '@testing-library/jest-dom';

test('renders button with correct text', () => {
    //Define a mock function for generateMemeImg
  const mockGenerateMemeImg = jest.fn();

    //Render the Button component with the mock function passed as props
  const { getByText } = render(
    <Button text="Generate Meme" generateMemeImg={mockGenerateMemeImg} />
  );

    //Get the button element by its text content
  const buttonElement = getByText('Generate Meme');

    //Assert that the button is rendered
  expect(buttonElement).toBeInTheDocument();

    //Simulate a click event on the button
  fireEvent.click(buttonElement);

    // Assert that the mock function was called once
  expect(mockGenerateMemeImg).toHaveBeenCalledTimes(1);
});

Conclusion

This tutorial focused on utilizing Jest and React Testing Library, two modern testing frameworks, to streamline the testing process. By following the installation guide and organizing test files effectively, we can create robust test suites to validate the behavior of their React components. Emphasizing simplicity and clarity, this tutorial aimed to equip developers with the necessary tools and knowledge to incorporate effective testing practices into their React projects.