Skip to content
Skillv1.0.0

fast-check

Find edge-case bugs with property-based testing using fast-check — generate thousands of random inputs automatically. Use when someone asks to "find edge cases", "fast-check", "property-based testing"

by terminalskills(0) 0 installs
Free
Sign in to install

Free account. Installing gives you the manifest plus copy-paste snippets.

See reviews

About

Imported from terminalskills/skills (skills/fast-check/SKILL.md). Install upstream with npx skills add terminalskills/skills --skill fast-check. Copyright stays with the author (Apache-2.0).

fast-check

Overview

fast-check is a property-based testing framework — instead of writing specific test cases, you describe properties that should always hold, and fast-check generates thousands of random inputs to try to break them. When it finds a failing input, it automatically shrinks it to the minimal reproducing case. Catches edge cases you'd never think to test: empty strings, negative numbers, Unicode, massive arrays, boundary values.

When to Use

  • Functions with many possible inputs (parsers, validators, serializers)
  • Finding edge cases in business logic (pricing, permissions, date handling)
  • Testing serialization/deserialization roundtrips (encode → decode = original)
  • Verifying mathematical properties (commutativity, associativity)
  • Replacing hand-written test cases with generated ones

Instructions

Setup

npm install -D fast-check

Basic Properties

// math.test.ts — Property-based testing for math functions
import fc from "fast-check";
import { describe, it, expect } from "vitest";

describe("sort", () => {
  it("should produce an array of same length", () => {
    fc.assert(
      fc.property(fc.array(fc.integer()), (arr) => {
        const sorted = [...arr].sort((a, b) => a - b);
        return sorted.length === arr.length;
      })
    );
  });

  it("should produce ordered output", () => {
    fc.assert(
      fc.property(fc.array(fc.integer()), (arr) => {
        const sorted = [...arr].sort((a, b) => a - b);
        for (let i = 1; i < sorted.length; i++) {
          expect(sorted[i]).toBeGreaterThanOrEqual(sorted[i - 1]);
        }
      })
    );
  });

  it("should contain the same elements", () => {
    fc.assert(
      fc.property(fc.array(fc.integer()), (arr) => {
        const sorted = [...arr].sort((a, b) => a - b);
        expect(sorted).toEqual(expect.arrayContaining(arr));
        expect(arr).toEqual(expect.arrayContaining(sorted));
      })
    );
  });
});

Roundtrip Testing

// serialization.test.ts — Encode/decode roundtrips
import fc from "fast-check";
import { encode, decode } from "./my-codec";

it("decode(encode(x)) === x for any string", () => {
  fc.assert(
    fc.property(fc.string(), (original) => {
      const encoded = encode(original);
      const decoded = decode(encoded);
      expect(decoded).toEqual(original);
    })
  );
});

it("JSON roundtrip preserves data", () => {
  fc.assert(
    fc.property(fc.jsonValue(), (value) => {
      const json = JSON.stringify(value);
      const parsed = JSON.parse(json);
      expect(parsed).toEqual(value);
    })
  );
});

Custom Arbitraries

// business.test.ts — Custom data generators for domain objects
import fc from "fast-check";

// Generate realistic user objects
const userArbitrary = fc.record({
  id: fc.uuid(),
  name: fc.string({ minLength: 1, maxLength: 100 }),
  email: fc.emailAddress(),
  age: fc.integer({ min: 13, max: 120 }),
  role: fc.constantFrom("admin", "user", "viewer"),
  createdAt: fc.date({ min: new Date("2020-01-01"), max: new Date() }),
});

// Generate realistic money amounts
const moneyArbitrary = fc.record({
  amount: fc.integer({ min: 0, max: 1_000_000 }),  // Cents
  currency: fc.constantFrom("USD", "EUR", "GBP"),
});

it("discount should never result in negative price", () => {
  fc.assert(
    fc.property(
      moneyArbitrary,
      fc.integer({ min: 0, max: 100 }),  // Discount percentage
      (price, discountPercent) => {
        const discounted = applyDiscount(price, discountPercent);
        expect(discounted.amount).toBeGreaterThanOrEqual(0);
      }
    )
  );
});

it("total should equal sum of line items", () => {
  fc.assert(
    fc.property(
      fc.array(moneyArbitrary, { minLength: 1, maxLength: 50 }),
      (items) => {
        const total = calculateTotal(items);
        const expected = items.reduce((sum, item) => sum + item.amount, 0);
        expect(total).toBe(expected);
      }
    )
  );
});

Shrinking (Automatic Minimal Reproduction)

// When a property fails, fast-check automatically finds the SMALLEST failing input

