Jest: Isolate your Code Coverage on Specific Files.

April 28, 2024

Goal

Run yarn:isolate:coverage, select a file, and see the coverage for that file only.

Introduction

When you run jest --coverage, Jest will collect coverage for the entire project. However, you might want to focus on specific files or modules to get a more isolated view of the code coverage.

This is particularly useful when you are working on a specific feature or module and want to see the coverage for that part of the codebase without running all the tests, all the time.

Step 1: Update Jest Configuration

We need to accomodate our Jest configuration to change the collectCoverageFrom value based on an environment variable.

// jest.config.js
import type { Config } from "jest";

const coverageFrom: string[] = [
  "**/*.{ts,tsx}",
  "!**/node_modules/**",
  "!**/vendor/**",
];

const { COVERAGE_PATH } = process.env;

const coverageCollection = COVERAGE_PATH ? COVERAGE_PATH : coverageFrom;

const config: Config = {
  collectCoverageFrom: coverageCollection,
  //   Rest of the Jest configuration
};

export default config;

Which you would then run in your terminal with:

$ COVERAGE_PATH=path/to/your/file/hello.ts jest --coverage path/to/your/file/hello.spec --watch

This is a bit cumbersome, and time consuming so let's improve the process.

The ideal situation would be to run a command like yarn:isolate:coverage, select a file in a list, and see the coverage for that file only.

Step 2: Create a Script to Simplify the Process

Inside your script folder (assuming you have a script folder), create a file called isolate-coverage.sh and add the following script:

ℹ️ Note: I have added a few comments to explain the script.

#!/bin/bash

# Finds source files (not spec files), with various extensions and select one
function select_file() {
  find . \( -name "*.js" -o -name "*.ts" -o -name "*.jsx" -o -name "*.tsx" \) ! \( -name "*.spec.js" -o -name "*.spec.ts" -o -name "*.spec.jsx" -o -name "*.spec.tsx" \) | fzf --prompt="Select a source file: "
}

# Determines the corresponding test file(s) based on glob pattern
function get_test_files() {
  local base_name="${1%.*}"  # Remove extension
  echo "$base_name.spec.*"
}


# Handles multiple test files and select one if multiple are found
function select_test_file() {
  local test_files_glob=$(get_test_files "$1")
  local test_files=( $test_files_glob )
  if [ ${#test_files[@]} -eq 0 ]; then
    echo "No test files found for $1"
    exit 1
  elif [ ${#test_files[@]} -eq 1 ]; then
    echo "${test_files[0]}"
  else
    # If multiple test files exist, use fzf to select one
    echo "${test_files[@]}" | tr ' ' '\n' | fzf --prompt="Multiple test files found. Select one: "
  fi
}

# Validate input argument for the type of test to run
if [ "$#" -eq 0 ]; then
  echo "No arguments provided. Use --coverage or --unit."
  exit 1
fi

# Determines the test command directly
case "$1" in
  --coverage)
    command_prefix="COVERAGE_PATH="
    test_command="jest --coverage"
    ;;
  --unit)
    command_prefix=""
    test_command="jest"
    ;;
  *)
    echo "Invalid argument provided. Use --coverage or --unit."
    exit 1
    ;;
esac

# Execute the file selection process
selected_file=$(select_file)
if [ -z "$selected_file" ]; then
  echo "No file selected."
  exit 1
fi

# Determine the corresponding test file
test_file=$(select_test_file "$selected_file")
if [ -z "$test_file" ]; then
  echo "No test file selected or found."
  exit 1
fi

# Run Jest directly with the selected test file, including the coverage path if necessary
if [[ "$1" == "--coverage" ]]; then
  COVERAGE_PATH="$selected_file" $test_command "$test_file" --watch
else
  $test_command "$test_file" --watch
fi

Step 3: Assign the right permissions

Make the script executable by running:

$ chmod +x scripts/isolate-coverage.sh

Step 4: Add the Script to Your package.json

Add the following script to your package.json:

{
  "scripts": {
    "test:isolate:coverage": "scripts/isolate-coverage.sh --coverage",
    "test:isolate:unit": "scripts/isolate-coverage.sh --unit"
  }
}

Step 5: Install fzf

You need to install fzf to use the script. You can install it with brew:

$ brew install fzf

Step 6: Run the Script

Now you can run the script with:

$ yarn test:isolate:coverage

You will be prompted to select a file, and the script will run Jest with the coverage for that file only.

Conclusion

Facilitate your and your team's life by making their developer's experience better. Do not underestimate the power of small improvements in your workflow.

The biggest mountains are made of small stones