From 76e116ef54fb160e94ce98df3a17ca527550b873 Mon Sep 17 00:00:00 2001 From: Michele Palamidessi <11261708+Palaxx@users.noreply.github.com> Date: Mon, 22 Apr 2024 14:47:56 +0200 Subject: [PATCH] Introduce c8 check coverage (#25) * test: check-coverage params * feat: enable thresholds params * docs: add check-coverage info in README.md --- README.md | 26 ++++++---- borp.js | 17 ++++++- fixtures/ts-esm-check-coverage/src/math.ts | 8 ++++ .../ts-esm-check-coverage/test/add.test.ts | 7 +++ fixtures/ts-esm-check-coverage/tsconfig.json | 24 ++++++++++ test/coverage.test.js | 48 ++++++++++++++++++- 6 files changed, 119 insertions(+), 11 deletions(-) create mode 100644 fixtures/ts-esm-check-coverage/src/math.ts create mode 100644 fixtures/ts-esm-check-coverage/test/add.test.ts create mode 100644 fixtures/ts-esm-check-coverage/tsconfig.json diff --git a/README.md b/README.md index 560d8e5..e3a8dda 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,9 @@ npm i borp --save-dev ```bash borp --coverage + +# with check coverage active +borp --coverage --check-coverage --lines 95 ``` Borp will automatically run all tests files matching `*.test.{js|ts}`. @@ -25,30 +28,30 @@ Borp will automatically run all tests files matching `*.test.{js|ts}`. . ├── src │   ├── lib -│   │   └── add.ts +│   │   └── math.ts │   └── test -│   └── add.test.ts +│   └── math.test.ts └── tsconfig.json ``` -As an example, consider having a `src/lib/add.ts` file +As an example, consider having a `src/lib/math.ts` file ```typescript -export function add (x: number, y: number): number { +export function math (x: number, y: number): number { return x + y } ``` -and a `src/test/add.test.ts` file: +and a `src/test/math.test.ts` file: ```typescript import { test } from 'node:test' -import { add } from '../lib/add.js' +import { math } from '../lib/math.js' import { strictEqual } from 'node:assert' -test('add', () => { - strictEqual(add(1, 2), 3) +test('math', () => { + strictEqual(math(1, 2), 3) }) ``` @@ -97,7 +100,12 @@ Note the use of `incremental: true`, which speed up compilation massively. * `--reporter` or `-r`, set up a reporter, use a colon to set a file destination. Default: `spec`. * `--no-typescript` or `-T`, disable automatic TypeScript compilation if `tsconfig.json` is found. * `--post-compile` or `-P`, the path to a file that will be executed after each typescript compilation. - +* `--check-coverage`, enables c8 check coverage; default is false +### Check coverage options +* `--lines`, set the lines threshold when check coverage is active; default is 100 +* `--functions`, set the functions threshold when check coverage is active; default is 100 +* `--statements`, set the statements threshold when check coverage is active; default is 100 +* `--branches`, set the branches threshold when check coverage is active; default is 100 ## Reporters Here are the available reporters: diff --git a/borp.js b/borp.js index 5a91a54..6bfa37a 100755 --- a/borp.js +++ b/borp.js @@ -10,6 +10,7 @@ import posix from 'node:path/posix' import runWithTypeScript from './lib/run.js' import githubReporter from '@reporters/github' import { Report } from 'c8' +import { checkCoverages } from 'c8/lib/commands/check-coverage.js' import os from 'node:os' import { execa } from 'execa' @@ -39,7 +40,12 @@ const args = parseArgs({ short: 'r', default: ['spec'], multiple: true - } + }, + 'check-coverage': { type: 'boolean' }, + lines: { type: 'string', default: '100' }, + branches: { type: 'string', default: '100' }, + functions: { type: 'string', default: '100' }, + statements: { type: 'string', default: '100' } }, allowPositionals: true }) @@ -136,6 +142,15 @@ try { exclude }) + if (args.values['check-coverage']) { + await checkCoverages({ + lines: parseInt(args.values.lines), + functions: parseInt(args.values.functions), + branches: parseInt(args.values.branches), + statements: parseInt(args.values.statements), + ...args + }, report) + } await report.run() } /* c8 ignore next 3 */ diff --git a/fixtures/ts-esm-check-coverage/src/math.ts b/fixtures/ts-esm-check-coverage/src/math.ts new file mode 100644 index 0000000..953f2cc --- /dev/null +++ b/fixtures/ts-esm-check-coverage/src/math.ts @@ -0,0 +1,8 @@ + +export function add (x: number, y: number): number { + return x + y +} + +export function sub (x: number, y: number): number { + return x - y +} diff --git a/fixtures/ts-esm-check-coverage/test/add.test.ts b/fixtures/ts-esm-check-coverage/test/add.test.ts new file mode 100644 index 0000000..5c02452 --- /dev/null +++ b/fixtures/ts-esm-check-coverage/test/add.test.ts @@ -0,0 +1,7 @@ +import { test } from 'node:test' +import { add } from '../src/math.js' +import { strictEqual } from 'node:assert' + +test('add', () => { + strictEqual(add(1, 2), 3) +}) diff --git a/fixtures/ts-esm-check-coverage/tsconfig.json b/fixtures/ts-esm-check-coverage/tsconfig.json new file mode 100644 index 0000000..52f28e3 --- /dev/null +++ b/fixtures/ts-esm-check-coverage/tsconfig.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "outDir": "dist", + "sourceMap": true, + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "esModuleInterop": true, + "strict": true, + "resolveJsonModule": true, + "removeComments": true, + "newLine": "lf", + "noUnusedLocals": true, + "noFallthroughCasesInSwitch": true, + "isolatedModules": true, + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true, + "lib": [ + "ESNext" + ], + "incremental": true + } +} diff --git a/test/coverage.test.js b/test/coverage.test.js index 8d763c1..dbc210f 100644 --- a/test/coverage.test.js +++ b/test/coverage.test.js @@ -1,5 +1,5 @@ import { test } from 'node:test' -import { match, doesNotMatch } from 'node:assert' +import { match, doesNotMatch, fail, equal, AssertionError } from 'node:assert' import { execa } from 'execa' import { join } from 'desm' @@ -35,3 +35,49 @@ test('coverage excludes', async () => { match(res.stdout, /add\.test\.ts/) match(res.stdout, /add2\.test\.ts/) }) + +test('borp should return right error when check coverage is active with default thresholds', async (t) => { + try { + await execa('node', [ + borp, + '--coverage', + '--check-coverage' + ], { + cwd: join(import.meta.url, '..', 'fixtures', 'ts-esm-check-coverage') + }) + fail('Should not complete borp without error') + } catch (e) { + if (e instanceof AssertionError) { + throw e + } + + equal(e.exitCode, 1) + match(e.stderr, /ERROR: Coverage for lines \(75%\) does not meet global threshold \(100%\)/) + match(e.stderr, /ERROR: Coverage for functions \(50%\) does not meet global threshold \(100%\)/) + match(e.stderr, /ERROR: Coverage for statements \(75%\) does not meet global threshold \(100%\)/) + } +}) + +test('borp should return right error when check coverage is active with defined thresholds', async (t) => { + try { + await execa('node', [ + borp, + '--coverage', + '--check-coverage', + '--lines=80', + '--functions=50', + '--statements=0', + '--branches=100' + ], { + cwd: join(import.meta.url, '..', 'fixtures', 'ts-esm-check-coverage') + }) + fail('Should not complete borp without error') + } catch (e) { + if (e instanceof AssertionError) { + throw e + } + + equal(e.exitCode, 1) + match(e.stderr, /ERROR: Coverage for lines \(75%\) does not meet global threshold \(80%\)/) + } +})