From 5fb128539afcaf413856cc43bc92e90ef41d9a05 Mon Sep 17 00:00:00 2001 From: Craig Spence Date: Mon, 16 Sep 2024 17:56:10 +1200 Subject: [PATCH] =?UTF-8?q?fix(betterer=20=F0=9F=90=9B):=20improve=20docs,?= =?UTF-8?q?=20handle=20include=20and=20exclude,=20add=20tests,=20simplify?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 1 + packages/coverage/src/coverage-test.ts | 11 +- packages/coverage/src/coverage.ts | 4 +- packages/coverage/src/serialiser.ts | 7 - packages/coverage/src/test.ts | 18 +- packages/coverage/src/types.ts | 14 +- .../coverage-total-include.spec.ts.snap | 132 +++++++++++++ test/coverage-files-better.spec.ts | 48 +++-- test/coverage-files-exclude.spec.ts | 44 +++-- test/coverage-files-include.spec.ts | 44 +++-- test/coverage-files-same.spec.ts | 102 +++++----- test/coverage-files-worse.spec.ts | 182 +++++++++--------- test/coverage-report-invalid.spec.ts | 16 +- test/coverage-report-missing.spec.ts | 12 +- test/coverage-total-include.spec.ts | 144 ++++++++++++++ test/coverage-total.spec.ts | 111 +++++++---- website/docs/coverage-test.md | 11 +- 17 files changed, 630 insertions(+), 271 deletions(-) delete mode 100644 packages/coverage/src/serialiser.ts create mode 100644 test/__snapshots__/coverage-total-include.spec.ts.snap create mode 100644 test/coverage-total-include.spec.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 9d752e831..ef5dc8dc6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,6 +17,7 @@ "docgen", "GOLDENS", "hasher", + "initialisation", "initialise", "initialised", "Initialising", diff --git a/packages/coverage/src/coverage-test.ts b/packages/coverage/src/coverage-test.ts index a3437f880..fd7b973d3 100644 --- a/packages/coverage/src/coverage-test.ts +++ b/packages/coverage/src/coverage-test.ts @@ -10,7 +10,6 @@ import { BettererResolverTest } from '@betterer/betterer'; import { constraint } from './constraint.js'; import { differ } from './differ.js'; import { goal } from './goal.js'; -import { deserialise, serialise } from './serialiser.js'; export class BettererCoverageTestΞ© extends BettererResolverTest @@ -18,16 +17,10 @@ export class BettererCoverageTestΞ© { constructor(test: BettererCoverageTestFunction, coverageSummaryPath = './coverage/coverage-summary.json') { super({ - test: async () => { - return await test(coverageSummaryPath, this.resolver); - }, + test: async () => await test(coverageSummaryPath, this.resolver), constraint, differ, - goal, - serialiser: { - serialise, - deserialise - } + goal }); } } diff --git a/packages/coverage/src/coverage.ts b/packages/coverage/src/coverage.ts index ed33d2477..c72c88d83 100644 --- a/packages/coverage/src/coverage.ts +++ b/packages/coverage/src/coverage.ts @@ -8,7 +8,7 @@ import { test, testTotal } from './test.js'; * Use this test to track your per-file test coverage. Reads a {@link https://github.com/istanbuljs/istanbuljs/blob/master/packages/istanbul-reports/lib/json-summary/index.js | json-summary format} * coverage summary. Make sure to run your tests separately before running Betterer. * - * @param coverageSummaryPath - relative path to the coverage summary. Defaults to './coverage/coverage-summary.json'. + * @param coverageSummaryPath - relative path to the coverage summary. Defaults to `'./coverage/coverage-summary.json'`. */ export function coverage(coverageSummaryPath?: string): BettererCoverageTest { return new BettererCoverageTestΞ©(test, coverageSummaryPath); @@ -19,7 +19,7 @@ export function coverage(coverageSummaryPath?: string): BettererCoverageTest { * Use this test to track your total test coverage. Reads a {@link https://github.com/istanbuljs/istanbuljs/blob/master/packages/istanbul-reports/lib/json-summary/index.js | json-summary format} * coverage summary. Make sure to run your tests separately before running Betterer. * - * @param coverageSummaryPath - relative path to the coverage summary. Defaults to './coverage/coverage-summary.json'. + * @param coverageSummaryPath - relative path to the coverage summary. Defaults to `'./coverage/coverage-summary.json'`. */ export function coverageTotal(coverageSummaryPath?: string): BettererCoverageTest { return new BettererCoverageTestΞ©(testTotal, coverageSummaryPath); diff --git a/packages/coverage/src/serialiser.ts b/packages/coverage/src/serialiser.ts deleted file mode 100644 index f95366e1e..000000000 --- a/packages/coverage/src/serialiser.ts +++ /dev/null @@ -1,7 +0,0 @@ -export function deserialise(serialised: T): T { - return serialised; -} - -export function serialise(input: T): T { - return input; -} diff --git a/packages/coverage/src/test.ts b/packages/coverage/src/test.ts index d0d8c71c0..5b090fd25 100644 --- a/packages/coverage/src/test.ts +++ b/packages/coverage/src/test.ts @@ -40,11 +40,21 @@ export async function testTotal( relativeCoverageSummaryPath: string, resolver: BettererFileResolver ): Promise { - const absoluteCoverageSummaryPath = resolver.resolve(relativeCoverageSummaryPath); - const { total } = await readCoverageSummary(absoluteCoverageSummaryPath); - return { - total: getUncoveredIssues(total) + const uncovered = await test(relativeCoverageSummaryPath, resolver); + + const total: BettererCoverageIssue = { + lines: 0, + statements: 0, + functions: 0, + branches: 0 }; + Object.values(uncovered).forEach((fileCoverage) => { + total.branches += fileCoverage.branches; + total.functions += fileCoverage.functions; + total.lines += fileCoverage.lines; + total.statements += fileCoverage.statements; + }); + return { total }; } async function readCoverageSummary(coverageSummaryPath: string): Promise { diff --git a/packages/coverage/src/types.ts b/packages/coverage/src/types.ts index 29a0c8f94..f8ca576d7 100644 --- a/packages/coverage/src/types.ts +++ b/packages/coverage/src/types.ts @@ -3,9 +3,7 @@ import type { CoverageSummaryData, Totals } from 'istanbul-lib-coverage'; export type IstanbulCoverage = Totals; export type IstanbulFileCoverage = CoverageSummaryData; -export type IstanbulCoverageSummary = Record & { - total: IstanbulFileCoverage; -}; +export type IstanbulCoverageSummary = Record; /** * @public A {@link @betterer/betterer#BettererTest | `BettererTest`} to incrementally improve test coverage. @@ -22,21 +20,23 @@ export type BettererCoverageTestFunction = ( ) => Promise; /** - * @public The different types of coverage which are checked + * @public The different types of coverage which are checked. */ export type BettererCoverageTypes = 'lines' | 'statements' | 'functions' | 'branches'; /** - * @public The lines, statements, functions and branches coverage for a file (or the total project) + * @public The lines, statements, functions and branches coverage for a file (or the total project). + * + * @remarks Each value indicates how many of each type remain uncovered in the file. */ export type BettererCoverageIssue = Record; /** - * @public The coverage for all the files in a project + * @public The coverage for all the files in a project. */ export type BettererCoverageIssues = Record; /** - * @public The difference in coverage for a project between two test runs + * @public The difference in coverage for a project between two test runs. */ export type BettererCoverageDiff = BettererCoverageIssues; diff --git a/test/__snapshots__/coverage-total-include.spec.ts.snap b/test/__snapshots__/coverage-total-include.spec.ts.snap new file mode 100644 index 000000000..eb1a05b60 --- /dev/null +++ b/test/__snapshots__/coverage-total-include.spec.ts.snap @@ -0,0 +1,132 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`betterer > should report the total coverage for included files 1`] = ` +"// BETTERER RESULTS V2. +// +// If this file contains merge conflicts, use \`betterer merge\` to automatically resolve them: +// https://phenomnomnominal.github.io/betterer/docs/results-file/#merge +// +exports[\`test\`] = { + value: \`{ + "total": { "lines": 50, "statements": 130, "functions": 15, "branches": 100 } +} +\` +}; +" +`; + +exports[`betterer > should report the total coverage for included files 2`] = ` +"// BETTERER RESULTS V2. +// +// If this file contains merge conflicts, use \`betterer merge\` to automatically resolve them: +// https://phenomnomnominal.github.io/betterer/docs/results-file/#merge +// +exports[\`test\`] = { + value: \`{ + "total": { "lines": 30, "statements": 130, "functions": 15, "branches": 100 } +} +\` +}; +" +`; + +exports[`betterer > should report the total coverage for included files 3`] = ` +"// BETTERER RESULTS V2. +// +// If this file contains merge conflicts, use \`betterer merge\` to automatically resolve them: +// https://phenomnomnominal.github.io/betterer/docs/results-file/#merge +// +exports[\`test\`] = { + value: \`{ + "total": { "lines": 30, "statements": 130, "functions": 15, "branches": 100 } +} +\` +}; +" +`; + +exports[`betterer > should report the total coverage for included files 4`] = ` +[ + "🌟 Betterer (0ms): +", + "🌟 Betterer (0ms): 1 test running... +πŸ€” test: running "test"! +", + "🌟 Betterer (0ms): 1 test running... +βœ… test: "test" got checked for the first time! πŸŽ‰ +", + "πŸŽ‰ Betterer (0ms): 1 test done! +βœ… test: "test" got checked for the first time! πŸŽ‰ +", + "πŸŽ‰ Betterer (0ms): 1 test done! +βœ… test: "test" got checked for the first time! πŸŽ‰ + +1 test got checked. πŸ€” +1 test got checked for the first time! πŸŽ‰ +", + "🌟 Betterer (0ms): +", + "🌟 Betterer (0ms): 1 test running... +πŸ€” test: running "test"! +", + "🌟 Betterer (0ms): 1 test running... +βœ… test: "test" stayed the same. 😐 +", + "πŸŽ‰ Betterer (0ms): 1 test done! +βœ… test: "test" stayed the same. 😐 +", + "πŸŽ‰ Betterer (0ms): 1 test done! +βœ… test: "test" stayed the same. 😐 + +1 test got checked. πŸ€” +1 test stayed the same. 😐 +", + "🌟 Betterer (0ms): +", + "🌟 Betterer (0ms): 1 test running... +πŸ€” test: running "test"! +", + "🌟 Betterer (0ms): 1 test running... +βœ… test: "test" got better! 😍 +", + "πŸŽ‰ Betterer (0ms): 1 test done! +βœ… test: "test" got better! 😍 +", + "πŸŽ‰ Betterer (0ms): 1 test done! +βœ… test: "test" got better! 😍 + +1 test got checked. πŸ€” +1 test got better! 😍 +", + "🌟 Betterer (0ms): +", + "🌟 Betterer (0ms): 1 test running... +πŸ€” test: running "test"! +", + "🌟 Betterer (0ms): 1 test running... +πŸ”₯ test: "test" got worse. πŸ˜” +", + "🌟 Betterer (0ms): 1 test running... +πŸ”₯ test: "test" got worse. πŸ˜” + +Error: "test" got worse. πŸ˜” +", + "πŸ’₯ Betterer (0ms): 1 test done! 1 test errored! +πŸ”₯ test: "test" got worse. πŸ˜” +・ "lines" coverage is worse in "total": 60 > 30 + +Error: "test" got worse. πŸ˜” +", + "πŸ’₯ Betterer (0ms): 1 test done! 1 test errored! +πŸ”₯ test: "test" got worse. πŸ˜” +・ "lines" coverage is worse in "total": 60 > 30 + +Error: "test" got worse. πŸ˜” + +1 test got checked. πŸ€” +1 test got worse. πŸ˜” + +You should try to fix the new issues! As a last resort, you can run \`betterer --update\` to force an update of the results file. πŸ†™ +", +] +`; diff --git a/test/coverage-files-better.spec.ts b/test/coverage-files-better.spec.ts index c7c8ccdc1..4bb7224bb 100644 --- a/test/coverage-files-better.spec.ts +++ b/test/coverage-files-better.spec.ts @@ -6,7 +6,7 @@ describe('betterer', () => { it('should report an improved file coverage result', async () => { const { betterer } = await import('@betterer/betterer'); - const fixture = await createFixture('coverage-files-better', { + const { paths, logs, cleanup, resolve, testNames, writeFile } = await createFixture('coverage-files-better', { '.betterer.js': ` import { coverage } from '@betterer/coverage'; @@ -22,10 +22,11 @@ export default { ` }); - const file1Path = fixture.resolve('./src/file-1.ts'); - const file2Path = fixture.resolve('./src/file-2.ts'); + const file1Path = resolve('./src/file-1.ts'); + const file2Path = resolve('./src/file-2.ts'); - const coverage = `{ + const coverage = ` +{ "total": { "lines": { "total": 220, "covered": 110, "skipped": 0, "pct": 50 }, "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, @@ -44,18 +45,20 @@ export default { "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } } -}`; +} + `; - const configPaths = [fixture.paths.config]; - const resultsPath = fixture.paths.results; - const coveragePath = fixture.resolve('./coverage/coverage-summary.json'); + const configPaths = [paths.config]; + const resultsPath = paths.results; + const coveragePath = resolve('./coverage/coverage-summary.json'); - await fixture.writeFile(coveragePath, coverage); + await writeFile(coveragePath, coverage); await betterer({ configPaths, resultsPath, workers: false }); // file-1 is better - const betterCoverage = `{ + const betterCoverage = ` +{ "total": { "lines": { "total": 220, "covered": 120, "skipped": 0, "pct": 54.54 }, "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, @@ -74,16 +77,18 @@ export default { "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } } -}`; +} + `; - await fixture.writeFile(coveragePath, betterCoverage); + await writeFile(coveragePath, betterCoverage); const betterTestRun = await betterer({ configPaths, resultsPath, workers: false }); - expect(fixture.testNames(betterTestRun.better)).toEqual(['test']); + expect(testNames(betterTestRun.better)).toEqual(['test']); // file-1 is gone - const evenBetterCoverage = `{ + const evenBetterCoverage = ` +{ "total": { "lines": { "total": 120, "covered": 60, "skipped": 0, "pct": 50 }, "statements": { "total": 210, "covered": 70, "skipped": 0, "pct": 33.3 }, @@ -96,13 +101,14 @@ export default { "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } } -}`; +} + `; - await fixture.writeFile(coveragePath, evenBetterCoverage); + await writeFile(coveragePath, evenBetterCoverage); const evenBetterTestRun = await betterer({ configPaths, resultsPath, workers: false }); - expect(fixture.testNames(evenBetterTestRun.better)).toEqual(['test']); + expect(testNames(evenBetterTestRun.better)).toEqual(['test']); // file-2 is fully covered const completedCoverage = `{ @@ -120,14 +126,14 @@ export default { } }`; - await fixture.writeFile(coveragePath, completedCoverage); + await writeFile(coveragePath, completedCoverage); const completedTestRun = await betterer({ configPaths, resultsPath, workers: false }); - expect(fixture.testNames(completedTestRun.completed)).toEqual(['test']); + expect(testNames(completedTestRun.completed)).toEqual(['test']); - expect(fixture.logs).toMatchSnapshot(); + expect(logs).toMatchSnapshot(); - await fixture.cleanup(); + await cleanup(); }); }); diff --git a/test/coverage-files-exclude.spec.ts b/test/coverage-files-exclude.spec.ts index a35ba1dfe..0350800f6 100644 --- a/test/coverage-files-exclude.spec.ts +++ b/test/coverage-files-exclude.spec.ts @@ -6,7 +6,7 @@ describe('betterer', () => { it('should work when excluding specific files', async () => { const { betterer } = await import('@betterer/betterer'); - const fixture = await createFixture('coverage-files-exclude', { + const { paths, logs, cleanup, resolve, testNames, writeFile } = await createFixture('coverage-files-exclude', { '.betterer.js': ` import { coverage } from '@betterer/coverage'; @@ -22,10 +22,11 @@ export default { ` }); - const file1Path = fixture.resolve('./src/file-1.ts'); - const file2Path = fixture.resolve('./src/file-2.ts'); + const file1Path = resolve('./src/file-1.ts'); + const file2Path = resolve('./src/file-2.ts'); - const coverage = `{ + const coverage = ` +{ "total": { "lines": { "total": 220, "covered": 110, "skipped": 0, "pct": 50 }, "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, @@ -44,18 +45,20 @@ export default { "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } } -}`; +} + `; - const configPaths = [fixture.paths.config]; - const resultsPath = fixture.paths.results; - const coveragePath = fixture.resolve('./coverage/coverage-summary.json'); + const configPaths = [paths.config]; + const resultsPath = paths.results; + const coveragePath = resolve('./coverage/coverage-summary.json'); - await fixture.writeFile(coveragePath, coverage); + await writeFile(coveragePath, coverage); await betterer({ configPaths, resultsPath, workers: false }); // file-1 is better - const betterCoverage = `{ + const betterCoverage = ` +{ "total": { "lines": { "total": 220, "covered": 120, "skipped": 0, "pct": 54.54 }, "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, @@ -74,16 +77,18 @@ export default { "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } } -}`; +} + `; - await fixture.writeFile(coveragePath, betterCoverage); + await writeFile(coveragePath, betterCoverage); const betterTestRun = await betterer({ configPaths, resultsPath, workers: false }); - expect(fixture.testNames(betterTestRun.better)).toEqual(['test']); + expect(testNames(betterTestRun.better)).toEqual(['test']); // file-2 is worse (but result is the same because it's excluded) - const sameCoverage = `{ + const sameCoverage = ` +{ "total": { "lines": { "total": 220, "covered": 100, "skipped": 0, "pct": 45.4 }, "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, @@ -102,16 +107,17 @@ export default { "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } } -}`; +} + `; - await fixture.writeFile(coveragePath, sameCoverage); + await writeFile(coveragePath, sameCoverage); const sameTestRun = await betterer({ configPaths, resultsPath, workers: false }); - expect(fixture.testNames(sameTestRun.same)).toEqual(['test']); + expect(testNames(sameTestRun.same)).toEqual(['test']); - expect(fixture.logs).toMatchSnapshot(); + expect(logs).toMatchSnapshot(); - await fixture.cleanup(); + await cleanup(); }); }); diff --git a/test/coverage-files-include.spec.ts b/test/coverage-files-include.spec.ts index 52312eda3..18246d243 100644 --- a/test/coverage-files-include.spec.ts +++ b/test/coverage-files-include.spec.ts @@ -6,7 +6,7 @@ describe('betterer', () => { it('should work when including specific files', async () => { const { betterer } = await import('@betterer/betterer'); - const fixture = await createFixture('coverage-files-include', { + const { paths, logs, cleanup, resolve, testNames, writeFile } = await createFixture('coverage-files-include', { '.betterer.ts': ` import { coverage } from '@betterer/coverage'; @@ -22,10 +22,11 @@ export default { ` }); - const file1Path = fixture.resolve('./src/file-1.ts'); - const file2Path = fixture.resolve('./src/file-2.ts'); + const file1Path = resolve('./src/file-1.ts'); + const file2Path = resolve('./src/file-2.ts'); - const coverage = `{ + const coverage = ` +{ "total": { "lines": { "total": 220, "covered": 110, "skipped": 0, "pct": 50 }, "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, @@ -44,18 +45,20 @@ export default { "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } } -}`; +} + `; - const configPaths = [fixture.paths.config]; - const resultsPath = fixture.paths.results; - const coveragePath = fixture.resolve('./coverage/coverage-summary.json'); + const configPaths = [paths.config]; + const resultsPath = paths.results; + const coveragePath = resolve('./coverage/coverage-summary.json'); - await fixture.writeFile(coveragePath, coverage); + await writeFile(coveragePath, coverage); await betterer({ configPaths, resultsPath, workers: false }); // file-1 is better - const betterCoverage = `{ + const betterCoverage = ` +{ "total": { "lines": { "total": 220, "covered": 120, "skipped": 0, "pct": 54.54 }, "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, @@ -74,16 +77,18 @@ export default { "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } } -}`; +} + `; - await fixture.writeFile(coveragePath, betterCoverage); + await writeFile(coveragePath, betterCoverage); const betterTestRun = await betterer({ configPaths, resultsPath, workers: false }); - expect(fixture.testNames(betterTestRun.better)).toEqual(['test']); + expect(testNames(betterTestRun.better)).toEqual(['test']); // file-2 is worse (but result is the same because it's ignored) - const sameCoverage = `{ + const sameCoverage = ` +{ "total": { "lines": { "total": 220, "covered": 100, "skipped": 0, "pct": 45.4 }, "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, @@ -102,16 +107,17 @@ export default { "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } } -}`; +} + `; - await fixture.writeFile(coveragePath, sameCoverage); + await writeFile(coveragePath, sameCoverage); const sameTestRun = await betterer({ configPaths, resultsPath, workers: false }); - expect(fixture.testNames(sameTestRun.same)).toEqual(['test']); + expect(testNames(sameTestRun.same)).toEqual(['test']); - expect(fixture.logs).toMatchSnapshot(); + expect(logs).toMatchSnapshot(); - await fixture.cleanup(); + await cleanup(); }); }); diff --git a/test/coverage-files-same.spec.ts b/test/coverage-files-same.spec.ts index 0e053470a..850c84139 100644 --- a/test/coverage-files-same.spec.ts +++ b/test/coverage-files-same.spec.ts @@ -6,27 +6,31 @@ describe('betterer', () => { it('should report a stable per-file coverage result', async () => { const { betterer } = await import('@betterer/betterer'); - const fixture = await createFixture('coverage-files-same', { - '.betterer.js': ` + const { paths, logs, cleanup, resolve, testNames, readFile, writeFile } = await createFixture( + 'coverage-files-same', + { + '.betterer.js': ` import { coverage } from '@betterer/coverage'; export default { test: () => coverage() }; `, - 'tsconfig.json': ` + 'tsconfig.json': ` { "extends": "../../tsconfig.json", "include": ["./src/**/*", "./.betterer.js"] } - ` - }); + ` + } + ); - const file1Path = fixture.resolve('./src/file-1.ts'); - const file2Path = fixture.resolve('./src/file-2.ts'); - const file3Path = fixture.resolve('./src/file-3.ts'); + const file1Path = resolve('./src/file-1.ts'); + const file2Path = resolve('./src/file-2.ts'); + const file3Path = resolve('./src/file-3.ts'); - const coverage = `{ + const coverage = ` +{ "total": { "lines": { "total": 220, "covered": 110, "skipped": 0, "pct": 50 }, "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, @@ -45,62 +49,66 @@ export default { "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } } -}`; +} + `; - const configPaths = [fixture.paths.config]; - const resultsPath = fixture.paths.results; - const coveragePath = fixture.resolve('./coverage/coverage-summary.json'); + const configPaths = [paths.config]; + const resultsPath = paths.results; + const coveragePath = resolve('./coverage/coverage-summary.json'); - await fixture.writeFile(coveragePath, coverage); + await writeFile(coveragePath, coverage); const newTestRun = await betterer({ configPaths, resultsPath, workers: false }); - expect(fixture.testNames(newTestRun.new)).toEqual(['test']); + expect(testNames(newTestRun.new)).toEqual(['test']); await betterer({ configPaths, resultsPath, workers: false }); const sameTestRun = await betterer({ configPaths, resultsPath, workers: false }); - expect(fixture.testNames(sameTestRun.same)).toEqual(['test']); + expect(testNames(sameTestRun.same)).toEqual(['test']); + + const result = await readFile(resultsPath); - const result = await fixture.readFile(resultsPath); expect(result).toMatchSnapshot(); // file-3 is added but it is 100% covered - const stillSameCoverage = `{ - "total": { - "lines": { "total": 220, "covered": 110, "skipped": 0, "pct": 50 }, - "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, - "functions": { "total": 30, "covered": 11, "skipped": 0, "pct": 36.6 }, - "branches": { "total": 300, "covered": 100, "skipped": 0, "pct": 33.3 } - }, - "${file1Path}": { - "lines": { "total": 100, "covered": 50, "skipped": 0, "pct": 50 }, - "statements": { "total": 200, "covered": 70, "skipped": 0, "pct": 35 }, - "functions": { "total": 20, "covered": 5, "skipped": 0, "pct": 25 }, - "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } - }, - "${file2Path}": { - "lines": { "total": 120, "covered": 60, "skipped": 0, "pct": 50 }, - "statements": { "total": 210, "covered": 70, "skipped": 0, "pct": 33.3 }, - "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, - "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } - }, - "${file3Path}": { - "lines": { "total": 120, "covered": 120, "skipped": 0, "pct": 100 }, - "statements": { "total": 210, "covered": 210, "skipped": 0, "pct": 100 }, - "functions": { "total": 10, "covered": 10, "skipped": 0, "pct": 100 }, - "branches": { "total": 150, "covered": 150, "skipped": 0, "pct": 100 } - } - }`; + const stillSameCoverage = ` +{ + "total": { + "lines": { "total": 220, "covered": 110, "skipped": 0, "pct": 50 }, + "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, + "functions": { "total": 30, "covered": 11, "skipped": 0, "pct": 36.6 }, + "branches": { "total": 300, "covered": 100, "skipped": 0, "pct": 33.3 } + }, + "${file1Path}": { + "lines": { "total": 100, "covered": 50, "skipped": 0, "pct": 50 }, + "statements": { "total": 200, "covered": 70, "skipped": 0, "pct": 35 }, + "functions": { "total": 20, "covered": 5, "skipped": 0, "pct": 25 }, + "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } + }, + "${file2Path}": { + "lines": { "total": 120, "covered": 60, "skipped": 0, "pct": 50 }, + "statements": { "total": 210, "covered": 70, "skipped": 0, "pct": 33.3 }, + "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, + "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } + }, + "${file3Path}": { + "lines": { "total": 120, "covered": 120, "skipped": 0, "pct": 100 }, + "statements": { "total": 210, "covered": 210, "skipped": 0, "pct": 100 }, + "functions": { "total": 10, "covered": 10, "skipped": 0, "pct": 100 }, + "branches": { "total": 150, "covered": 150, "skipped": 0, "pct": 100 } + } +} + `; - await fixture.writeFile(coveragePath, stillSameCoverage); + await writeFile(coveragePath, stillSameCoverage); const stillSameTestRun = await betterer({ configPaths, resultsPath, workers: false }); - expect(fixture.testNames(stillSameTestRun.same)).toEqual(['test']); + expect(testNames(stillSameTestRun.same)).toEqual(['test']); - expect(fixture.logs).toMatchSnapshot(); + expect(logs).toMatchSnapshot(); - await fixture.cleanup(); + await cleanup(); }); }); diff --git a/test/coverage-files-worse.spec.ts b/test/coverage-files-worse.spec.ts index b12964a4d..234a1b012 100644 --- a/test/coverage-files-worse.spec.ts +++ b/test/coverage-files-worse.spec.ts @@ -6,7 +6,7 @@ describe('betterer', () => { it('should report a worse file coverage result', async () => { const { betterer } = await import('@betterer/betterer'); - const fixture = await createFixture('coverage-files-worse', { + const { paths, logs, cleanup, resolve, testNames, writeFile } = await createFixture('coverage-files-worse', { '.betterer.js': ` import { coverage } from '@betterer/coverage'; @@ -22,11 +22,12 @@ export default { ` }); - const file1Path = fixture.resolve('./src/file-1.ts'); - const file2Path = fixture.resolve('./src/file-2.ts'); - const file3Path = fixture.resolve('./src/file-3.ts'); + const file1Path = resolve('./src/file-1.ts'); + const file2Path = resolve('./src/file-2.ts'); + const file3Path = resolve('./src/file-3.ts'); - const coverage = `{ + const coverage = ` +{ "total": { "lines": { "total": 220, "covered": 110, "skipped": 0, "pct": 50 }, "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, @@ -45,108 +46,115 @@ export default { "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } } -}`; +} + `; - const configPaths = [fixture.paths.config]; - const resultsPath = fixture.paths.results; - const coveragePath = fixture.resolve('./coverage/coverage-summary.json'); + const configPaths = [paths.config]; + const resultsPath = paths.results; + const coveragePath = resolve('./coverage/coverage-summary.json'); - await fixture.writeFile(coveragePath, coverage); + await writeFile(coveragePath, coverage); await betterer({ configPaths, resultsPath, workers: false }); // file-1 is worse - const worseCoverage = `{ - "total": { - "lines": { "total": 220, "covered": 100, "skipped": 0, "pct": 45.4 }, - "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, - "functions": { "total": 30, "covered": 11, "skipped": 0, "pct": 36.6 }, - "branches": { "total": 300, "covered": 100, "skipped": 0, "pct": 33.3 } - }, - "${file1Path}": { - "lines": { "total": 100, "covered": 40, "skipped": 0, "pct": 40 }, - "statements": { "total": 200, "covered": 70, "skipped": 0, "pct": 35 }, - "functions": { "total": 20, "covered": 5, "skipped": 0, "pct": 25 }, - "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } - }, - "${file2Path}": { - "lines": { "total": 120, "covered": 60, "skipped": 0, "pct": 50 }, - "statements": { "total": 210, "covered": 70, "skipped": 0, "pct": 33.3 }, - "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, - "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } - } - }`; - - await fixture.writeFile(coveragePath, worseCoverage); + const worseCoverage = ` +{ + "total": { + "lines": { "total": 220, "covered": 100, "skipped": 0, "pct": 45.4 }, + "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, + "functions": { "total": 30, "covered": 11, "skipped": 0, "pct": 36.6 }, + "branches": { "total": 300, "covered": 100, "skipped": 0, "pct": 33.3 } + }, + "${file1Path}": { + "lines": { "total": 100, "covered": 40, "skipped": 0, "pct": 40 }, + "statements": { "total": 200, "covered": 70, "skipped": 0, "pct": 35 }, + "functions": { "total": 20, "covered": 5, "skipped": 0, "pct": 25 }, + "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } + }, + "${file2Path}": { + "lines": { "total": 120, "covered": 60, "skipped": 0, "pct": 50 }, + "statements": { "total": 210, "covered": 70, "skipped": 0, "pct": 33.3 }, + "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, + "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } + } +} + `; + + await writeFile(coveragePath, worseCoverage); const worseTestRun = await betterer({ configPaths, resultsPath, workers: false }); - expect(fixture.testNames(worseTestRun.worse)).toEqual(['test']); + expect(testNames(worseTestRun.worse)).toEqual(['test']); // file-1 is better, but file-2 is worse - const stillWorseCoverage = `{ - "total": { - "lines": { "total": 220, "covered": 90, "skipped": 0, "pct": 40.9 }, - "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, - "functions": { "total": 30, "covered": 11, "skipped": 0, "pct": 36.6 }, - "branches": { "total": 300, "covered": 100, "skipped": 0, "pct": 33.3 } - }, - "${file1Path}": { - "lines": { "total": 100, "covered": 60, "skipped": 0, "pct": 60 }, - "statements": { "total": 200, "covered": 70, "skipped": 0, "pct": 35 }, - "functions": { "total": 20, "covered": 5, "skipped": 0, "pct": 25 }, - "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } - }, - "${file2Path}": { - "lines": { "total": 120, "covered": 30, "skipped": 0, "pct": 25 }, - "statements": { "total": 210, "covered": 70, "skipped": 0, "pct": 33.3 }, - "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, - "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } - } - }`; - - await fixture.writeFile(coveragePath, stillWorseCoverage); + const stillWorseCoverage = ` +{ + "total": { + "lines": { "total": 220, "covered": 90, "skipped": 0, "pct": 40.9 }, + "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, + "functions": { "total": 30, "covered": 11, "skipped": 0, "pct": 36.6 }, + "branches": { "total": 300, "covered": 100, "skipped": 0, "pct": 33.3 } + }, + "${file1Path}": { + "lines": { "total": 100, "covered": 60, "skipped": 0, "pct": 60 }, + "statements": { "total": 200, "covered": 70, "skipped": 0, "pct": 35 }, + "functions": { "total": 20, "covered": 5, "skipped": 0, "pct": 25 }, + "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } + }, + "${file2Path}": { + "lines": { "total": 120, "covered": 30, "skipped": 0, "pct": 25 }, + "statements": { "total": 210, "covered": 70, "skipped": 0, "pct": 33.3 }, + "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, + "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } + } +} + `; + + await writeFile(coveragePath, stillWorseCoverage); const stillWorseTestRun = await betterer({ configPaths, resultsPath, workers: false }); - expect(fixture.testNames(stillWorseTestRun.worse)).toEqual(['test']); + expect(testNames(stillWorseTestRun.worse)).toEqual(['test']); // file-3 is added but it is not 100% covered - const evenWorseCoverage = `{ - "total": { - "lines": { "total": 320, "covered": 150, "skipped": 0, "pct": 46.8 }, - "statements": { "total": 610, "covered": 210, "skipped": 0, "pct": 34.4 }, - "functions": { "total": 50, "covered": 16, "skipped": 0, "pct": 32 }, - "branches": { "total": 450, "covered": 150, "skipped": 0, "pct": 33.3 } - }, - "${file1Path}": { - "lines": { "total": 100, "covered": 60, "skipped": 0, "pct": 60 }, - "statements": { "total": 200, "covered": 70, "skipped": 0, "pct": 35 }, - "functions": { "total": 20, "covered": 5, "skipped": 0, "pct": 25 }, - "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } - }, - "${file2Path}": { - "lines": { "total": 120, "covered": 30, "skipped": 0, "pct": 25 }, - "statements": { "total": 210, "covered": 70, "skipped": 0, "pct": 33.3 }, - "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, - "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } - }, - "${file3Path}": { - "lines": { "total": 100, "covered": 60, "skipped": 0, "pct": 60 }, - "statements": { "total": 200, "covered": 70, "skipped": 0, "pct": 35 }, - "functions": { "total": 20, "covered": 5, "skipped": 0, "pct": 25 }, - "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } - } - }`; - - await fixture.writeFile(coveragePath, evenWorseCoverage); + const evenWorseCoverage = ` +{ + "total": { + "lines": { "total": 320, "covered": 150, "skipped": 0, "pct": 46.8 }, + "statements": { "total": 610, "covered": 210, "skipped": 0, "pct": 34.4 }, + "functions": { "total": 50, "covered": 16, "skipped": 0, "pct": 32 }, + "branches": { "total": 450, "covered": 150, "skipped": 0, "pct": 33.3 } + }, + "${file1Path}": { + "lines": { "total": 100, "covered": 60, "skipped": 0, "pct": 60 }, + "statements": { "total": 200, "covered": 70, "skipped": 0, "pct": 35 }, + "functions": { "total": 20, "covered": 5, "skipped": 0, "pct": 25 }, + "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } + }, + "${file2Path}": { + "lines": { "total": 120, "covered": 30, "skipped": 0, "pct": 25 }, + "statements": { "total": 210, "covered": 70, "skipped": 0, "pct": 33.3 }, + "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, + "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } + }, + "${file3Path}": { + "lines": { "total": 100, "covered": 60, "skipped": 0, "pct": 60 }, + "statements": { "total": 200, "covered": 70, "skipped": 0, "pct": 35 }, + "functions": { "total": 20, "covered": 5, "skipped": 0, "pct": 25 }, + "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } + } +} + `; + + await writeFile(coveragePath, evenWorseCoverage); const evenWorseTestRun = await betterer({ configPaths, resultsPath, workers: false }); - expect(fixture.testNames(evenWorseTestRun.worse)).toEqual(['test']); + expect(testNames(evenWorseTestRun.worse)).toEqual(['test']); - expect(fixture.logs).toMatchSnapshot(); + expect(logs).toMatchSnapshot(); - await fixture.cleanup(); + await cleanup(); }); }); diff --git a/test/coverage-report-invalid.spec.ts b/test/coverage-report-invalid.spec.ts index 1422b7516..92559e3d6 100644 --- a/test/coverage-report-invalid.spec.ts +++ b/test/coverage-report-invalid.spec.ts @@ -6,7 +6,7 @@ describe('betterer', () => { it('should fail when the coverage report is invalid', async () => { const { betterer } = await import('@betterer/betterer'); - const fixture = await createFixture('coverage-report-invalid', { + const { paths, logs, cleanup, resolve, testNames, writeFile } = await createFixture('coverage-report-invalid', { '.betterer.js': ` import { coverageTotal } from '@betterer/coverage'; @@ -30,18 +30,18 @@ export default { } }`; - const configPaths = [fixture.paths.config]; - const resultsPath = fixture.paths.results; - const coveragePath = fixture.resolve('./coverage/coverage-summary.json'); + const configPaths = [paths.config]; + const resultsPath = paths.results; + const coveragePath = resolve('./coverage/coverage-summary.json'); - await fixture.writeFile(coveragePath, coverage); + await writeFile(coveragePath, coverage); const newTestRun = await betterer({ configPaths, resultsPath, workers: false }); - expect(fixture.testNames(newTestRun.failed)).toEqual(['test']); + expect(testNames(newTestRun.failed)).toEqual(['test']); - expect(fixture.logs).toMatchSnapshot(); + expect(logs).toMatchSnapshot(); - await fixture.cleanup(); + await cleanup(); }); }); diff --git a/test/coverage-report-missing.spec.ts b/test/coverage-report-missing.spec.ts index b98a73332..837ad6f22 100644 --- a/test/coverage-report-missing.spec.ts +++ b/test/coverage-report-missing.spec.ts @@ -6,7 +6,7 @@ describe('betterer', () => { it('should fail when the coverage report is missing', async () => { const { betterer } = await import('@betterer/betterer'); - const fixture = await createFixture('coverage-report-missing', { + const { paths, logs, cleanup, testNames } = await createFixture('coverage-report-missing', { '.betterer.js': ` import { coverageTotal } from '@betterer/coverage'; @@ -22,15 +22,15 @@ export default { ` }); - const configPaths = [fixture.paths.config]; - const resultsPath = fixture.paths.results; + const configPaths = [paths.config]; + const resultsPath = paths.results; const newTestRun = await betterer({ configPaths, resultsPath, workers: false }); - expect(fixture.testNames(newTestRun.failed)).toEqual(['test']); + expect(testNames(newTestRun.failed)).toEqual(['test']); - expect(fixture.logs).toMatchSnapshot(); + expect(logs).toMatchSnapshot(); - await fixture.cleanup(); + await cleanup(); }); }); diff --git a/test/coverage-total-include.spec.ts b/test/coverage-total-include.spec.ts new file mode 100644 index 000000000..4b4dccdcd --- /dev/null +++ b/test/coverage-total-include.spec.ts @@ -0,0 +1,144 @@ +import { describe, expect, it } from 'vitest'; + +import { createFixture } from './fixture.js'; + +describe('betterer', () => { + it('should report the total coverage for included files', async () => { + const { betterer } = await import('@betterer/betterer'); + + const { paths, logs, cleanup, resolve, readFile, testNames, writeFile } = await createFixture( + 'coverage-total-include', + { + '.betterer.js': ` +import { coverageTotal } from '@betterer/coverage'; + +export default { + test: () => coverageTotal('./my-report/coverage.json').include('**/file-1.ts') +}; + `, + 'tsconfig.json': ` +{ + "extends": "../../tsconfig.json", + "include": ["./src/**/*", "./.betterer.js"] +} + ` + } + ); + + const file1Path = resolve('./src/file-1.ts'); + const file2Path = resolve('./src/file-2.ts'); + + const coverage = ` +{ + "total": { + "lines": { "total": 220, "covered": 110, "skipped": 0, "pct": 50 }, + "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, + "functions": { "total": 30, "covered": 11, "skipped": 0, "pct": 36.6 }, + "branches": { "total": 300, "covered": 100, "skipped": 0, "pct": 33.3 } + }, + "${file1Path}": { + "lines": { "total": 100, "covered": 50, "skipped": 0, "pct": 50 }, + "statements": { "total": 200, "covered": 70, "skipped": 0, "pct": 35 }, + "functions": { "total": 20, "covered": 5, "skipped": 0, "pct": 25 }, + "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } + }, + "${file2Path}": { + "lines": { "total": 120, "covered": 60, "skipped": 0, "pct": 50 }, + "statements": { "total": 210, "covered": 70, "skipped": 0, "pct": 33.3 }, + "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, + "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } + } +} + `; + + const configPaths = [paths.config]; + const resultsPath = paths.results; + const coveragePath = resolve('./my-report/coverage.json'); + + await writeFile(coveragePath, coverage); + + const newTestRun = await betterer({ configPaths, resultsPath, workers: false }); + + expect(testNames(newTestRun.new)).toEqual(['test']); + + const newResult = await readFile(resultsPath); + + expect(newResult).toMatchSnapshot(); + + const sameTestRun = await betterer({ configPaths, resultsPath, workers: false }); + + expect(testNames(sameTestRun.same)).toEqual(['test']); + + // Included file gets better, ignored file gets worse: + const betterCoverage = ` +{ + "total": { + "lines": { "total": 220, "covered": 110, "skipped": 0, "pct": 61.9 }, + "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, + "functions": { "total": 30, "covered": 11, "skipped": 0, "pct": 36.6 }, + "branches": { "total": 300, "covered": 100, "skipped": 0, "pct": 33.3 } + }, + "${file1Path}": { + "lines": { "total": 100, "covered": 70, "skipped": 0, "pct": 50 }, + "statements": { "total": 200, "covered": 70, "skipped": 0, "pct": 35 }, + "functions": { "total": 20, "covered": 5, "skipped": 0, "pct": 25 }, + "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } + }, + "${file2Path}": { + "lines": { "total": 120, "covered": 40, "skipped": 0, "pct": 33.3 }, + "statements": { "total": 210, "covered": 70, "skipped": 0, "pct": 33.3 }, + "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, + "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } + } +} + `; + + await writeFile(coveragePath, betterCoverage); + + const betterTestRun = await betterer({ configPaths, resultsPath, workers: false }); + + expect(testNames(betterTestRun.better)).toEqual(['test']); + + const betterResult = await readFile(resultsPath); + + expect(betterResult).toMatchSnapshot(); + + // Included file gets worse, included file gets better: + const worseCoverage = ` +{ + "total": { + "lines": { "total": 220, "covered": 110, "skipped": 0, "pct": 61.9 }, + "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, + "functions": { "total": 30, "covered": 11, "skipped": 0, "pct": 36.6 }, + "branches": { "total": 300, "covered": 100, "skipped": 0, "pct": 33.3 } + }, + "${file1Path}": { + "lines": { "total": 100, "covered": 40, "skipped": 0, "pct": 40 }, + "statements": { "total": 200, "covered": 70, "skipped": 0, "pct": 35 }, + "functions": { "total": 20, "covered": 5, "skipped": 0, "pct": 25 }, + "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } + }, + "${file2Path}": { + "lines": { "total": 120, "covered": 80, "skipped": 0, "pct": 66.6 }, + "statements": { "total": 210, "covered": 70, "skipped": 0, "pct": 33.3 }, + "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, + "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } + } +} + `; + + await writeFile(coveragePath, worseCoverage); + + const worseTestRun = await betterer({ configPaths, resultsPath, workers: false }); + + expect(testNames(worseTestRun.worse)).toEqual(['test']); + + const worseResult = await readFile(resultsPath); + + expect(worseResult).toMatchSnapshot(); + + expect(logs).toMatchSnapshot(); + + await cleanup(); + }); +}); diff --git a/test/coverage-total.spec.ts b/test/coverage-total.spec.ts index a681a586a..fc942a973 100644 --- a/test/coverage-total.spec.ts +++ b/test/coverage-total.spec.ts @@ -6,12 +6,12 @@ describe('betterer', () => { it('should report the total coverage', async () => { const { betterer } = await import('@betterer/betterer'); - const fixture = await createFixture('coverage-total', { + const { paths, logs, cleanup, resolve, readFile, testNames, writeFile } = await createFixture('coverage-total', { '.betterer.js': ` import { coverageTotal } from '@betterer/coverage'; export default { - test: () => coverageTotal() + test: () => coverageTotal('./my-report/coverage.json') }; `, 'tsconfig.json': ` @@ -22,65 +22,110 @@ export default { ` }); - const coverage = `{ + const file1Path = resolve('./src/file-1.ts'); + const file2Path = resolve('./src/file-2.ts'); + + const coverage = ` +{ "total": { "lines": { "total": 220, "covered": 110, "skipped": 0, "pct": 50 }, "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, "functions": { "total": 30, "covered": 11, "skipped": 0, "pct": 36.6 }, "branches": { "total": 300, "covered": 100, "skipped": 0, "pct": 33.3 } + }, + "${file1Path}": { + "lines": { "total": 100, "covered": 50, "skipped": 0, "pct": 50 }, + "statements": { "total": 200, "covered": 70, "skipped": 0, "pct": 35 }, + "functions": { "total": 20, "covered": 5, "skipped": 0, "pct": 25 }, + "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } + }, + "${file2Path}": { + "lines": { "total": 120, "covered": 60, "skipped": 0, "pct": 50 }, + "statements": { "total": 210, "covered": 70, "skipped": 0, "pct": 33.3 }, + "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, + "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } } -}`; +} + `; - const configPaths = [fixture.paths.config]; - const resultsPath = fixture.paths.results; - const coveragePath = fixture.resolve('./coverage/coverage-summary.json'); + const configPaths = [paths.config]; + const resultsPath = paths.results; + const coveragePath = resolve('./my-report/coverage.json'); - await fixture.writeFile(coveragePath, coverage); + await writeFile(coveragePath, coverage); const newTestRun = await betterer({ configPaths, resultsPath, workers: false }); - expect(fixture.testNames(newTestRun.new)).toEqual(['test']); + expect(testNames(newTestRun.new)).toEqual(['test']); - const result = await fixture.readFile(resultsPath); + const result = await readFile(resultsPath); expect(result).toMatchSnapshot(); const sameTestRun = await betterer({ configPaths, resultsPath, workers: false }); - expect(fixture.testNames(sameTestRun.same)).toEqual(['test']); + expect(testNames(sameTestRun.same)).toEqual(['test']); - const betterCoverage = `{ - "total": { - "lines": { "total": 220, "covered": 210, "skipped": 0, "pct": 95.4 }, - "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, - "functions": { "total": 30, "covered": 11, "skipped": 0, "pct": 36.6 }, - "branches": { "total": 300, "covered": 100, "skipped": 0, "pct": 33.3 } - } - }`; + const betterCoverage = ` +{ + "total": { + "lines": { "total": 220, "covered": 210, "skipped": 0, "pct": 95.4 }, + "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, + "functions": { "total": 30, "covered": 11, "skipped": 0, "pct": 36.6 }, + "branches": { "total": 300, "covered": 100, "skipped": 0, "pct": 33.3 } + }, + "${file1Path}": { + "lines": { "total": 100, "covered": 100, "skipped": 0, "pct": 100 }, + "statements": { "total": 200, "covered": 70, "skipped": 0, "pct": 35 }, + "functions": { "total": 20, "covered": 5, "skipped": 0, "pct": 25 }, + "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } + }, + "${file2Path}": { + "lines": { "total": 120, "covered": 110, "skipped": 0, "pct": 91.6 }, + "statements": { "total": 210, "covered": 70, "skipped": 0, "pct": 33.3 }, + "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, + "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } + } +} + `; - await fixture.writeFile(coveragePath, betterCoverage); + await writeFile(coveragePath, betterCoverage); const betterTestRun = await betterer({ configPaths, resultsPath, workers: false }); - expect(fixture.testNames(betterTestRun.better)).toEqual(['test']); + expect(testNames(betterTestRun.better)).toEqual(['test']); - const worseCoverage = `{ - "total": { - "lines": { "total": 220, "covered": 210, "skipped": 0, "pct": 95.4 }, - "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, - "functions": { "total": 30, "covered": 11, "skipped": 0, "pct": 36.6 }, - "branches": { "total": 300, "covered":90, "skipped": 0, "pct": 30 } - } - }`; + const worseCoverage = ` +{ + "total": { + "lines": { "total": 220, "covered": 210, "skipped": 0, "pct": 95.4 }, + "statements": { "total": 410, "covered": 140, "skipped": 0, "pct": 34.1 }, + "functions": { "total": 30, "covered": 11, "skipped": 0, "pct": 36.6 }, + "branches": { "total": 300, "covered": 90, "skipped": 0, "pct": 30 } + }, + "${file1Path}": { + "lines": { "total": 100, "covered": 100, "skipped": 0, "pct": 100 }, + "statements": { "total": 200, "covered": 70, "skipped": 0, "pct": 35 }, + "functions": { "total": 20, "covered": 5, "skipped": 0, "pct": 25 }, + "branches": { "total": 150, "covered": 40, "skipped": 0, "pct": 26.6 } + }, + "${file2Path}": { + "lines": { "total": 120, "covered": 110, "skipped": 0, "pct": 91.6 }, + "statements": { "total": 210, "covered": 70, "skipped": 0, "pct": 33.3 }, + "functions": { "total": 10, "covered": 6, "skipped": 0, "pct": 60 }, + "branches": { "total": 150, "covered": 50, "skipped": 0, "pct": 33.3 } + } +} + `; - await fixture.writeFile(coveragePath, worseCoverage); + await writeFile(coveragePath, worseCoverage); const worseTestRun = await betterer({ configPaths, resultsPath, workers: false }); - expect(fixture.testNames(worseTestRun.worse)).toEqual(['test']); + expect(testNames(worseTestRun.worse)).toEqual(['test']); - expect(fixture.logs).toMatchSnapshot(); + expect(logs).toMatchSnapshot(); - await fixture.cleanup(); + await cleanup(); }); }); diff --git a/website/docs/coverage-test.md b/website/docs/coverage-test.md index ed2870fc3..18502ef8f 100644 --- a/website/docs/coverage-test.md +++ b/website/docs/coverage-test.md @@ -10,22 +10,29 @@ slug: /coverage-test Use the `coverage` test to incrementally increase the per-file test coverage of your project. +:::caution + [`@betterer/coverage`](https://www.npmjs.com/package/@betterer/coverage) expects an [Istanbul](https://istanbul.js.org/) [json-summary](https://github.com/istanbuljs/istanbuljs/tree/master/packages/istanbul-reports/lib/json-summary) to exist, so you must run your tests first. +::: + +By default, `coverage()` looks for the summary at `'./coverage/coverage-summary.json'`, but you can pass the path to wherever yours is located, relative to your [test definition file](./test-definition-file). ```typescript import { coverage } from '@betterer/coverage'; export default { - 'increase per-file test coverage': () => coverage() + 'increase per-file test coverage': () => coverage('./my-reports/coverage.json') }; ``` Use the `coverageTotal` test to incrementally increase the total test coverage of your project. -```javascript +```typescript import { coverageTotal } from '@betterer/coverage'; export default { 'increase total test coverage': () => coverageTotal() }; ``` + +[`@betterer/coverage`](https://www.npmjs.com/package/@betterer/coverage) is a [BettererResolverTest](./betterer.bettererresolvertest), so you can use [`include`](./betterer.bettererresolvertest.include), [`exclude`](./betterer.bettererresolvertest.exclude), [`only`](betterer.bettererresolvertest.only), and [`skip`](betterer.bettererresolvertest.skip).