diff --git a/README.md b/README.md index a1ffc33..e0d8e3a 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,11 @@ typegap --baseline coverage.json typegap --compare coverage.json ``` +Baseline comparisons report changed and new files, plus files that were present +in the saved baseline but are absent from the current scan. Removed files retain +their previous coverage in both text and JSON output, so deleting a low-coverage +file cannot appear as an unexplained overall improvement. + The global install points at the checkout, so rebuild after pulling changes. When the first npm release is available, `npm install --global typegap` will become the registry installation path; it is not supported today. diff --git a/src/reporter.test.ts b/src/reporter.test.ts index 252854c..c54bd9b 100644 --- a/src/reporter.test.ts +++ b/src/reporter.test.ts @@ -73,6 +73,32 @@ describe('generateReport', () => { ]); }); + it('reports a removed low-coverage file behind an overall improvement', () => { + const removedFile = makeResult().files[0]; + removedFile.file = 'removed.ts'; + removedFile.coverage = 0; + const keptFile = { ...makeResult().files[0], file: 'kept.ts', coverage: 100 }; + const oldResult = makeResult({ files: [removedFile, keptFile], coverage: 50 }); + saveBaseline(oldResult, BASELINE_FILE); + + const newResult = makeResult({ files: [keptFile], coverage: 100 }); + const json = JSON.parse(generateReport(newResult, { + format: 'json', + compareBaseline: BASELINE_FILE, + }).output); + const text = generateReport(newResult, { compareBaseline: BASELINE_FILE }).output; + + expect(json.comparison.coverageDelta).toBe(50); + expect(json.comparison.files).toEqual([ + { + file: 'removed.ts', + coverageBefore: 0, + status: 'removed', + }, + ]); + expect(text).toMatch(/removed\.ts:.*removed.*\(0\.0%\)/); + }); + it('returns exit code 0 when above min coverage', () => { const result = makeResult(); const { exitCode } = generateReport(result, { minCoverage: 70 }); diff --git a/src/reporter.ts b/src/reporter.ts index 7b50806..0a05cdd 100644 --- a/src/reporter.ts +++ b/src/reporter.ts @@ -103,7 +103,11 @@ export function compareWithBaseline(result: ProjectResult, baseline: Baseline, c } if (file.status === 'new') { - lines.push(` ${file.file}: ${pc.yellow('new')} (${file.coverageCurrent.toFixed(1)}%)`); + lines.push(` ${file.file}: ${pc.yellow('new')} (${file.coverageCurrent!.toFixed(1)}%)`); + } + + if (file.status === 'removed') { + lines.push(` ${file.file}: ${pc.yellow('removed')} (${file.coverageBefore!.toFixed(1)}%)`); } } @@ -276,6 +280,8 @@ export function getBaselineComparison( continue; } + baselineMap.delete(filePath); + const coverageDelta = round(f.coverage - prev.coverage); if (coverageDelta !== 0) { files.push({ @@ -288,6 +294,14 @@ export function getBaselineComparison( } } + for (const [filePath, prev] of baselineMap) { + files.push({ + file: filePath, + coverageBefore: prev.coverage, + status: 'removed', + }); + } + return { baselineTimestamp: baseline.timestamp, coverageBefore: baseline.coverage, diff --git a/src/types.ts b/src/types.ts index 74165a2..d5e82aa 100644 --- a/src/types.ts +++ b/src/types.ts @@ -92,8 +92,8 @@ export interface BaselineComparison { files: Array<{ file: string; coverageBefore?: number; - coverageCurrent: number; + coverageCurrent?: number; coverageDelta?: number; - status: 'changed' | 'new'; + status: 'changed' | 'new' | 'removed'; }>; }