testing-plugin/skills/property-based-testing/SKILL.md
Property-based testing with fast-check (TS/JS) and Hypothesis (Python). Use when generating test data, finding edge cases, testing properties, or writing QuickCheck-style tests.
npx skillsauth add laurigates/claude-plugins property-based-testingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Expert knowledge for property-based testing - automatically generating test cases to verify code properties rather than testing specific examples.
| Use this skill when... | Use another skill instead when... | |------------------------|----------------------------------| | Testing mathematical properties (commutative, associative) | Writing specific example-based unit tests | | Testing encode/decode roundtrips | Setting up test runner configuration | | Finding edge cases automatically | Doing E2E browser testing | | Validating data transformations and invariants | Analyzing test quality or smells | | Testing API contracts with generated data | Running mutation testing |
Property-Based Testing Concept
When to Use Property-Based Testing
# Using Bun
bun add -d fast-check
# Using npm
npm install -D fast-check
import { test } from 'vitest'
import * as fc from 'fast-check'
// Property-based test
test('reverse twice returns original - property based', () => {
fc.assert(
fc.property(
fc.array(fc.integer()), // Generate random arrays of integers
(arr) => {
expect(reverse(reverse(arr))).toEqual(arr)
}
)
)
})
// fast-check automatically generates 100s of test cases!
| Generator | Description |
|-----------|-------------|
| fc.integer() | Any integer (with optional min/max) |
| fc.nat() | Natural numbers (>= 0) |
| fc.float() / fc.double() | Floating-point numbers |
| fc.string() | Any string (with optional length) |
| fc.emailAddress() | Email format strings |
| fc.array(arb) | Arrays of arbitrary type |
| fc.record({...}) | Object with typed fields |
| fc.boolean() | Boolean values |
| fc.constantFrom(...) | Pick from options |
| fc.tuple(...) | Fixed-size tuples |
| fc.oneof(...) | Union types |
| fc.option(arb) | Value or null |
| fc.date() | Date objects |
| Property | Pattern | Example |
|----------|---------|---------|
| Roundtrip | f(g(x)) = x | encode/decode, serialize/parse |
| Idempotence | f(f(x)) = f(x) | sort, normalize, format |
| Commutativity | f(a,b) = f(b,a) | add, merge, union |
| Associativity | f(f(a,b),c) = f(a,f(b,c)) | add, concat |
| Identity | f(x, id) = x | multiply by 1, add 0 |
| Inverse | f(g(x)) = x | encrypt/decrypt |
fc.assert(property, {
numRuns: 1000, // Run 1000 tests (default: 100)
seed: 42, // Reproducible tests
endOnFailure: true, // Stop after first failure
})
fc.pre(b !== 0) // Skip cases where b is 0
# Using uv
uv add --dev hypothesis pytest
# Optional extensions
uv add --dev hypothesis[numpy] # NumPy strategies
uv add --dev hypothesis[django] # Django model strategies
# pyproject.toml
[tool.hypothesis]
max_examples = 200
deadline = 1000
[tool.hypothesis.profiles.dev]
max_examples = 50
deadline = 1000
[tool.hypothesis.profiles.ci]
max_examples = 500
deadline = 5000
verbosity = "verbose"
# Activate profile in conftest.py
from hypothesis import settings
settings.load_profile("ci")
from hypothesis import given, example, assume
import hypothesis.strategies as st
# Test a property
@given(st.integers(), st.integers())
def test_addition_commutative(a, b):
assert a + b == b + a
# Add explicit edge cases with @example
@given(st.integers())
@example(0)
@example(-1)
@example(2**31 - 1)
def test_with_explicit_examples(x):
assert process(x) is not None
| Strategy | Description |
|----------|-------------|
| st.integers() | Any integer (with optional bounds) |
| st.floats() | Floating-point numbers |
| st.text() | Any string (with optional size) |
| st.binary() | Byte strings |
| st.lists(strat) | Lists of given strategy |
| st.sets(strat) | Unique value sets |
| st.dictionaries(k, v) | Dictionaries |
| st.booleans() | Boolean values |
| st.sampled_from(...) | Pick from options |
| st.tuples(...) | Fixed-size tuples |
| st.one_of(...) | Union types |
| st.emails() | Valid email addresses |
| st.uuids() | UUID objects |
| st.dates() / st.datetimes() | Date/time values |
| st.builds(Class, ...) | Build objects from strategies |
from hypothesis import given, settings, strategies as st
@settings(max_examples=1000, deadline=None)
@given(st.lists(st.integers()))
def test_with_custom_settings(arr):
assert sort(arr) == sorted(arr)
from hypothesis import assume
assume(b != 0) # Skip cases where b is 0
Hypothesis supports stateful testing via RuleBasedStateMachine for testing sequences of operations against invariants.
# .github/workflows/test.yml
- name: Run hypothesis tests
run: |
uv run pytest \
--hypothesis-show-statistics \
--hypothesis-profile=ci \
--hypothesis-seed=${{ github.run_number }}
- name: Upload hypothesis database
uses: actions/upload-artifact@v4
if: failure()
with:
name: hypothesis-examples
path: .hypothesis/
# Core decorators
@given(strategy) # Generate test inputs
@example(value) # Add explicit test case
@settings(max_examples=500) # Configure behavior
# Key helpers
assume(condition) # Skip invalid inputs
note(message) # Add debug info to failure output
target(value) # Guide generation toward value
| Context | Command |
|---------|---------|
| Quick TS test | bunx vitest --dots --bail=1 --grep 'property' |
| Quick Python test | uv run pytest -x -q --tb=short -k 'property' |
| CI TS test | bunx vitest run --reporter=junit --grep 'property' |
| CI Python test | uv run pytest --hypothesis-profile=ci --hypothesis-show-statistics -q |
| Reproducible | fc.assert(prop, { seed: 42 }) or pytest --hypothesis-seed=42 |
| Fast iteration | fc.assert(prop, { numRuns: 50 }) or pytest --hypothesis-profile=dev -x |
| Debug failing | pytest -x -s --hypothesis-verbosity=debug |
| No shrinking | Add phases=[Phase.generate] to @settings |
For detailed examples, advanced patterns, and best practices, see REFERENCE.md.
vitest-testing - Unit testing frameworkpython-testing - Python pytest testingtest-quality-analysis - Detecting test smellsmutation-testing - Validate test effectivenesstools
Scaffold a new ComfyUI custom-node repo (pyproject, CI, release-please, vitest+pytest, JS extension skeleton) in the picker/gesture vein. Use when bootstrapping or init-ing a comfyui node pack.
tools
Orchestrate a ComfyUI node pack from idea to registry: scaffold, create + seed the repo, open the gitops adoption PR. Use when releasing or spinning up a new comfyui node pack.
testing
macOS EndpointSecurity/EDR high CPU & battery drain. Use when Kandji ESF / XProtect pegs a core; trace the exec storm via powermetrics + eslogger.
development
odiff pixel-by-pixel image diffing. Use when comparing screenshots, detecting visual regressions, diffing before/after PNGs, asserting golden images.