Property based testing framework for JavaScript/TypeScript
Hands-on tutorial and definition of Property Based Testing: π see tutorial. Or directly try it online on our pre-configured CodeSandbox.
Property based testing frameworks check the truthfulness of properties. A property is a statement like: for all (x, y, ...) such that precondition(x, y, ...) holds predicate(x, y, ...) is true.
Install the module with: yarn add fast-check --dev
or npm install fast-check --save-dev
Example of integration in mocha:
import fc from 'fast-check';
// Code under test
const contains = (text, pattern) => text.indexOf(pattern) >= 0;
// Properties
describe('properties', () => {
// string text always contains itself
it('should always contain itself', () => {
fc.assert(fc.property(fc.string(), (text) => contains(text, text)));
});
// string a + b + c always contains b, whatever the values of a, b and c
it('should always contain its substrings', () => {
fc.assert(
fc.property(fc.string(), fc.string(), fc.string(), (a, b, c) => {
// Alternatively: no return statement and direct usage of expect or assert
return contains(a + b + c, b);
}),
);
});
});
In case of failure, the test raises a red flag. Its output should help you to diagnose what went wrong in your implementation. Example with a failing implementation of contain:
1) should always contain its substrings
Error: Property failed after 1 tests (seed: 1527422598337, path: 0:0): ["","",""]
Shrunk 1 time(s)
Got error: Property failed by returning false
Hint: Enable verbose mode in order to have the list of all failing values encountered during the run
Integration with other test frameworks: ava, jasmine, jest, mocha and tape.
More examples: simple examples, fuzzing and against various algorithms.
Useful documentations:
- π Introduction to Property Based & Hands On
- π£ Built-in arbitraries
- π§ Custom arbitraries
- πββοΈ Property based runners
- π₯ Tips
- π API Reference
- β Awesome fast-check
fast-check has initially been designed in an attempt to cope with limitations I encountered while using other property based testing frameworks designed for JavaScript:
- Types: strong and up-to-date types - thanks to TypeScript
- Extendable: easy
map
method to derive existing arbitraries while keeping shrink [more] - some frameworks ask the user to provide both a->b and b->a mappings in order to keep a shrinker - Extendable: kind of flatMap-operation called
chain
[more] - able to bind the output of an arbitrary as input of another one while keeping the shrink working - Extendable: precondition checks with
fc.pre(...)
[more] - filtering invalid entries can be done directly inside the check function if needed - Extendable: easily switch from fake data in tests to property based with
fc.gen()
[more] - generate random values within your predicates - Smart: ability to shrink on
fc.oneof
[more] - surprisingly some frameworks don't - Smart: biased by default - by default it generates both small and large values, making it easier to dig into counterexamples without having to tweak a size parameter manually
- Debug: verbose mode [more][tutorial] - easier troubleshooting with verbose mode enabled
- Debug: replay directly on the minimal counterexample [tutorial] - no need to replay the whole sequence, you get directly the counterexample
- Debug: custom examples in addition of generated ones [more] - no need to duplicate the code to play the property on custom examples
- Debug: logger per predicate run [more] - simplify your troubleshoot with fc.context and its logging feature
- Unique: model based approach [more][article] - use the power of property based testing to test UI, APIs or state machines
- Unique: detect race conditions in your code [more][tutorial] - shuffle the way your promises and async calls resolve using the power of property based testing to detect races
- Unique: simplify user definable corner cases [more] - simplify bug resolution by asking fast-check if it can find an even simpler corner case
For more details, refer to the documentation in the links above.
fast-check has been trusted for years by big projects like: jest, jasmine, fp-ts, io-ts, ramda, js-yaml, query-string...
It also proved useful in finding bugs among major open source projects such as jest, query-string... and many others.
Here are the minimal requirements to use fast-check properly without any polyfills:
fast-check | node | ECMAScript version | TypeScript (optional) |
---|---|---|---|
3.x | β₯8(1) | ES2017 | β₯4.1(2) |
2.x | β₯8(1) | ES2017 | β₯3.2(3) |
1.x | β₯0.12(1) | ES3 | β₯3.0(3) |
More details...
- Except for features that cannot be polyfilled - such as
bigint
-related ones - all the capabilities of fast-check should be usable given you use at least the minimal recommended version of node associated to your major of fast-check. - Require either lib or target β₯ ES2020 or
@types/node
to be installed. - Require either lib or target β₯ ES2015 or
@types/node
to be installed.
Bindings to use fast-check in ReScript are available in package rescript-fast-check. They are maintained by @TheSpyder as an external project.
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome! Become one of them
Many individuals and companies offer their financial support to the project, a huge thanks to all of them too π
You can also become one of them by contributing via GitHub Sponsors or OpenCollective.