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. |
- Read every file in
ciFiles. Also follow GitLabinclude:entries that point to local files and local reusable GitHub workflows referenced withuses: ./.github/workflows/x.yml. For GitHub Actions, reason per job: a checkout step’swith.fetch-depthapplies to the steps after it in the same job. If there are no CI files, writestatus: "partial",reason: "no CI configuration found", and do not emitci-coverage/tests-not-run-in-ci. - Resolve Nx targets as in caching (targetDefaults merged with project config). Resolve Turbo tasks from
turbo.json/pipelineand package overrides. - Apply the rules; quote the CI step / config object as
evidence. - Write
findings/ci-coverage.json.
Fix guidance
Section titled “Fix guidance”- 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 }onactions/checkout. - nx-affected-base-missing: add
- uses: nrwl/nx-set-shas@v4beforenx affected. - nx-test-inputs-ignore-deps:
"test": { "inputs": ["default", "^production"] }. - turbo-test-missing-dependson:
"test": { "dependsOn": ["^build"] }(or["^test"]when tests run on sources).