Skip to content

Test Coverage Matrix

The test coverage matrix transforms execution paths into concrete test cases. Each path becomes a test with setup conditions, expected steps, and a priority level - giving you a structured plan for testing your Effect programs.

Terminal window
npx effect-analyze ./src/transfer.ts --format matrix

This outputs a markdown table of programs and their service dependencies. For the full test matrix with test cases, use the library API.

import { analyze, generatePaths, generateTestMatrix } from "effect-analyzer"
import { Effect } from "effect"
const ir = await Effect.runPromise(analyze("./src/transfer.ts").single())
const paths = generatePaths(ir)
const matrix = generateTestMatrix(paths)
console.log(matrix.summary.totalTests) // Total test cases
console.log(matrix.summary.highPriority) // High-priority tests
console.log(matrix.summary.conditions) // Unique conditions to cover

The TestMatrix object contains:

FieldTypeDescription
pathsTestPath[]One test case per execution path
conditionsTestCondition[]All unique conditions across paths
summaryTestMatrixSummaryAggregate statistics

Each TestPath includes:

FieldTypeDescription
testNamestringGenerated test name (e.g., “should complete transfer successfully”)
priority'high' | 'medium' | 'low'Test importance based on path characteristics
setupConditionsstring[]What to set up before the test
expectedStepsstring[]Steps that should execute in this path
hasLoopsbooleanWhether this path involves loop iterations

Test cases are prioritized based on the path they cover:

PriorityCriteria
HighHappy path (no error conditions), or paths with error handling
MediumPaths with conditional branches
LowLoop-heavy paths, paths with many conditions

Render the test matrix as a readable markdown document:

import { formatTestMatrixMarkdown } from "effect-analyzer"
const markdown = formatTestMatrixMarkdown(matrix)
console.log(markdown)

Output:

## Test Coverage Matrix
| # | Test | Priority | Conditions | Steps |
|---|------|----------|------------|-------|
| 1 | should complete transfer successfully | high | balance >= amount | getBalance → debit → credit → record |
| 2 | should fail with InsufficientFunds | high | balance < amount | getBalance → fail |

Generate runnable test skeletons for your preferred test framework:

import { formatTestMatrixAsCode } from "effect-analyzer"
// Vitest (default)
const vitest = formatTestMatrixAsCode(matrix, { framework: "vitest" })
// Jest
const jest = formatTestMatrixAsCode(matrix, { framework: "jest" })
// Mocha
const mocha = formatTestMatrixAsCode(matrix, { framework: "mocha" })

Example output for Vitest:

import { describe, it, expect } from "vitest"
describe("transfer", () => {
it("should complete transfer successfully", () => {
// Setup: balance >= amount
// Expected steps: getBalance → debit → credit → record
})
it("should fail with InsufficientFunds", () => {
// Setup: balance < amount
// Expected steps: getBalance → fail
})
})

For code review or manual testing, generate a markdown checklist:

import { formatTestChecklist } from "effect-analyzer"
const checklist = formatTestChecklist(matrix)
console.log(checklist)

Output:

## Test Checklist
- [ ] **[HIGH]** should complete transfer successfully
- Setup: balance >= amount
- Verify: getBalance → debit → credit → record
- [ ] **[HIGH]** should fail with InsufficientFunds
- Setup: balance < amount
- Verify: getBalance → fail

Customize test matrix generation with TestMatrixOptions:

const matrix = generateTestMatrix(paths, {
testNamePrefix: "should", // Prefix for test names
includeLoopPaths: true, // Include paths through loops
testNameGenerator: (path) => { // Custom name generator
return `handles ${path.steps.length} steps`
},
})
OptionTypeDefaultDescription
testNamePrefixstring"should"Prefix for generated test names
testNameGenerator(path) => stringbuilt-inCustom function for test naming
includeLoopPathsbooleantrueInclude paths that traverse loops