Setup jest from scratch in a vanilla js project.

manuartero

Manuel Artero Anguita šŸŸØ

Posted on May 13, 2022

Setup jest from scratch in a vanilla js project.

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


Enter fullscreen mode Exit fullscreen mode


  ...
  "html-webpack-plugin": "^5.5.0",
+ "jest": "^28.0.3",
  "postcss-loader": "^6.2.1",
  ...


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

āž”ļø 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/


Enter fullscreen mode Exit fullscreen mode

This implies a subtle tuning at jest.config.js



...
- roots: ['src']
+ roots: ['../src'],
...


Enter fullscreen mode Exit fullscreen mode

Plus considering the new path at package.json



...
- "test": "jest"
+ "test": "jest --config=config/jest.config.js"
...


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode


  ...
+ "@babel/core": "^7.17.9",
+ "@babel/preset-env": "^7.16.11",
+ "babel-jest": "^28.0.3",
  ...


Enter fullscreen mode Exit fullscreen mode

Plus these lines at jest.config.js



+ transform: {
+   '\\.[jt]sx?$': 'babel-jest',
+ },


Enter fullscreen mode Exit fullscreen mode

And (if you didn't have one already) a brand new config/babel.config.json



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


Enter fullscreen mode Exit fullscreen mode

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,
        },
    });
});


Enter fullscreen mode Exit fullscreen mode

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:

  1. At config/jest.config.js


+setupFiles: ['./jest-env-vars.js']


Enter fullscreen mode Exit fullscreen mode
  1. config/jest-env-vars.js


process.env.API_URL = 'https://fake-url.api.test';
process.env.API_KEY = '==API KEY TEST==';


Enter fullscreen mode Exit fullscreen mode

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"
+            ]
        }
    }
}


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode
  1. At config/jest.config.js


+ setupFilesAfterEnv: ['./setup-tests.js'],


Enter fullscreen mode Exit fullscreen mode
  1. config/setup-tests.js


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


Enter fullscreen mode Exit fullscreen mode

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 šŸ’š.

šŸ’– šŸ’Ŗ šŸ™… šŸš©
manuartero
Manuel Artero Anguita šŸŸØ

Posted on May 13, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related