@systemfsoftware/oxlint-plugin-property-testing
v2.0.2
Published
Oxlint rules enforcing the property-testing contract: it.prop / it.effect.prop predicates return a boolean on every path, never assert/expect, and never run through raw fc.assert.
Maintainers
Readme
@systemfsoftware/oxlint-plugin-property-testing
Enforce the property-testing contract:
it.prop/it.effect.proppredicates return a boolean on every path, never callexpect/assert, and live only in*.property.test.tsfiles.
fast-check counts undefined as success — a bare return;, a non-boolean return, or falling off the end of a predicate is a silent pass wearing a green checkmark. These rules make the silent failure modes loud.
Rules
| Rule | What it enforces |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| no-silent-return | Every code path of an it.prop / it.effect.prop predicate (including Effect.gen generator bodies) ends in return <boolean>. Flags bare return;, missing returns, and provably non-boolean returns. |
| no-assert-in-property | No expect(...), assert*(...), or raw fc.assert/fc.check inside a property predicate. The boolean return IS the verdict. assert* stays correct in normal tests. |
| property-file-purity | Property tests live ONLY in *.property.test.ts files (no plain it()/it.effect() or raw fc.assert there), and every other test file contains no FastCheck imports and no it.prop / it.effect.prop calls. The two never mix. |
| no-nested-quantification | A property predicate must not quantify over its own generated value and call out again inside that loop — per-case cost then scales with the drawn size rather than the draw count, and a budget tuned on small draws times out on large ones. Iteration over a bound the generator does not control, and a fold whose body calls nothing, stay silent, as do basenames in the exempt option. |
| prop-fixture-schema-origin | Inside an import.meta.vitest in-source block or a *.test.ts file, a recursive schema union must enter through a named local builder or an imported helper, or its recursion point must declare its generation with a visible toCodecArbitrary derivation or recursionBudget ceiling. An inline hand-rolled recursive union reports; outside test scope the rule is silent, because production schemas are the derivation-cost rule's domain. |
Install
pnpm add -D @systemfsoftware/oxlint-plugin-property-testing// oxlint.config.ts
import { defineConfig } from 'oxlint'
export default defineConfig({
jsPlugins: ['@systemfsoftware/oxlint-plugin-property-testing'],
rules: {
'@systemfsoftware/oxlint-plugin-property-testing/no-silent-return': 'error',
'@systemfsoftware/oxlint-plugin-property-testing/no-assert-in-property': 'error',
'@systemfsoftware/oxlint-plugin-property-testing/property-file-purity': 'error',
'@systemfsoftware/oxlint-plugin-property-testing/no-nested-quantification': 'error',
},
})Or spread the recommended preset:
import propertyTestingPlugin from '@systemfsoftware/oxlint-plugin-property-testing'
import { defineConfig } from 'oxlint'
export default defineConfig({
jsPlugins: ['@systemfsoftware/oxlint-plugin-property-testing'],
rules: {
...propertyTestingPlugin.configs.recommended.rules,
},
})