MC/DC coverage for JavaScript
Line and branch coverage can reach 100% while a condition goes untested. MC/DC shows what’s missing.

A checkout function can have 100% line and branch coverage without a test for an expired session. Both return paths run. Both tests pass. But removing the expiry check still leaves the suite green.
MC/DC coverage asks a more specific question: has each condition been shown to change the decision on its own?
Here’s what that looks like in JavaScript, using a small example we ran with Supercov.
The condition the tests miss
This function allows checkout when a customer is signed in and their session has not expired:
export function canCheckout(signedIn, expired) {
if (signedIn && !expired) return true;
return false;
}
The original tests check a valid session and a signed-out visitor:
assert.equal(canCheckout(true, false), true);
assert.equal(canCheckout(false, false), false);
One test takes the true return path. The other takes the false path. Neither passes true for expired.
If we accidentally change the condition to just signedIn, both tests still pass. An expired session would now be accepted.

What MC/DC measures
MC/DC stands for Modified Condition/Decision Coverage. A decision is the whole expression, signedIn && !expired. Its two conditions are signedIn and !expired.
For each condition, MC/DC looks for a pair of executions showing that the condition independently changes the decision’s outcome. For this example, the useful cases are:
| Case | signedIn | expired | Checkout allowed? |
|---|---|---|---|
| Valid session | true | false | true |
| Signed out | false | false | false |
| Expired session | true | true | false |
Compare the first two rows: changing signedIn changes the result. Compare the first and third: changing expired changes the result while signedIn stays true. The original suite has the first pair, but not the second.
JavaScript short-circuits &&: when signedIn is false, it does not evaluate !expired. Coverage tools need to retain that distinction rather than treating a skipped condition as a false one. The precise witness rules also depend on the form of MC/DC being measured; Clang’s coverage documentation explains its masking approach. For this small example, the missing expired-session case is straightforward.
Measure it with Supercov
Run your existing test command through Supercov, then query the result:
npx supercov -- npm test
npx supercov runs latest
Everything after -- is your project’s test command. Here, npm test runs the example’s two tests. This is the coverage summary from that recorded run:
Coverage
Lines 100.00% (3/3)
Branches 100.00% (2/2)
MC/DC 50.00% (1/2)
These are Supercov’s counts for this file, not a claim that every coverage provider would print the same percentages. Different tools count branches differently. In particular, ordinary branch or condition counters are not the same as evidence that a condition independently changes a decision.
To see what’s missing:
npx supercov runs latest gaps
npx supercov runs latest file src/session.js
The file view identifies the condition:
LINE STATUS SOURCE
2 PARTIAL signedIn && !expired
Unobserved: no witness pair shows `!expired` independently changing the decision result
That is enough information to choose a test. We need a signed-in customer whose session has expired.
Add a test that checks the missing behavior
In our recorded run, the coding agent added this test and left the application code unchanged:
test('a signed-in visitor with an expired session cannot check out', () => {
assert.equal(canCheckout(true, true), false);
});
The assertion matters. Calling the function would exercise the condition; checking the result verifies that this input is denied checkout.
After rerunning the same suite, all three tests passed. The agent compared the new run with the baseline:
npx supercov -- npm test
npx supercov diff <before-run-id> latest
Replace <before-run-id> with the ID from your baseline run. The recorded comparison showed:
lines +0pp, branches +0pp, MC/DC +50pp
gained: 0 lines, 0 branches, 1 MC/DC conditions
lost: 0 lines, 0 branches, 0 MC/DC conditions
+ MC/DC src/session.js:2 C2 !expired
Line and branch coverage did not change. The suite now checks a behavior it did not check before. Removing the expiry guard makes the new test fail.

You can download the original two-test project or inspect the source files and recorded run. The Agent workflow guide walks through reproducing it with your own agent.
Use it with a coding agent
You don’t need to pick every gap yourself. Open your project in your agent and ask:
Measure code coverage with npx supercov and write one missing test.
Only change tests. Rerun the full test suite and show me the test you
added and the before-and-after coverage.
Supercov supplies the measurements. The agent runs the commands and writes the test. Review the changed test and the comparison in the conversation.
MC/DC is useful for conditions in session checks, permissions, discounts, and feature gates. It does not establish that the requirement itself is right, that every input is tested, or that the program is bug-free. Use it to find specific gaps, then write assertions for the behavior you actually want.
For runner and language requirements, see Supported languages. For the meaning and limits of each metric, see Understanding coverage.