fast-check
repository·main·Indexed 26 days ago
https://github.com/dubzzz/fast-checkA property-based testing framework for JavaScript and TypeScript that verifies code properties across automatically generated inputs. It includes the core fast-check library and official integrations for testing frameworks including Jest (@fast-check/jest), Vitest (@fast-check/vitest), and AVA (@fast-check/ava), as well as specialized utilities like @fast-check/poisoning for prototype poisoning detection and @fast-check/packaged for npm publication file management.
What's inside fast-check
- fast-check is a property-based testing library for JavaScript and TypeScript. Unlike traditional example-based testing where you manually provide specific inputs, fast-check automatically generates hundreds of test cases for your assertions. When a failure is found, it automatically 'shrinks' the input to find the smallest possible case that still reproduces the bug.
Overview of the fast-check ecosystem
mainThe
fast-checkecosystem consists of official and third-party extensions and plugins that add additional capabilities to the core library.Stability Warning:
- Official packages (marked with ⭐) are maintained and guaranteed by the
fast-checkteam. - Non-official packages (marked with 🥇, 🥈, 🌗, or ⚠️) are third-party and do not come with the same stability or maintenance guarantees from the core team.
- Official packages (marked with ⭐) are maintained and guaranteed by the
Use @fast-check/ava for AVA testing
mainThe@fast-check/avapackage is the official integration for usingfast-checkproperty-based testing with the AVA test runner. It replaces the legacyava-fast-checkpackage. This package provides support for pre-conditions (fc.pre) and ensures seed computation is aligned with the corefast-checklibrary.Explore advanced fast-check topics and API reference
mainOnce you have mastered the basics via tutorials, you can use the following documentation sections to deepen your knowledge:
- Core Blocks: Reference for properties, runners, and arbitraries.
- Configuration: Instructions for fine-tuning fast-check to match your project's constraints.
- Advanced: Deep dives into model-based testing, race conditions, and more.
- API Reference: An exhaustive list of every exported symbol in the library.
Understand fast-check configuration precedence
mainfast-check uses a hierarchical configuration model:
- Per-assertion configuration: Passed directly to
fc.assert(property, { ... }). This has the highest priority and overrides all other settings. - Global configuration: Set via
fc.configureGlobal({ ... }). This applies to all assertions that do not provide their own local configuration.
A common pattern is to set conservative defaults globally (e.g., tighter timeouts for CI environments) and widen them locally for specific tests that require more runs, larger input sizes, or a specific seed.
- Per-assertion configuration: Passed directly to
Understand the difference between example-based and property-based testing
mainProperty-based testing differs from traditional example-based testing in how it asserts code behavior:
- Example-based testing: Asserts how code behaves on one specific set of inputs and expects a specific outcome.
- Property-based testing: Asserts a relationship (a "property") between inputs and outputs that should hold for all valid sets of inputs. In
fast-check, a property is a function that takes randomly-generated inputs, performs a test, and throws an error if the property is violated.
This approach allows you to focus on the general behaviors of your code rather than manually picking specific test values.
Understand Composite Arbitraries in fast-check
mainComposite arbitraries allow you to assemble structured values by combining smaller, existing arbitraries. Instead of generating random structures, you define a specific shape (like an array, object, or typed array) and provide child arbitraries to fill that shape.
Key features of composites include:
- Size control: Most composites support
minLengthandmaxLengthbounds, along with asizemodifier to scale the magnitude of generated values. - Two-dimensional shrinking: When a test fails, fast-check shrinks the structure (e.g., reducing array length or object keys) and the contents (shrinking individual elements using their own arbitraries) independently. This ensures counterexamples collapse to the minimal failing value.
- Size control: Most composites support
Validate fp-ts constructs with fp-ts-laws
mainUsefp-ts-lawsto ensure that yourfp-tsconstructs are properly configured by leveraging fast-check properties and predicates.Install and use @fast-check/poisoning
mainThe
@fast-check/poisoningpackage provides utilities to detect and revert prototype poisoning in JavaScript.Requirements:
- Node.js version ≥20.19.0
Available Utilities:
assertNoPoisoning: Asserts that defaults known at import time have not been changed.restoreGlobals: Restores defaults to their original state.
Fast-check track record and bug detection examples
mainFast-check has been used to identify critical bugs and CVEs in major open-source projects. It is effective at finding edge cases in algorithms, serialization libraries, and security-sensitive code (such as prototype poisoning in
lodash).Key projects where bugs were confirmed via fast-check include:
- Test Runners:
jest,jasmine - Utility Libraries:
underscore.js,query-string,left-pad,javascript-stringify - Data Formats:
js-yaml,yaml - Security/Auth:
node-jsonwebtoken - Algorithms:
javascript-algorithms
- Test Runners:
Understand Primitive Arbitraries and Constraints
mainPrimitive arbitraries (strings, numbers, booleans, dates, and bigints) are the foundational building blocks of
fast-check. All composite, combiner, and fake data arbitraries are eventually derived from these primitives.Key behaviors to note:
- Constraint Inheritance: Constraints applied to a primitive (such as number ranges, string character sets, or date bounds) are inherited by any complex arbitrary built on top of them. Narrowing a primitive's constraints directly narrows the possible values of all downstream arbitraries.
- Shrinking Behavior: When a test fails,
fast-checkshrinks primitive values toward specific canonical "simple" targets. Recognizing these targets helps in interpreting counterexamples in the terminal.
Advanced testing techniques in fast-check
mainBeyond simple property testing with
fc.assert, fast-check provides advanced capabilities for complex testing scenarios:- Model-based testing: Used for stateful systems where bugs appear only after specific sequences of operations. You define legal commands, and fast-check explores the space of operation sequences.
- Race conditions: Used to find bugs caused by the order of asynchronous callback resolutions. fast-check provides a scheduler to deterministically explore these interleavings.
- Fuzzing: Used for continuous bug hunting. You can extend fast-check into a continuous fuzz loop to hunt for counterexamples beyond the default budget or across multiple runs.
- Fake data generation: Used to generate large volumes of realistic-looking values for seeding environments or staging datasets outside of a standard property-test context.