From time to time I see myself setting up a web project from scratch. Something super-easy if you use create-react-app
(if you're using React)... but not that smooth in vanilla.
โก๏ธ This occasion we needed at work a vanilla js project.
A co-worker was setting up webpack and asked me to enable jest.
And I was like, "sure this should take 10 mins at most".
It took longer.
1. Install jest
First step is obv.
$ yarn add -D jest
...
"html-webpack-plugin": "^5.5.0",
+ "jest": "^28.0.3",
"postcss-loader": "^6.2.1",
...
2. Base Config
Next, call the jest CLI
tool which will create the base config:
$ยป jest --init
The following questions will help Jest to create a suitable configuration for your project
โ Would you like to use Jest when running "test" script in "package.json"? โฆ yes
โ Would you like to use Typescript for the configuration file? โฆ no
โ Choose the test environment that will be used for testing โบ jsdom (browser-like)
โ Do you want Jest to add coverage reports? โฆ no
โ Which provider should be used to instrument code for coverage? โบ babel
โ Automatically clear mock calls, instances and results before every test? โฆ no
โก๏ธ Note: Here we've taken one relevant decision. test environment is
jsdom
since we're building a web app, we want a browser-like environment.
[3]. Optional Step
We try to reduce dot-files-pollution at root folder. Basically, we gather every tool-related config file and move them to config/
.
$ยป mv jest.config.js config/
This implies a subtle tuning at jest.config.js
...
- roots: ['src']
+ roots: ['../src'],
...
Plus considering the new path at package.json
...
- "test": "jest"
+ "test": "jest --config=config/jest.config.js"
...
4. Configure Jest
Jest runs over node. From the docs:
Jest runs the code of your project as JavaScript, hence a transformer is needed if you use some syntax not supported by Node out of the box.
Since we're playing with browser-things, we need babel-jest
.
$ยป yarn add -D babel-jest @babel/preset-env @babel/core
...
+ "@babel/core": "^7.17.9",
+ "@babel/preset-env": "^7.16.11",
+ "babel-jest": "^28.0.3",
...
Plus these lines at jest.config.js
+ transform: {
+ '\\.[jt]sx?$': 'babel-jest',
+ },
And (if you didn't have one already) a brand new config/babel.config.json
{
"env": {
"test": {
"presets": [
"@babel/preset-env"
],
}
}
}
5. Try the thing with a real test
One of the things I hate the most from tutorials is that they use fake-hello-world examples.
Our real world test is:
import axios from 'axios';
import api from './api';
jest.mock('axios');
afterEach(() => {
jest.clearAllMocks();
});
test('getLayoutData() [200]', async () => {
axios.get.mockResolvedValue({ status: 200, data: { layout: 'hello world' } });
const id = 42
const layoutData = await api.getLayoutData(id, { someQueryParam: true });
expect(layoutData).toEqual({ layout: 'hello world' });
expect(axios.get).toHaveBeenCalledTimes(1);
expect(axios.get).toHaveBeenCalledWith('https://fake-url.api.test/v1/layouts/42', {
headers: {
'x-api-key': '==API KEY TEST==',
},
params: {
someQueryParam: true,
},
});
});
I bet you have one of those at your real world problems
6. ENV vars
Our code relies on two env vars; these two values: 'https://fake-url.api.test'
and '==API KEY TEST=='
.
Let's add those:
- At
config/jest.config.js
+setupFiles: ['./jest-env-vars.js']
-
config/jest-env-vars.js
process.env.API_URL = 'https://fake-url.api.test';
process.env.API_KEY = '==API KEY TEST==';
AND... It fails ๐ค
7. Enable async
await
Straight to the point what it's happening is that we need yet another babel plugin: @babel/plugin-transform-runtime
Enable the plugin at babel.config.js
{
"env": {
"test": {
"presets": [
"@babel/preset-env"
],
+ "plugins": [
+ "@babel/plugin-transform-runtime"
+ ]
}
}
}
8. Final touches ๐
At some point we'll rendering some component, and testing those you want the handy methods toBeInTheDocument()
, toBeVisible()
from Testing Library
$ยป yarn add -D @testing-library/jest-dom
- At
config/jest.config.js
+ setupFilesAfterEnv: ['./setup-tests.js'],
-
config/setup-tests.js
import '@testing-library/jest-dom';
Summary
With just 7 dev-dependencies,
@babel/core
@babel/preset-env
@babel/plugin-transform-runtime
@testing-library/jest-dom
babel-jest
jest
jest-environment-jsdom
And just 4 config files,
- babel.config.json
- jest-env-vars.js
- jest.config.js
- setup-tests.js
we got $ยป yarn test
working ๐
--
Cover image People illustrations by Storyset
Thanks for reading ๐.