Skip to content

Check 4 — CI test coverage

Question: can a change land without the tests that cover it running in CI? Inputs: workspace.json (ciFiles), scan.json. Output: findings/ci-coverage.json.

id severity detect
ci-coverage/undeclared-workspace-dependency critical (medium when Nx is an orchestrator, since Nx infers edges from imports) scan.imports entry with declared: false, isTest: false and fromSource: "package.json". Affected/filtered runs and ^ caching won’t treat the importer as depending on the target, so changing the target skips the importer’s tests. One finding per (from, target) pair.
ci-coverage/missing-test-script high package has scan.packages[p].testFiles.length > 0 but no package-level test entry point is covered. Accept test, e2e, or test:* package scripts; an Nx test target; inferred Nx test plugins (@nx/vite/plugin, @nx/jest/plugin, @nx/vitest); root vitest.workspace.* / root vitest.config.* test.projects or root Jest projects, counted only when one of its project roots or globs matches the package’s dir; or a root test script whose globs explicitly include the package path. Do not treat pnpm -r test, npm --workspaces test, or similar recursive root scripts as coverage for packages without their own test script (generic-pnpm deliberately still flags @acme/app).
ci-coverage/tests-not-run-in-ci high at least one CI file exists, but no job that runs before a change can land (triggered by pull_request/merge_group or the CI system’s equivalent, or by push only when its branch filter shows it runs before landing, e.g. unfiltered or matching feature/topic branches — push limited to the protected default branch, scheduled-only, or manual-only workflows don’t count) has a step matching /\b(npm|pnpm|yarn|bun|npx|nx|turbo)\b[^\n]*\btest\b|\b(vitest|jest|mocha)\b|\b(make|task|just)\s+test\b/ (each | is a Markdown table escape for a regex alternation bar). If ciFiles is empty, set this check status to partial with reason no CI configuration found and emit no tests-not-run-in-ci finding.
ci-coverage/shallow-checkout-affected high an affected/filtered CI job lacks full base history. GitHub Actions: job runs nx affected, turbo … --affected, or --filter=…[<ref>], uses actions/checkout, and does not set fetch-depth: 0. GitLab: affected logic is used while GIT_DEPTH is unset/nonzero (default 20) or the MR target branch is not fetched. Azure: checkout: self lacks fetchDepth: 0. Bitbucket: clone: depth is set while affected logic is used.
ci-coverage/nx-affected-base-missing high nx affected in CI with no --base, no nrwl/nx-set-shas step, no NX_BASE env, and no nx.json#defaultBase.
ci-coverage/nx-test-inputs-ignore-deps high Nx test target (targetDefaults or project) is cacheable and explicitly sets inputs with no ^ dependency entry after resolving named inputs. Omitted inputs are ok because Nx defaults to default + ^default.
ci-coverage/turbo-test-missing-dependson high Turbo test (or *:test) task is cacheable and its dependsOn graph has no transitive ^ entry. Follow local task indirections such as "transit": { "dependsOn": ["^transit"] }, "test": { "dependsOn": ["transit"] }; that pattern satisfies the rule.
  1. Read every file in ciFiles. Also follow GitLab include: entries that point to local files and local reusable GitHub workflows referenced with uses: ./.github/workflows/x.yml. For GitHub Actions, reason per job: a checkout step’s with.fetch-depth applies to the steps after it in the same job. If there are no CI files, write status: "partial", reason: "no CI configuration found", and do not emit ci-coverage/tests-not-run-in-ci.
  2. Resolve Nx targets as in caching (targetDefaults merged with project config). Resolve Turbo tasks from turbo.json/pipeline and package overrides.
  3. Apply the rules; quote the CI step / config object as evidence.
  4. Write findings/ci-coverage.json.
  • undeclared-workspace-dependency: add "<target>": "workspace:*" (pnpm/yarn/bun) or "*" (npm) to the importer’s dependencies, and import via the package name.
  • shallow-checkout-affected: with: { fetch-depth: 0 } on actions/checkout.
  • nx-affected-base-missing: add - uses: nrwl/nx-set-shas@v4 before nx affected.
  • nx-test-inputs-ignore-deps: "test": { "inputs": ["default", "^production"] }.
  • turbo-test-missing-dependson: "test": { "dependsOn": ["^build"] } (or ["^test"] when tests run on sources).