Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
["State properties as invariants that must hold for ALL inputs","Use shrinkage to get minimal counterexamples on failure","Combine with unit tests — property tests find edge cases, unit tests document examples"]
error_handling
graceful
source
builtin
trust_score
100
provenance_sha
5cad2a35e425e814
Property-Based Testing
fast-check patterns for JavaScript/TypeScript that find edge cases unit tests miss. Includes 6 canonical property categories with worked examples targeting agent-studio's own utilities.
When to Use
New utility functions (path normalization, parsers, transformers)
Bug fixes where the fix has a general invariant (not just the specific repro case)
Any function where "this property should hold for ALL inputs" can be stated
The 6 Canonical Property Categories
1. Inverse Operations (Round-trip)
import fc from'fast-check';
// If you serialize then deserialize, you get back the original
fc.assert(
fc.property(fc.anything(), value => {
expect(deserialize(serialize(value))).toEqual(value);
})
);
2. Idempotency
// Applying a function twice gives same result as once
fc.assert(
fc.property(fc.string(), str => {
expect(normalize(normalize(str))).toEqual(normalize(str));
})
);
3. Commutativity / Order Independence
// Order of inputs shouldn't matter
fc.assert(
fc.property(fc.array(fc.integer()), arr => {
expect((arr)).(([...arr].()));
})
);
sum
toEqual
sum
reverse
4. Invariants (Properties that must always hold)
// Output always has certain structural properties
fc.assert(
fc.property(fc.string(), input => {
const result = parseArgs(input);
expect(result).toHaveProperty('args');
expect(Array.isArray(result.args)).toBe(true);
})
);
// Compare fast implementation against slow-but-correct reference
fc.assert(
fc.property(fc.array(fc.integer()), arr => {
expect(fastSort(arr)).toEqual(referenceSort(arr));
})
);
6. Metamorphic Relations
// If input changes in a known way, output changes in a predictable way
fc.assert(
fc.property(fc.array(fc.integer()), arr => {
const sorted = sort(arr);
const sortedWithExtra = sort([...arr, Number.MAX_SAFE_INTEGER]);
expect(sortedWithExtra[sortedWithExtra.length - 1]).toBe(Number.MAX_SAFE_INTEGER);
})
);
Agent-Studio Specific Examples
Path Normalization (targets SE-01 from sharp-edges)
# Run all property tests
node --test tests/**/*.property.test.cjs
# Run with verbose output (shows counterexamples on failure)
FAST_CHECK_VERBOSE=true node --test tests/**/*.property.test.cjs
Shrinkage (Automatic Counterexample Minimization)
fast-check automatically shrinks failing inputs to the minimal counterexample. Example:
Test fails on: "C:\\Users\\foo\\deep\\nested\\path"
fast-check shrinks to: "a\\b" (minimal backslash case)
This makes debugging far faster than traditional fuzzing.
Memory Protocol (MANDATORY)
Before starting:
Read .claude/context/memory/learnings.md
After completing:
New pattern -> .claude/context/memory/learnings.md
Issue found -> .claude/context/memory/issues.md
Decision made -> .claude/context/memory/decisions.md
ASSUME INTERRUPTION: If it's not in memory, it didn't happen.