it("handles edge cases in URL parsing", () => {
  fc.assert(
    fc.property(fc.webUrl(), (url) => {
      const parsed = parseUrl(url);
      expect(parsed.protocol).toBeTruthy();
      // If this fails on a complex URL, fast-check shrinks it to
      // the simplest URL that still fails, e.g., "http://a"
    })
  );
});

Examples

Example 1: Test a parser for edge cases

User prompt: "My CSV parser breaks on weird inputs. Find all the edge cases."

The agent will write properties like "parse(serialize(data)) === data", generate random CSV data with edge cases (commas in fields, newlines, empty cells, Unicode), and identify failing inputs.

Example 2: Verify pricing logic

User prompt: "Test our discount calculation to make sure it never produces negative prices or rounding errors."

The agent will generate random prices, discount percentages, and coupon combinations, then verify invariants (non-negative, correct rounding, order doesn't matter).

Guidelines

  • Think in properties, not examples — "sorted output is ordered" not "sort([3,1,2]) = [1,2,3]"
  • Roundtrip is the easiest propertydecode(encode(x)) === x
  • fc.assert runs 100 iterations by default — increase with { numRuns: 1000 }
  • Shrinking is automatic — failed inputs are minimized to the simplest case
  • Built-in arbitraries cover most needsstring, integer, array, record, date, uuid, emailAddress
  • constantFrom for enumsfc.constantFrom("a", "b", "c")
  • fc.pre(condition) for preconditions — skip inputs that don't meet criteria
  • Combine with example-based tests — properties find unknowns, examples verify knowns
  • Seed for reproducibility — failed runs print a seed; re-run with same seed to reproduce

Use it

Copy one of these into your project. Installing also returns the manifest and these snippets.

yaml
targets:
  - https://api.opensmartroute.ai/api/v1/registry/terminalskills-skills-fast-check/manifest   # or paste the manifest below

Manifest

An Open Capability Manifest: the router reads it to know what this does, what it costs and when to pick it.

terminalskills-skills-fast-check.ocm.jsonjson
{
  "ocm": "1",
  "id": "terminalskills-skills-fast-check",
  "kind": "skill",
  "name": "fast-check",
  "description": "Find edge-case bugs with property-based testing using fast-check — generate thousands of random inputs automatically. Use when someone asks to \"find edge cases\", \"fast-check\", \"property-based testing\", \"fuzz testing in TypeScript\", \"generate random test data\", \"QuickCheck for JavaScript\", or \"test with random inputs\". Covers property definitions, arbitraries, shrinking, model-based testing, and integration with Vitest/Jest.",
  "publisher": "terminalskills",
  "version": "1.0.0",
  "capabilities": {
    "domains": [
      "coding"
    ],
    "tags": [
      "skill-md",
      "testing",
      "property-based",
      "fast-check",
      "fuzzing",
      "edge-cases",
      "skills-sh"
    ],
    "languages": [
      "en"
    ]
  },
  "quality_prior": 0.6,
  "examples": [
    "Find edge-case bugs with property-based testing using fast-check — generate thousands of random inputs automatically. Use when someone asks to \"find edge cases\", \"fast-check\", \"property-based testing\", \"fuzz testing in TypeScript\", \"generate random test data\", \"QuickCheck for JavaScript\", or \"test with random inputs\". Covers property definitions, arbitraries, shrinking, model-based testing, and integration with Vitest/Jest."
  ],
  "primary": false,
  "metadata": {
    "source": {
      "provider": "skills.sh",
      "repository": "https://github.com/terminalskills/skills",
      "path": "skills/fast-check/SKILL.md",
      "ref": "HEAD",
      "url": "https://github.com/terminalskills/skills/blob/HEAD/skills/fast-check/SKILL.md",
      "key": "terminalskills/skills/skills/fast-check/SKILL.md"
    },
    "compatibility": "TypeScript/JavaScript. Vitest, Jest, Mocha, or standalone.",
    "license": "Apache-2.0"
  },
  "instructions": "# fast-check\n\n## Overview\n\nfast-check is a property-based testing framework — instead of writing specific test cases, you describe properties that should always hold, and fast-check generates thousands of random inputs to try to break them. When it finds a failing input, it automatically shrinks it to the minimal reproducing case. Catches edge cases you'd never think to test: empty strings, negative numbers, Unicode, massive arrays, boundary values.\n\n## When to Use\n\n- Functions with many possible inputs (parsers, validators, serializers)\n- Finding edge cases in business logic (pricing, permiss",
  "cost": {
    "context_tokens": 1483
  }
}

Fetch it by URL: GET /api/v1/registry/terminalskills-skills-fast-check/manifest?version=1.0.0

Reviews

Star ratings from people who tried it. One review per account; edit yours any time.

No reviews yet. Install it, try it, and be the first to rate it.