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
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.
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.
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.
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’.
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.
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.
What’s Next and Further Reading
Next.Js provides great opportunities to expand and empower a React application. Please read further these articles on the series:
Further reading: