ReviseAlgo Logo

Testing JavaScript

Code Coverage

Master code coverage in JavaScript testing. Understand statement, branch, function, and line coverage metrics and how to generate report files.

Last Updated: July 15, 2026 10 min read

1. Introduction

Code Coverage is a metric that measures the percentage of your application's source code that is executed when running your automated test suite. It helps you identify untested files, functions, or execution branches.

2. Why It Matters

Writing tests doesn't guarantee that all code is verified. If your application has complex if-else branches, your tests might only cover the success path, leaving error-handling paths untested. Code coverage reports highlight these untested blocks, helping you improve test reliability.

3. Real-World Analogy

Think of a Warehouse Security Guard Patrol Log:

  • Untracked Patrol: The guard claims they checked the building. Everything seemed fine. However, they only walked down the main hallways, skipping the storage rooms and fire exits.
  • Code Coverage (GPS Checkpoint Tracker): The guard carries a scanner that registers checkpoints. When they complete their patrol, the tracker generates a report: "85% of rooms visited. Untested rooms: Back storage room 4 and Emergency Exit B." You get a clear, mathematical record of what areas were inspected and what areas were missed.

4. Types of Code Coverage

Coverage reports divide source code metrics into four categories:
Statement Coverage: The percentage of statements in the code that were executed.
Branch Coverage: The percentage of control structures (like if statements or switch cases) executed. This is critical for catching untested conditional branches.
Function Coverage: The percentage of functions or methods declared in the code that were called.
Line Coverage: The percentage of executable lines of code that were run.

5. Generating Coverage Reports

Jest includes a built-in coverage tool using Istanbul. You can generate a coverage report by running Jest with the --coverage flag:

This command prints a table summary to the console and generates a detailed HTML report inside a local /coverage folder. You can open /coverage/lcov-report/index.html in your browser to inspect which lines are highlighted in green (executed) or red (unexecuted).

6. Practical Example

Consider this validation helper:

If you write a single test that passes an admin user, your coverage report will show:
Statement Coverage: 75%
Branch Coverage: 50% (Branch B was never executed!)
To reach 100% branch coverage, you must add a second test case that passes a non-admin user.

7. Common Mistakes

  • Targeting 100% code coverage as a strict requirement: Chasing 100% coverage can lead to writing tests that assert trivial properties (like getters and setters) or writing weak assertions that do not verify actual behavior just to increase coverage. Focus on writing high-quality tests for critical business logic instead of chasing metrics.

8. Quick Quiz

Q1: Which type of code coverage checks that both the true and false conditions of an 'if' statement have been executed by tests?

A) Function Coverage

B) Branch Coverage

Answer: B — Branch coverage measures the execution of all conditional pathways, ensuring both true and false paths are verified.

9. Scenario-Based Challenge

The Multi-Branch Shipping Discount Reporter:

An application calculates shipping discounts based on membership status, price, and region. Write a Jest test suite that uses the --coverage report tool to locate and cover all conditional branches, ensuring 100% branch coverage.

10. Debugging Exercise

Explain why this test suite reports 100% line coverage but fails to prevent a crash when an error is thrown:

// utils.js
export function formatData(str) {
  return str.trim(); 
}

// utils.test.js test('formats values', () => { formatData(' hello '); // Executes the line! Reports 100% coverage! });

// Bug: running formatData(null) throws a TypeError, but tests never checked null inputs! Why?

View Solution

Diagnosis: Code coverage only measures which lines of code were executed; it does not measure the quality or completeness of your assertions. The test executed the function with a valid string, reporting 100% coverage, but failed to test boundary conditions (like passing null or undefined) where errors could be thrown.

Fix: Add boundary test cases to verify error handling for invalid inputs:

test('handles null input safely', () => {
  expect(() => formatData(null)).toThrow(); // Test boundary conditions!
});

11. Interview Questions

🟢 Q1: Explain why 100% code coverage does not guarantee bug-free code.

Answer: Code coverage measures which lines of code were executed during tests, but it does not measure the quality or completeness of your assertions.
Missing Assertions: A test can execute a function without checking its return value, reporting 100% coverage while failing to verify behavior.
Boundary Conditions: Coverage checks do not verify that your code handles unexpected inputs (like null, undefined, or negative numbers) correctly.
Logic Bugs: Coverage cannot detect if your code implements the wrong business logic, even if every line is executed.

12. Production Considerations

  • Coverage Gates: In production environments, configure coverage thresholds inside your jest.config.js file (e.g. setting branches: 80) to fail builds in your CI/CD pipeline if code coverage drops below the limit.