Implementing Jest and RTL for beginners (1/3)
Tags: jest, beginners, react, webdev
Published: 2022-06-21 08:02:11

## Table Of Contents
[1. Introduction](#chapter-1)
[2. Getting Started](#chapter-2)
[3. Examples and Methods](#chapter-3)
[4. Conclusion](#chapter-4)

So, for this week's post, we will be looking at Jest.js and React Testing Library. I just recently started learning how to test my code. So likely for the next few posts, I will be documenting the learning and pointers I gathered along the way. It will be pretty basic testing but hopefully the complexity increases as I learn more about testing.

<a name="chapter-1">Introduction</a>
So just a little introduction to this topic. I decided to create a simple TicTacToe game using React Library with the intention to implement testing into my simple game app to get exposure to a testing framework. 

__What is Jest?__
Jest is a testing framework which was first build for React applications. It allows developers to run tests on JavaScript and TypeScript code and integrates well with React. It offer functions for test suites, test cases, and assertions which we will get into more later in the post.

__What is React Testing Library (RTL)?__
React Testing Library is a JavaScript testing utility built specifically to test React components. It is a DOM testing library that handles DOM elements and how they behave in front of real users instead of dealing with instances of rendered React components. The library comes with a set of testing helpers which we will get into later in this post.

__So what is the difference between both of them? Can they replace one another?__
No they are not a replacement for one another. In fact, we need both to test our component completely.

<a name="chapter-2">Getting Started</a>
Fortunately, if we create our React app using `create-react-app`, Jest and RTL already comes as part of the installation. Once we created our app, there is a file called `app.test.js` which uses Jest and React Testing Library. 

To run the test, open our terminal and run

```Javascript
npm run test // if using npm
```
or
```Javascript
yarn test // if using yarn
```

This will initialize the test. The output for a successful and failed test will be shown at the end of the post.

<a name="chapter-3">Examples and Methods</a>
In this section, we will reference certain lines of code from the TicTacToe app.

For this post, we will use the `Board` component to conduct certain tests. Below is the board component which renders a board with nine squares as shown below:

![TicTacToe Board](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6485l1oeztn9573sz7vz.png) 

And the JSX for this component are as shown:

```Javascript
  return (
    <div className={classes.container} data-testid="board">
      <span data-testid="playerTurn">Player {select} Turn</span>
      <div className={classes.gridContainer}>
        {arr.map((a, i) => (
          <Square
            key={Math.random()}
            index={i}
            onHandleSelect={onHandleSelect}
            moveName={a}
            disable={disable}
          />
        ))}
      </div>
      {winner ? (
        <h2>
          {winner === "Draw"
            ? "Round Draw. Restart Round."
            : `Player ${winner} is the Winner!`}
        </h2>
      ) : (
        ""
      )}
      <button
        onClick={onHandleReset}
        type="button"
        className={classes.buttonReset}
      >
        reset
      </button>
    </div>
  );
}
```
To start off, we would like to test if the board itself is rendered in the DOM. To begin, we will create a `__test__` folder  in the folder which houses the `Board` component and create a test file called `Board.test.tsx`. like this: 

![Folder Structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lmfmi9u90bfk2sl6203t.png)

In `Board.test.tsx`, import `render` and `cleanup` from react test library and also the Board component itself.

```Javascript
import { render, cleanup } from "@testing-library/react";
import Board from "../Board";
```
Before writing test logic, we need to call the `describe` method from Jest. `describe` is used describe our test suite and each test suite can consist of multiple test as shown below

```Javascript
describe(Board, () => {
  test("Board is rendered on screen", () => {
     // our test function comes in here.
  });
  it("Reset button is rendered on screen", () => {
     // ourtest function comes in here.
  });
  // other tests
});
```
The `test` method from Jest takes in two argument (test description, test function). Instead of `test`, the method `it` can be used as well. Both methods exist to enable the user to make a readable English sentence from our test.

Next, we have to call on the `render()` method from RTL and insert the component we want to render (in this case it is the `Board` component). One of the key feature of `render()` is that we can destructure the rendor method and select different ways to queries the DOM. There are quite a few queries to choose from (for example: byRole, byText, byTitle, etc) and they can be found in RTL official document. For now, we will use `getByTestId`. 

```Javascript
const { getByTestId } = render(<Board />);
```

From there, we will use `getByTestId` to search the DOM for the html element with the specified test ID and assign it to a variable. 

```Javascript
const renderBoardElement = getByTestId("board");
```

In this case, the main `div` in the highest component has the the data-testid prop and can be seen in an abstract from the `Board` component JSX

```Javascript
  return (
    <div className={classes.container} data-testid="board"> // data-testid *************
      <span data-testid="playerTurn">Player {select} Turn</span>
      <div className={classes.gridContainer}>
        {arr.map((a, i) => ( .....
```

Then we will use the `expect` method from Jest and insert the variable in and choose a matcher method to decide the requirement of our test. There are many matchers to choose from and they can be found in Jest official documents. In this case, the matcher we choose will be `.toBeInTheDocument()`

```Javascript
expect(renderBoardElement).toBeInTheDocument();
```
Lastly, we will need to use the cleanup method from RTL to clean up the test everytime it finishes executing. The clean up method Unmounts React trees that were mounted with render. The whole testing function for checking  the board will be render in the DOM would look something like this:

```Javascript
import { render, cleanup } from "@testing-library/react";
import Board from "../Board";

afterEach(cleanup);

describe(Board, () => {
  test("Board is rendered on screen", () => {
    const { getByTestId } = render(<Board />);
    const renderBoardElement = getByTestId("board");
    expect(renderBoardElement).toBeInTheDocument();
  });
});
```

If we type `npm run test` in the terminal and the test is successful, we will see this printout:

![Pass Test](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vo2mg20k8m8rmn1opjh7.png)

This means the `div` with test-dataId of `board` was rendered in the DOM. 

To generate a fail test, we will change the test-dataId from `board` to `boar` and this is what a fail test looks like.

![Failed Test](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3eodtovnfltu90axz4ln.png)

<a name="chapter-4">Conclusion</a>
Alright, this is the end of the first part of testing. it is a very basic test to check if the html element are rendered. This is an extremely high level check and there will be many other more in depth to conduct to ensure the test is working correctly. Such as fire-events, number of components rendered, etc. I will document more as I develop my testing skills along the way. If I have any inaccuracies, do tell me as I would love to learn from my mistakes. Apologies for the long intro and for more information on Jest and RTL, refer to the official documentations at:

For Jest: https://jestjs.io/
For React Test Library: https://testing-library.com/docs/react-testing-library/intro/