Oskar
Oskar
Aug 21 · 4 min read
Photo by William Iven on Unsplash

A few months ago, I met the one and only Robert “Uncle Bob” Martin (“Clean Code,” “The Clean Coder,” “Clean Architecture,” etc ). One of many questions people had for him was, “What parts on my application need to be covered with unit tests?” His response was, “Well, only the ones you want to work.”

Great response, right?

The more I write code, the more I believe that the 100% (or close to it) line-coverage threshold is not crazy but mandatory. One of the best things about good coverage is coverage reports that are green across all files.

Seeing all green makes people happy, and they tend to keep it green (i.e., adding new tests when they add new code). No one wants to be that guy that made a file red after it was green for a long time.

Robert Martin and the author

So it’s really important to have code-coverage reports and thresholds from the start. In this article, we configure Istanbul on the React application, using Jest as the test runner.


Let’s Start

Let’s start with the React app. We will use Facebook’s Create React App template.

Create React App requires no configuration and creates a very simple React application with a single command:

npx create-react-app my-app-name

Now you have the React application. What’s even better: You have one Jest test in src/App.test.js.

That’s all you need for trying out Istanbul. If you want more data, you can add few more files and write tests for them, or you can use your existing React projects.


Setting up Istanbul

The good news is that Istanbul is built into Jest. That means configuration is handled directly by Jest.

The catch here is that Istanbul is not running by default when you create your app with the Create React App template.

There are two ways of running Istanbul alongside Jest when test scripts are executed. Both are really simple.

The first is running your tests with a --coverage flag. Let’s add a new npm script called test:coverage that will use Istanbul to generate coverage report after running tests:

//package.json
{
...
"scripts": {
...
// test run without coverage report
"test": "set CI=true && react-scripts test",

// run tests in watch mode
"test:watch": "react-scripts test",
// test run that generates coverage reports
"test:coverage": "set CI=true
&& react-scripts test --coverage"
}
}

This is the best way of introducing Istanbul to your app because you control whether or not reports will be generated based on what script you use.
The reason why you don’t want to always create reports is performance — generating reports on every run may significantly slow down your tests.
So when you need a coverage report, you run npm run test:coverage, but when you don't, you use npm run test, which has faster and less expensive execution.

The second way of turning on Istanbul is using the collectCoverage property that is false by default.

//package.json
{
...
"jest": {
collectCoverage: true
}
}

Doing this will make every test run collect coverage and generate reports, which is way less flexible then using the --coverage flag and can have a big performance impact.

I would suggest always setting Istanbul using the first way we discussed with the coverage flag. That way you will have a completely flexible configuration that will allow you to only pay the overhead of collecting coverage when you actually need coverage report.


Custom Coverage Configuration

Istanbul has many properties that let you customize your coverage report. Let’s take a look at the most useful or interesting ones.

Property collectCoverageFrom lets you define from what sources you want and, more importantly, don’t want to collect coverage from.

You always want to exclude the node_modules directory, some third party code, test files, and so on. Using the collectCoverageFrom property makes configuring that really easy. Excluding is done with a negation operator: “!”.

"jest": {
"collectCoverageFrom": [
"**/*.{js,jsx}",
"!**/node_modules/**",
"!**/coverage/**",
"!**/serviceWorker.js",
"!**/index.js"
],
}

The property coverageThreshold will enforce minimum threshold for coverage results. You can enforce minimums for every entry Istanbul measures: branches, methods, lines, and statements. The cool thing here is that other then global thresholds, you can set them up for any separate directory and even every file.

"jest": {
"coverageThreshold": {
"global": { // global thresholds
"branches": 80,
"functions": 80,
"lines": 80,
"statements": 80
},
"./src/App.js": { // file level thresholds
"lines": 100
}
}
}

There are many more Jest properties. You can really go deep and make configuration that’s perfect for your project.


Conclusion

Having coverage reports and thresholds from the start will make a big difference in the long run. It will keep your project clean, long lasting, and resilient to bugs.

Trying to include test coverage thresholds, linters, and other rules late in the project lifetime almost always ends up as a failure that no one respects.

Be smart and do it from the start.

Better Programming

Advice for programmers.

Oskar

Written by

Oskar

linkedin.com/in/oskarvat

Better Programming

Advice for programmers.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade