Configuring Jest for Next.JS (React) and Babel from scratch

Construct your Jest, Babel and package.json configuration files for a working Next.JS environment

Pablo A. Del Valle H.
Level Up Coding

--

Configuring Jest for Next.JS and Babel from scratch
Photo by Fleur on Unsplash
Jest, library for testing Javascript.
Jest, library for testing Javascript.

Setting up a proper Front-End project today no doubt will include having a good framework to test your code.

There are many good software modules nowadays to run your unit tests. One of the most popular is Jest.

There are many ways to set up your environment. In here I’ll show you one way that works for me and becomes very flexible for any small, medium and even large projects.

Next.JS, a web application framework.
Next.JS, a web application framework.

For this, we will be using the Next.JS web application framework. Under the hood, it will install many of the most popular and powerful tools and libraries to date, such as React, Webpack, stylesheet preprocessors, and more.

Step 1: create a new project. In our case, let’s name it ‘sample-project’.

mkdir sample-project
cd sample-project
npm init

At this point, you’ll see NPM’s utility to create your package.json. In our sample, we will keep all the default values.

Step 2: Install the required libraries. First we will install our regular dependencies: Next, React and React DOM.

npm i --save next react react-dom

Next, let’s install the development dependencies: @babel/preset-env, @babel/preset-react, babel-jest, enzyme, enzyme-adapter-react-16, jest.

npm i --save-dev @babel/preset-env @babel/preset-react babel-jest enzyme enzyme-adapter-react-16 jest

Step 3: Create the configuration files.

Let’s begin with ‘package.json’. You’ll add the following nodes under “script”: test, test:coverage, dev.

Your ‘package.json’ will look like this:

{
"name": "sample-project",
"version": "1.0.0",
"description": "Your project description",
"scripts": {
"dev": "next dev",
"test": "jest",
"test:coverage": "jest --coverage"
},
"author": "Your name",
"license": "ISC",
"dependencies": {
"next": "^9.3.6",
"react": "^16.13.1",
"react-dom": "^16.13.1"
},
"devDependencies": {
"@babel/preset-env": "^7.9.6",
"@babel/preset-react": "^7.9.4",
"babel-jest": "^26.0.1",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.2",
"jest": "^26.0.1"
}
}

Next, we’ll work with the Jest configuration file. Create a ‘jest.config.js’ file at the root of your project. The file you are going to end up with will look like this:

module.exports = {
collectCoverageFrom: [
'**/*.{js,jsx}',
'!**/node_modules/**',
'!**/tests/**',
'!**/coverage/**',
'!jest.config.js',
],
coverageThreshold: {
global: {
branches: 100,
functions: 100,
lines: 100,
statements: 100,
},
},
moduleNameMapper: {
'\\.(css|less)$': '<rootDir>/__mocks__/styleMock.js',
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/__mocks__/fileMock.js',
},
setupFiles: [
'<rootDir>/tests/setup.js',
],
setupFilesAfterEnv: [
'<rootDir>/tests/setupAfterEnv.js',
],
testMatch: [
'**/?(*.)+(spec|test).[jt]s?(x)',
],
testPathIgnorePatterns: [
'/.next/',
'/node_modules/',
'/tests/',
'/coverage/'
],
transform: {
'^.+\\.jsx?$': 'babel-jest',
},
};

This file references two more configuration files. Create both files in the ‘/tests/’ directory. The first one is ‘/tests/setup.js’ and the second one ‘/tests/setupAfterEnv.js’.

This is how your ‘setup.js’ must look like. Typically in it, you’ll have configuration or setup code for your tests. This code will run once before each test and before the testing framework gets executed.

process.env.NODE_ENV = 'test';

Next, ‘setupAfterEnv.js’, This code will run also before each test but after the testing framework gets executed:

const Adapter = require('enzyme-adapter-react-16');

require('enzyme').configure({ adapter: new Adapter() });

Lastly, let’s create the Babel configuration file. For this you’ll create a ‘babel.config.js’ file at the root of the project.

{
"env": {
"test": {
"presets": [
"@babel/preset-env",
"@babel/react",
"next/babel"
]
},
"development": {
"presets": [
"next/babel"
]
}
}
}

Step 4: create a simple test. Following a ‘test-first development’ paradigm, let’s create a test first. At the root of the project create a ‘/components/’ directory. In it create a ‘title.spec.js’ file. This simple test file will look like this:

import { mount } from 'enzyme';

import Title from './title';

/** @test {Title Component} */
describe('Title Component', () => {
it('should render without crashing', () => {
const wrapper = mount(<Title label="test" />);

expect(wrapper.find('h1')).toHaveLength(1);
});
});

This test will instantiate a ‘Title’ component which receives a ‘label’ prop. The assertion made is that this component will render an <h1> tag.

Step 5: create a simple component. Following up our “blueprint” in the previous step, we can create our simple component. In the same ‘/components/’ directory we can create the file ‘title.js’:

const Title = ({ label }) => (
<h1>{label}</h1>
);

export default Title;

Step 6: run your tests and verify your coverage. At this point, you are all set and all you need to do is execute your tests. We can do this by executing the ‘test’ script from our ‘package.json’ file.

npm run test

If all goes well, you should see a message that informs you that all tests (in this case only one) passed.

Successful test executed.

One of the most powerful features of Jest is that it can also show detailed statistics of how your tests are covering all your code. For this we can run the script ‘test:coverage’:

npm run test:coverage

This will generate two things. The first one is that you’ll see a summary of all your test coverage in percentages, from statements, branches, functions, and lines.

Coverage report after executing ‘npm run test:coverage’.

But also you’ll notice a ‘/coverage/’ directory in the root of your project which will show you a detailed analysis of your tests. You can see this in your browser by opening the file ‘/coverage/lcov-report/index.html’.

Coverage report.

Once you have these simple basics covered you can scale your project up fairly easy. However, remember that unit tests will not guarantee that your code is completely error free. Unit tests will automate specific cases and tasks that will help isolate when the integrated software runs into glitch.

Likewise, unit tests can provide a pseudo documentation for your project. Once you go back and check the tests of a component that you created ages ago, the tests will give you a sort of “x-ray” to what you, or your coworker, intended when it was first coded.

In that same vein, unit tests make it harder to introduce errors when refactoring existing code that might alter the current test suites of your component.

In case you are curious and wanted to see your ‘Title’ component in a Next.JS page, just follow these final steps:

  • Create a ‘/page/’ directory and an ‘index.js’ file inside. This file will look like this:
import Title from '../components/title';

const Home = () => (
<Title label="this is a test" />
);

export default Home;
  • Finally, to pull up the server that will render the page that holds the ‘Title’ component, run this script:
npm run dev

You can navigate to http://localhost:3000 and see your rendered page.

Your final rendered page.

Of course, remember that if you run the tests now, you’ll need to cover this ‘index.js’ file within an ‘index.spec.js’ testing script.

Thanks for reading!

Find me on LinkedIn, Medium, GitHub.

--

--