From 50492883e94db8435c04d795b511343929384942 Mon Sep 17 00:00:00 2001 From: Justin Stayton Date: Thu, 27 Aug 2026 12:06:13 -0400 Subject: [PATCH] Report test coverage in the CI run summary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `npm test` runs `node --test` with no coverage flags, so seeing coverage meant passing `--experimental-test-coverage` by hand. A separate `Test coverage` job now posts the report to the run summary and uploads `coverage/lcov.info` as an artifact, following the same shape as vision-download. There's no threshold — coverage is reported, not enforced. Node's built-in coverage plus the `lcov` reporter keep this dependency-free. `set -o pipefail` is load-bearing in that step: `npm run test:coverage | tee` otherwise returns tee's exit status, so the job would pass on a failing suite. `pretest:coverage` creates `coverage/` because the lcov reporter exits rather than creating it. Co-Authored-By: Claude Opus 5 --- .github/workflows/ci.yml | 31 +++++++++++++++++++++++++++++++ .gitignore | 3 +++ AGENTS.md | 4 ++++ package.json | 2 ++ 4 files changed, 40 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 82bb918..cab502a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,3 +29,34 @@ jobs: run: npm run typecheck - name: Run tests run: npm test + + test-coverage: + name: Test coverage + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - name: Set up Node.js + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 + with: + node-version: '26.x' + cache: 'npm' + - name: Install npm dependencies + run: npm install + - name: Report coverage + run: | + set -o pipefail + npm run test:coverage | tee "$RUNNER_TEMP/coverage.txt" + { + echo '## Test coverage' + echo + echo '```' + awk '/start of coverage report/{f=1;next} /end of coverage report/{f=0} f' "$RUNNER_TEMP/coverage.txt" | sed 's/^ℹ //' + echo '```' + } >> "$GITHUB_STEP_SUMMARY" + - name: Upload coverage report + if: ${{ !cancelled() }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: coverage + path: coverage/ diff --git a/.gitignore b/.gitignore index 3055d78..94947f7 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ # JSDoc /docs + +# Test coverage +/coverage diff --git a/AGENTS.md b/AGENTS.md index 934cba3..179c102 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,6 +8,10 @@ code in this repository. - `npm test` — run the test suite (uses Node's built-in `node --test` runner; tests live next to source as `*.test.js`). - `npm test -- --watch` — re-run tests on file change. +- `npm run test:coverage` — run the suite with coverage, printing a report and + writing `coverage/lcov.info`. CI runs this in a separate job that posts the + report to the run summary and uploads it as an artifact. There is no + threshold: coverage is reported, not enforced. - `node --test src/main.test.js` — run a single test file. Add `--test-name-pattern ''` to filter by test name. - `npm run lint` — Prettier format check + ESLint. `npm run lint:format:fix` and diff --git a/package.json b/package.json index de25356..4b5ba99 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,10 @@ "lint:format:fix": "prettier --write .", "lint:quality": "eslint .", "lint:quality:fix": "eslint --fix .", + "pretest:coverage": "node -e \"require('node:fs').mkdirSync('coverage', { recursive: true })\"", "release": "release-it --only-version", "test": "node --test", + "test:coverage": "node --test --experimental-test-coverage --test-reporter=spec --test-reporter-destination=stdout --test-reporter=lcov --test-reporter-destination=coverage/lcov.info", "typecheck": "tsc" }, "devDependencies": {