DEV Community

Chidera Ani
Chidera Ani

Posted on

How to Write a Simple Test for Your Next.js App

A guide to writing a simple test for a Next.js app.

First things first

It’s important for software developers to write tests for their software, especially in production to correctly determine whether or not it works effectively and as intended. We don’t want to assume it works only for it to fail later.

Well, it might “work” but you still need to write tests :)

In this tutorial, I’ll be taking you through writing a simple set of tests for a form in your Next.js application using the Jest and React Testing Library. Let’s take a brief look at these tools mentioned above and set our project up.

Next.js

Next.js is an open-source JavaScript framework built by Vercel which provides React-based web applications functionalities. It enables functionalities such as server-side rendering, serverless functions, static applications, etc.

We’ll set up our project by creating a new Next.js app.

Open your terminal and navigate to where you’d keep repos and type the command below.

$ npx create next-app@latest
Enter fullscreen mode Exit fullscreen mode

This will take you through some installation prompts after which it’ll create a basic Next.js app in our folder. If you’d prefer a TypeScript setup add a TypeScript flag as displayed below:

npx create-next-app@latest --typescript
Enter fullscreen mode Exit fullscreen mode

Now that we’ve set up our Next.js app let’s add the testing tools to our app.

Jest

Jest is a Javascript testing framework built by Christoph Nakazawa and currently being maintained by Facebook. One of Jest’s main advantages is simplicity. It’s relatively easy to set up especially for first-time users.

Let’s install our Jest dependencies using npm:

$ npm install -D jest babel-jest
Enter fullscreen mode Exit fullscreen mode

This will install Jest and also Babel Jest which ensure Jest works properly with Next.js.

Next up we’ll create a .babelrc file and add the configuration displayed below. This will help with configuring Babel Jest we already installed.

{  
 "presets": ["next/babel"] 
}
Enter fullscreen mode Exit fullscreen mode

This ensures Jest works in our app as expected.

While Jest enables us easily test javascript apps and code it cannot directly test our Next.js app because it does not have the functionality to render React-based components. We’ll therefore need a tool that can work with Jest to render our Next.js app and then run tests on it.

That’s where React Testing Library comes in.

React Testing Library

React Testing Library is an open-source tool that helps test your React.js app by rendering it and exposing the DOM to be queried. This helps you test your React.js app in its intention to be used rather than just the implementation details.

Let’s install the dependencies to our app.

$ npm install -D @testing-library/jest-dom @testing-library/react
Enter fullscreen mode Exit fullscreen mode

This will install the React Testing Library and a @testing-library/jest-dom package that’ll work with Jest in testing our app.

Before we start writing our tests let’s make some changes to the package.json file in our project directory.

The first change is in the scripts field which tells npm how to run tests on our app.

“test”: “jest — watch”
Enter fullscreen mode Exit fullscreen mode

This tells npm to run jest in watch mode (monitor our changes and run tests accordingly) when we run the npm test a command. Our scripts field should now look as displayed below.

“scripts”: {
 “dev”: “next dev”,
 “build”: “next build”,
 “start”: “next start”,
 “test”: “jest — watch”
},
Enter fullscreen mode Exit fullscreen mode

Secondly, we’ll add a new field to our package.json called jest .

"jest": {
 "testEnvironment": "jsdom"
}
Enter fullscreen mode Exit fullscreen mode

This tells Node to use jsdom as our test environment. The default Node testEnvironment won’t enable us to test using a browser environment.

Having set up these tools we can now proceed to code and write our tests.

We’ll start by creating a basic sign-up form and then we’ll write tests for it.

Sign up form

We’ll navigate to our index.js file, delete all its content, and import useState.

import { useState } from 'react';
Enter fullscreen mode Exit fullscreen mode

Next up, we create a RegisterPage component and in it, we’ll create a basic form which we’ll be testing.



In this RegisterPage component we declare an isLoading state value and set it to false. This value will indicate whether our being submitted (isLoading) or not.

We then proceed to create a registerUser function which we’ll use to simulate a form submission, it’ll prevent the default form submission, set isLoading to true and set it back to false after 5 seconds or 5000 milliseconds.

Next up we create formInputs, an array of objects, containing form inputs which we’ll render in our return block.

