Skip to main content

eslint-plugin-test-signal

eslint-plugin-test-signal reports tests that look green while proving too little about behavior.

The first rule set focuses on common weak-test signals:

  • tests whose only assertion is a snapshot;
  • tests whose only assertion inspects mock call metadata;
  • assertions whose subject is a static constant;
  • broad existence assertions that do not verify expected shape or value;
  • assertions that compare a value to itself;
  • vacuous whole-value asymmetric assertions;
  • length assertions that only prove length is non-negative;
  • fixed real-time waits that make tests slow or flaky;
  • synthetic Promise assertions that do not exercise code under test;
  • string and numeric assertions with vacuous expected values;
  • broad object key-count assertions that only prove non-emptiness;
  • duplicate assertion chains in the same test;
  • Promise assertions that are not awaited or returned;
  • async tests that contain no assertion;
  • suites that have no negative-path coverage signal.

Design scopeโ€‹

The plugin uses syntax-level heuristics that work across Vitest, Jest-style APIs, and @typescript-eslint/rule-tester suites. It intentionally avoids type checker work because the targeted patterns are visible directly in the test AST.

Presetsโ€‹

  • testSignal.configs.minimal enables the lowest-noise correctness rules.
  • testSignal.configs.recommended adds weak assertion signal detection, including snapshot-only, mock-call-only, constant-subject, and broad existence assertions.
  • testSignal.configs["recommended-type-checked"] currently matches recommended because no shipped rule requires parser services yet.
  • testSignal.configs.strict adds negative-path coverage enforcement.
  • testSignal.configs.all enables every stable rule.
  • testSignal.configs.experimental is reserved for future candidate rules and currently matches all.

Rule referenceโ€‹

RulePurpose
no-empty-async-testsFlags async tests without assertions.
require-awaited-async-assertionsFlags floating .resolves and .rejects assertions.
no-snapshot-only-testsFlags tests whose only assertions are snapshots.
no-mock-call-only-testsFlags tests whose only assertions inspect mock calls.
no-constant-assertionsFlags assertions whose subject is a static constant.
no-weak-existence-assertionsFlags broad existence assertions such as toBeDefined().
no-identical-expected-actualFlags assertions that compare a value to itself.
no-weak-asymmetric-assertionsFlags vacuous whole-value asymmetric assertions.
no-tautological-length-assertionsFlags length assertions that only prove length is non-negative.
no-fixed-delay-testsFlags fixed real-time delays in executable tests.
no-synthetic-promise-assertionsFlags .resolves and .rejects assertions against synthetic Promise values.
no-vacuous-string-assertionsFlags string assertions with expected values that match anything.
no-vacuous-numeric-assertionsFlags numeric bound assertions with infinite thresholds.
no-broad-object-key-count-assertionsFlags object key-count assertions that only prove an object is non-empty.
no-duplicate-assertionsFlags repeated identical assertion chains in the same test.
require-negative-pathFlags test scopes without negative-path coverage signals.