Property-based Testing Reference¶
The prop DSL, forall engine, and gen generator factories are exported from 'utest'.
import { prop, forall, gen, is_generator } from 'utest';
Testing APIs¶
prop(name, generator, prop_fn, opts)¶
Registers a property test block. Equivalent to wrapping forall inside an it block, with persist_id auto-derived from the test file path, enclosing describe names, and name.
| Parameter | Type | Description |
|---|---|---|
name |
string | The name of the property test. |
generator |
Generator | The generator defining the input data shape. |
prop_fn |
function | The property function (value, ctx). Must throw or call assert on failure. |
opts |
object | Optional configuration. See Options below. |
forall(generator, prop_fn, opts)¶
The core property testing engine. Runs the property and reports failures directly. Call it inside an it block when you need more control than prop() provides — for example, to run several independent properties in one test, or to skip persistence.
| Parameter | Type | Description |
|---|---|---|
generator |
Generator | The generator defining the input data shape. |
prop_fn |
function | The property function (value, ctx). Must throw or call assert on failure. |
opts |
object | Optional configuration. See Options below. |
Options¶
| Key | Type | Default | Description |
|---|---|---|---|
runs |
integer | 100 |
The number of random inputs to generate before declaring the property passing. |
shrink_max |
integer | 1000 |
The maximum total number of property evaluations during shrinking. |
seed |
integer | (clock-derived) | Fix the random seed. Useful for reproducing a CI failure locally. |
persist_id |
string | (none) | Key used to store and reload failing counterexamples under .utest/property/. When null (the default for bare forall() calls), persistence is disabled regardless of persist. prop() sets this automatically. |
persist |
boolean | true |
Set to false to disable counterexample persistence even when persist_id is set. Has no effect when persist_id is null. |
Property function context¶
prop_fn receives two arguments: the generated value and a ctx object.
ctx.classify(label, cond) tags the current generated value with label when cond is truthy (or omitted). Tagged counts are printed in the failure output as a coverage breakdown, making it easier to see how inputs are distributed across interesting categories:
prop("clamp result is always within [lo, hi]",
gen.tuple(gen.int(-100, 100), gen.int(-100, 100), gen.int(-100, 100)),
(t, ctx) => {
const lo = t[0] < t[2] ? t[0] : t[2];
const hi = t[0] < t[2] ? t[2] : t[0];
ctx.classify("negative range", lo < 0 && hi < 0);
ctx.classify("straddles zero", lo < 0 && hi >= 0);
ctx.classify("positive range", lo >= 0);
const result = clamp(t[1], lo, hi);
assert.match(true, result >= lo && result <= hi);
});
ctx.classify is a no-op during shrinking — classifications are only counted during the original generation phase.
Generators¶
All generators are available under the gen object.
All numeric and collection generators are biased: 1 in every 8 draws is forced to 0 before being mapped to the output range. Zero maps to the value closest to 0 within the generator's range, so edge-case inputs (zero, boundary values, empty collections) are generated roughly 8× more often than a uniform distribution would produce.
Primitives¶
gen.int(lo, hi): Generates an integer in[lo, hi]. Values shrink toward the endpoint of the range closest to0.gen.bool(): Generatestrueorfalse.gen.float(lo, hi, opts): Generates a floating point number in[lo, hi].opts.precisioncontrols the discrete steps (default10000).gen.constant(v): Always yields the exact valuev.gen.elements(v1, v2, ...): Uniformly picks one of the provided values.
Strings¶
The opts object for strings requires either { len } for an exact length or { min_len, max_len } for bounds.
gen.string(opts): Generates strings fromopts.charset. The default charset includes lowercase letters, numbers, and space.gen.ascii(opts): Generates strings using all printable ASCII characters.gen.alphanumeric(opts): Generates strings using[A-Za-z0-9].
Collections¶
The opts object for arrays requires either { len } for an exact length or { min_len, max_len } for bounds.
gen.array(elem_generator, opts): Generates arrays where every element is produced byelem_generator.gen.tuple(gen1, gen2, ...): Generates a fixed-size array where indexiis generated bygen[i].gen.record({ k1: gen1, k2: gen2 }): Generates an object matching the shape of the specification.
Combinators¶
gen.oneof(gen1, gen2, ...): Uniformly delegates to one of the provided generators.gen.frequency([weight1, gen1], [weight2, gen2], ...): Delegates to generators based on their relative weights.gen.optional(generator, opts): Yields eithernullor a value fromgenerator.opts.none_weightandopts.some_weightcontrol the probability (both default to 1).gen.map(generator, fn): Transforms the output ofgeneratorby passing it throughfn(value).gen.bind(generator, fn): Passes the output ofgeneratortofn(value), which must return a new Generator to be evaluated.gen.filter(generator, pred, opts): Discards values fromgeneratorthat do not satisfypred(value). Throws a discard sentinel ifopts.attempts(default32) consecutive failures occur.
Utilities¶
is_generator(v): Returnstrueifvis a generator object.