Moving on, in our component, we’ll create a form, map through our formInputs array, and add a button that calls registerUser when it’s clicked. We can now export our components.

Styles

Let’s add some basic styling to our styles/globals.css. If you do not have the file create one and import it to your _app.js file.


We’ll now save these files and run our Next app using npm run dev . When we open our browsers to http://localhost:3000 we should see our app now up and running.

Now it’s time to write tests for the form in our app.

Testing the app

Let’s start by creating a tests folder, in it, we’ll create a subfolder called pages . This is where we’ll be keeping test files for our pages (Create your first test file and name it index.test.js).

First, we’ll make some imports to our test file.

import '@testing-library/jest-dom';

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

We import @testing-library/jest-dom which was earlier installed, we also import render, screen and fireEvent from @testing-library/react more on their usage in this tutorial.

Next up we import the Index file we’ll be testing.

import Index from '../../pages/index';
Enter fullscreen mode Exit fullscreen mode

Before we write our tests let us create an array formInputValues that will contain mock data we’ll use in testing our form.



Now, the tests.

We’ll start by describing what our tests are for. We’ll start by creating a describe block of code. Describe is a Jest method used to group related testing blocks together. It takes two arguments: a string for describing the test suite and a callback function for wrapping the test or tests you’ll be writing.

describe(‘Simple working form’, () => {

});
Enter fullscreen mode Exit fullscreen mode

Next up we’ll be writing our test cases in it blocks. it is a Jest method where the actual test functionalities are written. Just like a describe block, it takes 2 arguments: It takes two arguments: a string for describing the test suite and a callback function for wrapping the test functionality. An alternative method to it is test. Let’s start by writing one that tests if all our form inputs were correctly rendered. We’ll do this in our describe block.



In our it block we’ll pass our Index component to a render method. render is a @testing-library/react method that simulates the render of the React component passed as an argument.

We then proceed to loop through our formInputValues using forEach . For each value, we call screen.getByLabelText on value.label . screen is a @testing-library/react object that exposes methods used to query our component previously rendered, one of which is getByLabelText . getByLabelText is used to retrieve one element with the label passed as an argument.

We pass the value returned from screen.getByLabelText as an argument to expect . expect is a Jest method that allows us access to matchers that help us test for certain conditions. An example of a matcher which we use is toBeInTheDocument , calling it on our expect function checks if our argument passed to expect is present in the component we rendered, i.e in the document.

In essence, we expect elements with labels in our formInputValuesarray to exist in our component.

Let’s add two more tests to complete our test cases. One that’ll check if our button is present in the document and another that’ll check if our button loads after it’s clicked.


In our 2nd it block, we render Index, retrieve our button by calling the getByRole method from the screen object and initialize submitButton with the value. getByRole takes several arguments but for this tutorial, we only pass the name of the role we are querying for and an object containing the name of the button (The button’s text). We use two matchers to test for our button. toBeInTheDocument and not.toBeDisabled check if our button is present and not disabled.

Note: Using not before any matcher tests for the reverse of the matcher.

In our 3rd it block, we render Index and retrieve our submitButton . We loop through our inputFormValues array, get the respective inputs, and use fireEvent.change to simulate filling each input with values from our array.

fireEvent is an object from @testing-library/react with methods used to simulate real dom events. We used change to change the form values and then we use click to simulate a click on our button.

At last, we check if the value of our button has now been changed to Loading… after the click. We’re able to do that with another query method, findByRole . It is similar to getByRole but it returns a promise that’s resolved after a while.

Note: If you expect that your fireEvent changes won’t reflect immediately use findBy, rather than getBy.

Our index.test.js should now look like this:


run npm test a to see your test results, you should see something like this
PASS  tests/pages/index.test.js (14.833 s)
Simple working form
√ Should render all form inputs (208 ms)
√ Should render submit button (458 ms)
√ Should submit when inputs are filled and submit button clicked (303 ms)

Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 30.426 s
Ran all test suites matching /a/i.

Enter fullscreen mode Exit fullscreen mode




Conclusion

Congratulations, we’ve successfully tested our Next.js app. Feel free to include more test cases/increase the scope of the tests. The full project is available here on my GitHub.

For more details on the tools used in this tutorial check out the Next.js, Jest, and React Testing Library docs.

I’ll appreciate feedback on this tutorial :), Goodluck coding!

Discussion (0)