Writing Your First React Test
Tags: react, testing
Published: 2021-03-17 20:35:32

---
title: Writing Your First React Test
published: true
description: Always wear your seatbelt. This applies while coding as well -- meaning, you should always add tests!
tags: react, testing
cover_image: https://i.imgur.com/Vw4LnDc.jpg
---

Cover image unrelated -- nice to look at though, right? Discovery Park, Seattle, WA. 

This post will assume that the reader has a good understanding of the React basics. It will also involve some coding, which you are welcome to code along with. The repository for the starter code can be found [HERE](https://github.com/halented/testing-tutorial). To view the finished product with tests, use the same repository, but switch to the `with-tests` branch.

Before we make any changes, take a moment to poke around the code. It's fairly simple -- just two components & a little bit of state to swap the image between a dog and not-a-dog. 

Since this repository was created with [create-react-app](https://create-react-app.dev/docs/getting-started/), there are some testing tools which are already in the code that we don't have to build or add ourselves.

![Screenshot of file tree](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j66ucvyxsq34w2nymv6x.png)

Firstly, there is a file called `setupTests.js`, which contains the basic import for the [Jest](https://jestjs.io/) test runner. This file can be edited for fancier, more complicated tests in the future, but we won't need to do much with it right now. 
Secondly, you'll see a file called `App.test.js`. Now, I know this is crazy, but that's where we'll write the tests for the App component. The file extension matters, as when we input the command to run the tests (either `npm test` or `yarn test` depending on your package manager), anything with a `.test.js` file extension will get read & executed.
There is also some code which already lives inside of the `App.test.js` file, which we can use to make some basic assumptions about how tests look. We might as well check it out.

```javascript
import { render, screen } from '@testing-library/react'
import App from './App'

test('renders learn react link', () => {
  render(<App />)
  const linkElement = screen.getByText(/learn react/i)
  expect(linkElement).toBeInTheDocument()

})
```
Let's break down what we are looking at before changing it. 

I think the most confusing and, potentially most important part to recognize with this small snippet is that there are two different testing packages being used. The first package we are using is the [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/). It's the more obvious package, because the import is right at the top, like normal. We are importing `render`, which will allow us to access an instance of any component, and `screen`, which will allow us to make queries off the DOM similarly to vanilla JavaScript, after said component is rendered.

The second package is Jest, which is a "test runner". Jest ships out of the box when you make a project using `create-react-app`, but it **is** a third party library. You don't have to use Jest if you discover that an alternate test runner offers more applicable functionality, but it's the most widely used and a great place to start. 

## What's a test runner?

Test runners are not all the same, but their overall purpose is to read the test files and print some output based on whether or not the *expectations*, otherwise known as *assertions*, are met for each test. 

Jest itself is a **runner** (meaning you can read tests with it), **assertion library** (meaning you can write expectations with it), and a **mocker** (meaning you can create a fake replica of outside functionality to mess around with in the testing space). Now let's look at another picture of landscape really quick.

![Discovery Park, WA](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/veef036yo868cbl9xjsb.jpg)
> *Discovery Park again!! What a nice damn place to be.*

Okay, back to the code snippet: 

```javascript
import { render, screen } from '@testing-library/react'
import App from './App'

test('renders learn react link', () => {
  render(<App />)
  const linkElement = screen.getByText(/learn react/i)
  expect(linkElement).toBeInTheDocument()

})
```

We can now determine which parts are Jest: `test` and `expect` (assertions) 

and which parts are the React Testing Library: `render` and `screen`.

**One last thing you may be wondering...** why don't we have to import `test` and `expect` from Jest?

**And that the answer to that would be...** that Jest sneakily adds its methods into the global scope of your `.test.js` files. If you pop a `console.log(global)` into one of your test files and then run it, you can physically see every single method available to you in that space. Be warned, that is a huge console.log you are about to see. But `expect` and `test` are in there. 

At this point, go ahead and run `yarn test` if you haven't already. Our app doesn't have the learn react link, so of course the original test won't pass. 

## Determining What to Test

Now that we've got a taste of what tools `create-react-app` grants us, we can begin to think about what tests to write. There are three main types of tests: 

1. **Unit** - Tests one single piece of functionailty, like a method or a piece of state, in a vaccuum. 
2. **Integrations** - Tests a group of methods or components together, to make sure they work properly in combination. 
3. **End-to-End** - Begins where the site user would begin and tests the entirety of the available app.

>*⚠ Which type of test do you think is currently being rendered in `App.test.js`?*

I've read differing opinions on which style you should *begin* your testing with, but the one that makes the most sense to me is to write integrations tests. Overall, the prevailing philosophy is to test your app the way that it might be used by a user. So let's take that and look at what our app does. Go ahead and spin up the app from a second terminal using `yarn start`. 

![Screenshot of the pre-built app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kem6g4eve1vqk7k9k03i.png)

Wow, it's a dog. 

While running the app, you should be able to click on the image to flip it back and forth between a dog, and not-a-dog. So there you have it: seems like we should write a test to make sure that clicking on the image switches it back & forth. After all, that's what our users are doing. 

## Writing the Test

We'll start by rendering the app. That part we don't have to change. 

```javascript
import { render } from '@testing-library/react'
import App from './App'

test('Switches image upon clicking', () => {
  render(<App />)

})
```

Next, we need to grab the image from the DOM, so we can simulate a click. The `screen` import from React Testing Library is pre-bound to the `document.body`, so conceptually, you can query `screen` like you would the `document.body` in vanilla JS. The methods are a little different, but the idea is the same. If you are using VS Code, there is a quick way to check out all the methods available on the `screen` object. Head over to your `App.test.js` file and type `screen.`, and you should see some options pop up in a drop down that you can scroll through with the arrow keys. 

You may notice that "getByTagName" is not available -- so how do we grab an image? Well, images have alt texts.

```javascript
import { render, screen } from '@testing-library/react'
import App from './App'

test('Switches image upon clicking', () => {
  render(<App />)
  const img = screen.getByAltText(/My dog, Beany/i)
  console.log(img)

})
```

Since this is our first time poking around with tests, I recommend `console.log`ging as much as you need to in order to prove that your ideas are working. If you run the above code, you should see a log in the test server that looks like a React Node. 

Now we've rendered the App and we have ahold of the image, so it's time to simulate a click. 

```javascript
import { render, screen, fireEvent } from '@testing-library/react'
import App from './App'

test('Switches image upon clicking', () => {
  render(<App />)
  const img = screen.getByAltText(/My dog, Beany/i)
  fireEvent.click(img)

})
```

We can import the `fireEvent` object from the React Testing Library and use its `click` method. By passing it the image, we would expect that the image on the screen is now changed. So for the final part of the test, we're going to write out that expectation. 

```javascript
import { render, screen, fireEvent } from '@testing-library/react'
import App from './App'

test('Switches image upon clicking', () => {
  render(<App />)
  const dogImg = screen.getByAltText(/My dog, Beany/i)
  fireEvent.click(dogImg)

  const notDogImg = screen.getByAltText(/Rainbow frowny face/i)
  expect(notDogImg).toBeInTheDocument()
})
```

And there you have it: you have written your first test in React. Hopefully you have also gained some tools for understanding the testing libraries and the ability to write more!


Might as well sign off with a nice picture of some landscape. 

![Double Bluff Beach on Whidbey Island](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6s0snup0znniqn8gk0wv.jpg)

Another one of beautiful, sunny Discov- just kidding! This one is from Whidbey Island. 

Happy coding!