JSVerify is a property-based testing library, highly inspired by QuickCheck. It is testing framework agnostic, you could use JSVerify with Mocha, nodeunit, Jasmine or any other framework.

Write properties about your function that should hold true for all inputs, instead of enumerating expected inputs and outputs. Tests written this way are concise and powerful.

Property-based tests make statements about the output of your code based on the input, and these statements are verified for many different possible inputs. [1]

Property-based testing encourages a high level approach to testing in the form of abstract invariants functions should satisfy universally, with the actual test data generated for the programmer by the testing library. In this way code can be hammered with thousands of tests that would be infeasible to write by hand, often uncovering subtle corner cases that wouldn't be found otherwise. [2]

Install the module from npm registry with: npm install jsverify

Clone the source from GitHub and contribute!

This example is taken from older revision of Software Foundations book. We could prove the proposition by hand, as there are only four distinct bool → bool functions. Or we can let JSVerify generate inputs for us.

var boolFnAppliedThrice = jsc.forall( "bool -> bool" , "bool" , function ( f , b ) { return f ( f ( f (b) )) === f (b) ; }); jsc.assert(boolFnAppliedThrice);

A unary operation (or function) is idempotent if, whenever it is applied twice to any value, it gives the same result as if it were applied once; i.e., ƒ(ƒ(x)) ≡ ƒ(x). For example, sort: sort(sort(x)) ≡ sort(x).

var sortIdempotent = jsc.forall( "string -> nat" , "array string" , function ( f , arr ) { return _.isEqual(_.sortBy(_.sortBy( arr , f ), f ), _.sortBy( arr , f )); }); jsc.assert(sortIdempotent);

We could test asynchronous methods with JSVerify too. Just return a Promise from a property function.

function delay( timeout , f ) { var complete ; var p = new Promise(function ( c , r ) { complete = c ; }); setTimeout(function () { complete ( f ()); }, timeout ); return p ; } var noEffectOnPureComputations = jsc.forall( "json -> json" , "json" , jsc.nat( 100 ), function ( f , x , t ) { var sync = f ( x ); return delay( t , function () { return f ( x ); }) .then(function ( async ) { return _.isEqual( sync , async ); }); }); jsc.check(noEffectOnPureComputations);

In case property doesn't hold, JSVerify tries to find the smallest possible counterexample.

var wrongTakeProp = jsc.forall( "array nat" , "nat" , function ( arr , n ) { return _.take( arr , n ).length === n ; }); jsc.check(wrongTakeProp);

Here the problem was in the property specification:

var correctTakeProp = jsc.forall( "array nat" , "nat" , function ( arr , n ) { return _.take( arr , n ).length <= n ; }); jsc.check(correctTakeProp);

Check the README on GitHub for API and usage documentation.