Skip to content

ci: fail when a checked-in test file has no runner - #33080

Merged
nwparker merged 7 commits into
mainfrom
nwparker/ci-test-file-selection
Oct 24, 2026
Merged

nwparker merged 7 commits into
mainfrom
nwparker/ci-test-file-selection

Conversation

@nwparker

@nwparker nwparker commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 3 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​105 $\color{#cf222e}{\Huge{\mathbf{−}}}$​2 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​103
Prod 10 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​329 $\color{#cf222e}{\Huge{\mathbf{−}}}$​10 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​319

ELI5

Some checked-in test files were never run by anything, so they could break without anyone noticing. This change wires those files back into a runner. It also adds a CI check that fails whenever a test file exists that no runner picks up.

What Changed

Before: four test files and one benchmark config had no working runner.

  • .github/actions/cloud-sql-rollout-lease/{action-contract,storage-lease}.test.mjs: 16 node:test cases. Move Relay deployment configuration into private cloud operations #31792 dropped them from cloud pretest.
  • src/renderer/src/components/editor/monaco-content-sync{,.undo-retention}.bench.ts: Vitest benchmark files. Nothing ran vitest bench, and vitest run refuses the bench fixture.
  • config/vitest.agent-status-benchmark.config.ts: it inherited the unit projects, whose includes override its own. So it ran all 13.5k unit files and never the benchmark.

The src/**/*.spec.ts(x) files, such as the AutomationsPage.*.spec.tsx cases, already run. They are suite modules that a *.test.* entry imports (for example, AutomationsPage.behavior.test.tsx runs all 35 of those cases). So this change does not add *.spec.* to UNIT_INCLUDE; doing so would run each suite twice and without its entry's setup.

After:

  • The lease tests run in cloud test:runner. The glob is quoted so it also works under cmd.exe.
  • pnpm test:perf:benchmarks (vitest bench --run with benchmark.include in the performance config) runs the monaco benchmarks. They stay manual, because their wall-clock budgets have never run on a CI runner.
  • The agent-status benchmark config clears projects, so it now selects only its file.
  • New static-job step node config/scripts/check-test-file-runners.mjs (also in pnpm lint). It finds every tracked file that is test-like, meaning a test-style name or a test-framework import plus a test registration. It fails unless a runner in its table collects the file, or a collected file imports it at runtime. Details:
    • Runtime imports come from ts.transpileModule output. That erases type-only and unused imports the same way Vitest's transform does.
    • Each import resolves to the single file Vite would load.
    • The unit row subtracts UNIT_EXCLUDE. Each excluded file must be named in pr.yml or unit-tests.yml.
    • Each non-unit row lists the literal include strings its config must still contain, so editing a runner's include fails the check.
    • Manual-only rows (the two benchmark sets) are printed on every run.
  • Cloud-only diffs that touch code or a package.json now run the static job (isCloudTestRunnerInput). Without this, an orphaned cloud test could land green.

Why

A test that no runner collects passes vacuously, and nothing reports it. The check uses a declared runner table plus a runtime-import walk. The alternatives were weaker or too slow:

  • Adding *.spec.* to the include would double-run the suite modules.
  • vitest list for every config is too slow, and needs mobile and cloud installs, which the static job doesn't have.
  • Reusing ci-unit-dependency-graph was tried first. It deliberately keeps every plausible resolution candidate and type-only edge, so it cannot prove that a suite runs.

Linked Issue

N/A. This is an internal CI gap found during review, with no issue filed.

Visual Proof

N/A: CI-only change, no UI.

Testing

  • I manually tested these changes locally

  • Automated tests added/updated, or explained why not below

  • node config/scripts/check-test-file-runners.mjs passes on this branch, in about 15–20s under load. With the new runner rows removed, it lists exactly the four orphaned files above.

  • config/scripts/check-test-file-runners.test.mjs covers:

    • name-agnostic detection;
    • UNIT_EXCLUDE with within;
    • suite modules collected only through runtime imports (type-only, inline type, typeof import() and type-position-only imports don't count; competing .ts/.tsx twins);
    • runner drift;
    • cloud routing.
  • node --test on the lease tests passes 16/16. cloud pnpm test:runner passes 32.

  • pnpm test:perf:benchmarks passes. Two adjustments were needed:

    • The 50 MiB case got an explicit 180s timeout, because the budget is its p95, not its total.
    • The read-only undo-retention check now asserts a process-wide arrayBuffers delta under 1 MiB instead of exactly 0. I observed −45 bytes, against 104,857,529 bytes for the undoable arm.
  • vitest list --filesOnly --config config/vitest.agent-status-benchmark.config.ts now lists only the benchmark.

  • The full static job passes locally (lint, format, anti-slop, code-quality, tc, ratchets, generators). So do pr-code-change-scope, pr-preflight-gates and the other routing tests.

  • Platforms: macOS locally. The glob quoting was checked for sh and cmd.exe.

Review

Agent skill upstream boundary

  • Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

  • Not run in CI: the monaco and agent-status benchmarks, which are manual by design and printed by the check.
  • .github/actions/cloud-sql-rollout-lease is no longer used by any workflow here. It may be worth removing separately.
  • Static-job routing now includes cloud code edits, which costs some CI time on cloud-only PRs.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

Two node:test files under .github/actions lost their runner when #31792
trimmed cloud pretest, and the two monaco .bench.ts budgets were never run
by any CI job. Wire both back in and add a static check that every
test-like file is collected by a declared runner or imported by a
collected entry (the src .spec.* suite-module convention).
…dits

Type-only imports are now dropped with the TypeScript parser, so a type
alias before a runtime re-export no longer hides it. UNIT_EXCLUDE files
must be named by a pr.yml or unit-tests.yml step. A cloud-only diff that
adds a test or edits a runner config now runs the static job. The monaco
benchmarks stay manual (pnpm test:perf:benchmarks) until a CI runner
proves their wall-clock budgets.
The unit dependency graph keeps every plausible candidate so it can
invalidate conservatively, which cannot prove a suite runs: an import of
./case.spec counted both case.spec.ts and case.spec.tsx. Resolve with
Vite's extension order instead.
Imports used only as types are erased without a type modifier, so
parsing for type-only syntax still followed them. Derive edges from
ts.transpileModule output, which erases what Vitest's transform erases,
and only transpile files that can reach an uncollected candidate.
The agent-status benchmark config inherited the unit projects, whose
includes override its own, so it ran the whole unit suite and never the
benchmark. Clear projects as the performance config does. Route every
cloud code file to the static job, since content-detected tests can have
any name.
@nwparker
nwparker requested a review from Jinwoo-H as a code owner October 24, 2026 07:36
@coderabbitai

coderabbitai Bot commented Oct 24, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 4 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 7ce08e0c-e35f-44ab-9034-6c4c2f155776
Commits

Reviewing files that changed from the base of the PR and between 06211d1 and 466d89c.

Files selected for processing: 13
  • .github/workflows/pr.yml
  • cloud/package.json
  • config/scripts/check-test-file-runners.mjs
  • config/scripts/check-test-file-runners.test.mjs
  • config/scripts/pr-code-change-scope.mjs
  • config/scripts/pr-code-change-scope.test.mjs
  • config/scripts/pr-package-test-paths.mjs
  • config/scripts/pr-preflight-gates.test.mjs
  • config/vitest.agent-status-benchmark.config.ts
  • config/vitest.performance.config.ts
  • package.json
  • src/renderer/src/components/editor/monaco-content-sync.bench.ts
  • src/renderer/src/components/editor/monaco-content-sync.undo-retention.bench.ts
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@nwparker
nwparker merged commit 24069f0 into main Oct 24, 2026
65 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant