Skip to main content

Getting Started

Get started with fast-check in an existing project.

Install the package

fast-check can be installed into any existing project by running the following command:

npm install --save-dev fast-check
No install

You can also directly pull it from a CDN:

// deno
import fc from 'https://cdn.skypack.dev/fast-check';
<!-- html file -->
<script type="module">
import fc from 'https://cdn.skypack.dev/fast-check';
// code...
</script>
Integration with test runners

fast-check is agnostic of the test runner you rely on. It works with any test runner without needing any specific change.

Simple property

Now, that you've it in your project you can start playing with it on any property. Here is an example of property:

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) => {
return 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);
}),
);
});
});
Hands on Property-Based Testing

If you want to quickly get started with property-based testing, you may check our tutorials and our quick start guide.

Walk through the test

Let's quickly walk through the core building blocks we had to leverage in the code snippet above. If you want to dig further into each of these building blocks, they will be covered into more details in the following pages of this guide.

Runner

fast-check has several runners. Runners are responsible to interpret and possibly execute the properties or at least part of them. The runner used in the snippet above is fc.assert.

fc.assert takes a property and runs it multiple times. In case of failure, it will try to reduce the case that caused the failure into something easily readable for a human. For instance, if the test "should always contain itself" failed for some inputs, instead of stopping itself when it failed for the first time, fc.assert will try to find the smallest value responsible for the error. The reduction capacity will be referred as shrinking in the next sections.

Property

A property describes:

  1. what the user wants to assess — via a predicate
  2. how to generate the inputs of the predicate — via arbitraries

The snippet above declared synchronous properties by calling fc.property. Synchronous properties can only deal with synchronous predicates. For asynchronous predicates, users should go for fc.asyncProperty instead of fc.property.

Whatever the helper you take, the structure to declare a property is the same:

fc.property(
...arbitraries // how to generate the values received as inputs of the predicate
predicate // how to check if the code worked
);

The predicate is a function taking the values produced by the declared arbitraries as inputs and returning either a boolean value or directly asserting. For instance, our first property could also have leveraged assertions by using the following predicate:

(text) => {
expect(contains(text, text)).toBe(true);
// return contains(text, text); // <-- the boolean version
};

Arbitrary

An arbitrary is responsible to generate random values in a seeded way and to shrink them in case it's requested. Here we only used one kind of arbitrary: fc.string(). But they are many others built-in ones and an infinity you can produce just by combining existing ones together.

The arbitrary called fc.string() is responsible to generate and shrink strings.