When a function uses compound boolean expressions (e.g., A && B || C), standard branch coverage is insufficient. Use Modified Condition/Decision Coverage (MC/DC) to ensure each individual condition independently affects the outcome.
When to use MC/DC:
- Authorization/RBAC guards
- Eligibility/business rules (status, feature flags, tiers)
- Validation logic (multi-field validation)
- State machine transitions
The Pattern: Baseline + Toggle Each Condition
- Baseline: Test where all conditions are true (result is expected to be true).
- Toggles: Create one test for each condition where that specific condition is changed to make the expression false, while keeping all other conditions true.
describe("canPerformAction -- MC/DC", () => {
// Baseline: all conditions true -> allowed
it("allows when all conditions met", () => {
const result = canPerformAction(
createMockUser({ role: "ADMIN" }),
createMockOrganization({ tier: "PRO", suspended: false })
);
expect(result).toBe(true);
});
// Toggle role alone -> denied
it("denies when non-admin (other conditions true)", () => {
const result = canPerformAction(
createMockUser({ role: "MEMBER" }),
createMockOrganization({ tier: "PRO", suspended: false })
);
expect(result).toBe(false);
});
// Toggle tier alone -> denied
it("denies when free tier (other conditions true)", () => {
const result = canPerformAction(
createMockUser({ role: "ADMIN" }),
createMockOrganization({ tier: "FREE", suspended: false })
);
expect(result).toBe(false);
});
// Toggle suspended alone -> denied
it("denies when suspended (other conditions true)", () => {
const result = canPerformAction(
createMockUser({ role: "ADMIN" }),
createMockOrganization({ tier: "PRO", suspended: true })
);
expect(result).toBe(false);
});
});