3rd‐party property based testing - uhop/tape-six GitHub Wiki

3rd-party property-based testing

Property-based testing generates many random inputs and checks an invariant holds for all of them. tape-six doesn't ship a generator — bring fast-check (or another lib that throws on counterexample) and assert via t.*.

fast-check

Install: npm install --save-dev fast-check. Throws plain Error (not AssertionError) on counterexample, with a message containing the failing seed and shrunk inputs.

Passing property

import * as fc from 'fast-check';
import test from 'tape-six';

test('string concat is associative', t => {
  fc.assert(
    fc.property(fc.string(), fc.string(), fc.string(), (a, b, c) => {
      return a + (b + c) === a + b + c;
    })
  );
  t.pass('property held over 100 random inputs');
});

fc.assert runs the property a configurable number of times (default 100) and returns silently on success. Add a t.pass() so the test contributes a counted assertion.

Failing property — caught with t.throws

For negative-case tests where you expect the property to fail (e.g. demonstrating a counterexample exists), wrap with t.throws:

test('addition is not subtraction', t => {
  t.throws(
    () => fc.assert(fc.property(fc.integer(), fc.integer(), (a, b) => a + b === a - b)),
    err => err && /Property failed/.test(String(err.message)),
    'fast-check found a counterexample'
  );
});

Failure rendering

A real test failure (the property is supposed to hold but doesn't) surfaces as UNEXPECTED EXCEPTION with fast-check's diagnostic message:

not ok N UNEXPECTED EXCEPTION: Error: Property failed after 4 tests
  { seed: 2045860912, path: "3:0", endOnFailure: true }
  Counterexample: [...]
  Shrunk: ...

The seed and path let you reproduce the exact failure with fc.assert(prop, {seed: ..., path: ...}).

Tuning runs and seeds

fc.assert(prop, {numRuns: 1000, seed: 42}); // deterministic, more iterations

Useful when a flaky property needs investigation, or when you want to lock down a known-good seed in CI.

Browser tests

fast-check ships an ESM build. Add it to your importmap:

{
  "tape6": {
    "importmap": {
      "imports": {
        "fast-check": "/node_modules/fast-check/lib/esm/fast-check.js"
      }
    }
  }
}

Verify the path against node_modules/fast-check/package.json#exports for the version you installed.

See also