Back to skills
SKILL.md
Property Based Testing
ASecurityfast-check patterns for JS/TS — 6 canonical property categories with worked examples targeting agent-studio utilities (path normalization, safe-json, glob-to-regex, routing logic)
- 40 stars
- 0 votes
- 0 copies
- 1 view
- Added September 6, 2026
Works with
Security analysis
96/100- Installs packages at runtime which could introduce malicious dependencies
Pro scans all 10 files and shows the line behind each finding
npx -y skills add oimiragieo/agent-studio --skill property-based-testing --agent claude-codeAre you the author of Property Based Testing?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/oimiragieo-property-based-testing)---
name: property-based-testing
description: 'fast-check patterns for JS/TS — 6 canonical property categories with worked examples targeting agent-studio utilities (path normalization, safe-json, glob-to-regex, routing logic)'
version: 1.1.0
verified: true
lastVerifiedAt: '2026-03-01'
category: 'Testing'
agents: [qa, developer]
user_invocable: true
invoked_by: both
tools: [Read, Write, Bash]
tags: [testing, property-based, fast-check, javascript, typescript, fuzzing, invariants]
best_practices:
- 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)
- Security-sensitive string handling (avoid escaping bugs, injection vectors)
- Any function where "this property should hold for ALL inputs" can be stated
## The 6 Canonical Property Categories
### 1. Inverse Operations (Round-trip)
```javascript
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
```javascript
// 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
```javascript
// Order of inputs shouldn't matter
fc.assert(
fc.property(fc.array(fc.integer()), arr => {
expect(sum(arr)).toEqual(sum([...arr].reverse()));
})
);
```
### 4. Invariants (Properties that must always hold)
```javascript
// 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);
})
);
```
### 5. Oracle Comparison (Simpler reference implementation)
```javascript
// 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
```javascript
// 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)
```javascript
import fc from 'fast-check';
const { normalizePath } = require('.claude/lib/utils/path-constants.cjs');
// Property: normalized path never contains backslashes
fc.assert(
fc.property(fc.string(), path => {
expect(normalizePath(path)).not.toMatch(/\\/);
})
);
// Property: idempotent
fc.assert(
fc.property(fc.string(), path => {
expect(normalizePath(normalizePath(path))).toEqual(normalizePath(path));
})
);
```
### Safe JSON Parser (targets SE-02 from sharp-edges)
```javascript
const { safeParseJSON } = require('.claude/lib/utils/safe-json.cjs');
// Property: never throws, always returns { success, data }
fc.assert(
fc.property(fc.string(), input => {
const result = safeParseJSON(input, null);
expect(result).toHaveProperty('success');
expect(typeof result.success).toBe('boolean');
})
);
// Property: prototype pollution not possible
fc.assert(
fc.property(fc.string(), input => {
const before = Object.prototype.toString;
safeParseJSON(input, null);
expect(Object.prototype.toString).toBe(before);
})
);
```
### Glob-to-Regex (targets SE-05 from sharp-edges)
```javascript
// Property: patterns with **/dir/** match root-level dir
fc.assert(
fc.property(fc.constantFrom('foo', 'bar', 'baz'), dir => {
const pattern = `**/${dir}/**`;
const regex = globToRegex(pattern);
expect(`${dir}/file.js`).toMatch(regex); // root-level match
expect(`a/${dir}/file.js`).toMatch(regex); // nested match
})
);
```
### Routing Logic
```javascript
// Property: routing is deterministic (same input -> same agent)
fc.assert(
fc.property(fc.string(), intent => {
expect(route(intent)).toEqual(route(intent));
})
);
// Property: routing never returns null/undefined
fc.assert(
fc.property(fc.string(), intent => {
expect(route(intent)).toBeTruthy();
})
);
```
## Installation
```bash
pnpm add -D fast-check
```
## Running Property Tests
```bash
# 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.
Files in this skill
- SKILL.md
- commands/property-based-testing.md
- hooks/post-execute.cjs
- hooks/pre-execute.cjs
- references/research-requirements.md
- rules/property-based-testing.md
- schemas/input.schema.json
- schemas/output.schema.json
- scripts/main.cjs
- templates/implementation-template.md
Attribution
Comments
Loading comments…