Spirolo

Reading a report

What each line of `spirolo check` means, on a real run.

This is the unedited output of spirolo check on react-day-picker at commit 19033b4:

$ spirolo check
904 files · 223 test files · 938 tests (938 jest) · 1268 expects · 0 handlers · 4 configs · 82ms
Health C (61)

── Weak tests (audit) ────────────────────────────────────────

● absence-anchor (2 files) · advisory: 16/20 (UNADJUDICATED)
  examples/Disabled.test.tsx:21 test "should not display the previous button" asserts only that DOM is absent with no anchor (not.toBeInTheDocument)
  examples/ModifiersHidden.test.tsx:16 test "the day %s should be hidden" asserts only that DOM is absent with no anchor (not.toBeInTheDocument)
  A render test asserts only that things are absent from the DOM, with no positive assertion proving the render happened at all. · spirolo explain absence-anchor
  To gate it: .spirolorc.jsonc { "rules": { "absence-anchor": { "severity": "warn" } } } · to accept today's rows: spirolo ratchet

── Merge gate (gate) ────────────────────────────────────────

● fail-closed-setup (1 file, 2 findings) · advisory: 19/19 (UNADJUDICATED)
  jest.config.ts (2)
    :0 setup does not guard the console (no throwing console.error/warn spy or fail-on-console package)
    :0 setup does not restore mocks between tests (no restoreMocks or afterEach restoreAllMocks)
  The runner's setup misses an invariant (unhandled requests error, a console guard, mock reset, a global server) that makes a broken test fail. · spirolo explain fail-closed-setup
  To gate it: .spirolorc.jsonc { "rules": { "fail-closed-setup": { "severity": "warn" } } } · to accept today's rows: spirolo ratchet

● dead-skip (1 file, 2 findings) · 1 info · 1 listed · advisory: 18/18 (INSUFFICIENT)
  packages/ethiopic/src/ethiopic/lib/endOfWeek.test.ts (2)
    :1 todo "should return the correct end of the week date for a given date": unconditional · listed
    :1 todo "should return the correct end of the week date for a given date" has no linked issue
  A skipped or focused test disagrees with the suite that is believed to run, with no linked issue or visible condition watching it. · spirolo explain dead-skip
  To gate it: .spirolorc.jsonc { "rules": { "dead-skip": { "severity": "warn" } } } · to accept today's rows: spirolo ratchet

── Unused tests (hygiene) ────────────────────────────────────────

● duplicate-test (2 files) · advisory: 15/18 (UNADJUDICATED)
  examples/Input.test.tsx:26 updates the calendar when a date is typed in duplicates 1 other test
  packages/react-day-picker/src/helpers/getNavMonth.test.ts:95 when "captionLayout" is "dropdown-months" › "startMonth" should be undefined duplicates 1 other test
  Two tests with different names have bodies that normalise to the same code, so one of them adds nothing. · spirolo explain duplicate-test
  To gate it: .spirolorc.jsonc { "rules": { "duplicate-test": { "severity": "warn" } } } · to accept today's rows: spirolo ratchet

✓ 8 rules found nothing: handler-drift, generator-walk, data-layer-mock, redundant-test, unused-mock, orphan-test, stale-snapshot, flake-observed

7 findings in 4 of 16 rules · 0 warn · 0 error · 7 info · 1 listed · exit 0
 hidden 227 findings: 222 experimental (gate-truth 1, flake-candidate 1, untested-hotspot 220), 5 from DROPPED or FAIL rules (weak-assertion 5); spirolo check --all shows them
 note   no churn input: untested-hotspot ranks by complexity × weakness alone. Save `git log --numstat --format= --since=180.days` to a file and pass it with `--churn <file>` or name it in `inputs.churn`

The header

The first line counts what the graph holds: files, test files, tests per runner, expect calls, MSW or nock handlers, runner configs, and how long the pass took.

Health C (61) is a provisional score out of 100. Each family takes off points for the share of its subjects that have findings, up to a cap per family. Rules outside the default view count half. The score is a summary to watch over time: nothing gates on it, and machine formats do not carry it.

Families and rules

Findings are grouped under one banner per family: Weak tests (audit), Merge gate (gate), Unused tests (hygiene) and Flaky (flake). Under each banner, each rule appears once:

● dead-skip (1 file, 2 findings) · 1 info · 1 listed · advisory: 18/18 (INSUFFICIENT)
  • the rule and how many files and findings it has;
  • the severity counts. listed rows are context that never counts as a finding;
  • the trust label: advisory is the tier, 18/18 means 18 of its 18 decided corpus findings were true, and INSUFFICIENT is its verdict (not enough decided to call it proven). How far to trust a finding explains each part.

Then the rows, file by file, with line numbers. A :0 row is about the whole file or config. The last two lines of each rule state what it claims and how to make it gate.

The closing lines

7 findings in 4 of 16 rules · 0 warn · 0 error · 7 info · 1 listed · exit 0
 hidden 227 findings: 222 experimental (...), 5 from DROPPED or FAIL rules (...); spirolo check --all shows them

The summary counts what was shown and gives the exit code. The hidden line counts the findings of rules the default view leaves out: experimental rules, and rules whose measurement failed or that were dropped. spirolo check --all shows them, each labelled.

A note line flags missing input. Here, without a churn file, untested-hotspot ranks modules by complexity and test weakness alone.

Caps

Long sections are capped by files and rows, and end with … and N more files and the command that lifts the cap: spirolo check --rule <rule> --all.

On this page