Javascript Quality Control with Jest 🤹 and ESLint ✨

Giovanni Puntil
ASOS Tech Blog
Published in
5 min readJun 28, 2018

Working on a project with multiple people can be fun, but javascript is a very flexible language. As everyone has their own way of writing code, it’s not always easy to maintain high code quality standards.

With the help of Jest, ESLint and git-hooks we are able to automate some tasks to guard our code and make sure that our app never breaks again.

https://unsplash.com/@rawpixel

1 — Getting started with Jest 🤹

Before we start juggling let’s see why Jest is good for the task:

  • It works out of the box
  • Automatically finds tests
  • Automatically mocks function dependencies
  • It’s blazing fast 🔥

To get started we need to install Jest as one of our dev dependencies using npm:

npm install jest --save-dev

or using yarn

yarn add jest --dev

Jest works out of the box so place the tests in a __tests__ folder, or name the test files with .spec.js or .test.js extension.

Let’s add the test command in our package.json

// package.json{
"scripts": {
"test": "jest"
}
}

Now we can use npm test or yarn test from the terminal to run our unit tests.

How to watch the unit tests

When in development mode, we are likely to watch the tests running. This means we don’t need to rerun the process every time we make changes and our test command will restart automatically.

We easily do that by executing Jest with the --watch flag, our package.json should look like this now:

// package.json{
"scripts": {
"test": "jest",
"test:watch": "jest --watch"
}
}

Configuring Jest to show your code coverage

Add the --coverage flag to Jest for the test command

// package.json{
"scripts": {
"test": "jest --coverage",
"test:watch": "jest --watch"
}
}

We want our command to fail in case we forget to test any code, to do so we will define every threshold to be 100% for: statements, branches, functions, lines.

// package.json{
"jest": {
"collectCoverageFrom": [
"*.js"
],
"coveragePathIgnorePatterns": [
"/node_modules/"
],
"coverageThreshold": {
"global": {
"statements": 100,
"branches": 100,
"functions": 100,
"lines": 100
}
}
}
}

Now when you run npm test it will output the coverage results in the terminal (see below) and also create a folder called coverage where we will find a full report.

Sample output of jest --coverage

Now my favourite part, if you open this file:

open coverage/lcov-report/index.html

You can interactively navigate through your repository and clearly see in your code any uncovered area.

I know, right?

NB. Update .gitignore to exclude the coverage output folder.

// .gitignorenode_modules
coverage

2 — Installing ESLint ✨

Linting code should be part of every developer daily workflow. Some of the benefits of linting your code include:

  • Improved readability
  • Finding syntax errors before execution
  • Disallow unused and undeclared variables
  • Solves the tab vs. spaces debate 😉

ESLint is the best tool of choice. It’s easy to configure and can be extended using plugins, so let’s install it locally using npm:

npm install eslint --save-dev

or using yarn

yarn add eslint --dev

How to configure ESLint

Cool, let’s create a basic configuration through a file called .eslintrc, run:

touch .eslintrc

and add these lines:

// .eslintrc{
"env": {
"browser": true,
"es6": true,
"jest": true,
"node": true
},
"extends": [
"eslint:recommended"
]
}

No rules are enabled by default, therefore adding the "eslint:recommended" property enables rules to report common problems. If you want to know what’s included, check the official list of available rules.

You are likely to write es6 nowadays, maybe some node code too so, we configured "env" to not validate code that might be specific to the browser, es6, jest or node.

How to exclude files from linting

We also don’t want to lint any file produced with the coverage report and we don’t want to validate anything inside node_modules, so to exclude these folders we need to create a new file called .eslintignore where we can add any PATH that we want to ignore:

// .eslintignorenode_modules
coverage

Now let’s add the lint command in our package.json

// package.json{
"scripts": {
"lint": "eslint .",
"test": "jest --coverage",
"test:watch": "jest --watch"
}
}

We can now run npm run lint or yarn lint and validate our code with ease:

Sample output of eslint

PRO TIP — What about running ESLint fix command on every file save?

3 — How to set up a git pre-hook ⬆️

Good software development involves running the tests frequently and making sure the code high quality standards are met. Adding a git-pre-push hook can help you to automate these tasks and avoid pushing some nasty code into your repo.

To easily do that we will be using husky 🐶 — a git-hook made easy library.

Let’s install husky using npm:

npm install husky --save-dev

or using yarn:

yarn add husky --dev

Then we simply need to write our prepush hook in the package.json, husky will automatically know that’s the command to run on git push:

// package.json{
"scripts": {
"lint": "eslint .",
"prepush": "npm run lint && npm test",
"test": "jest --coverage",
"test:watch": "jest --watch"
}
}

There is also a precommit option available but we’d rather be free to commit and avoid slowing down our development process.

Now the next time we try to push our code, husky will run the prepush command and in our case we will be running lint to validate our code standards and test to run the unit tests and check the coverage.

If either of these fails, the code won’t be pushed to the remote and we will be forced to review our changes.

We did it folks,

Happy safe coding! ⛑

Who am I? / What do I do?

Hello, my name is Giovanni and I’m a Web Engineer at @ ASOS, let me know if you have any questions, comments or feedback.

You can also find me on Twitter @giovannipuntil

--

--