Installation | Built-in Tests | Custom Tests
Willy is an assertion library designed to be simple and readable. It doesn't follow the normal BDD/TDD assertion styles, but reads more like questions.
var will = require('willy').will;
describe('some test suite', function () {
it('should do X, Y, and Z', function () {
// Will it?
will(true).be(true);
});
});
Willy...
- is super easy to use
- includes a bunch of built-in tests
- makes custom tests easy
- supports promises
Keep it simple, so you can focus on your code, not your tests. Compare testing instanceof
in a few different assertion libraries.
// Chai
expect(foo).to.be.an.instanceof(Foo);
// Shouldjs
foo.should.be.an.instanceOf(Foo)
// Jasmine
expect(foo).toEqual(jasmine.any(Foo));
// Willy
will(foo).beA(Foo);
Want to add to Willy's repertoire? That's easy, too.
willy.define(function beASubstringOf() {
return this.expected.indexOf(this.actual) > -1;
});
will('potato').beASubstringOf('Bender Bending Rodriguez');
// expected 'potato' to be a substring of 'Bender Bending Rodriguez'
Use npm, man. Keep it simple.
npm install willy --save-dev
- be
- beA
- beAn
- beDefined
- beFalsy
- beGreaterThan
- beLessThan
- beLike
- beMoreThan
- beNull
- beTruthy
- beUndefined
- exist
- have
- haveAny
- haveOnly
- haveOwn
- match
- throw
Test identity.
// pass
will(3).be(3);
// fail
will('3').be(3);
Test inheritance.
This also handles some of the weirdness of JavaScript, so that String
and Number
literals act as expected.
var Foo = function () {};
var foo = new Foo();
// pass
will(foo).beA(Foo);
will('').beA(String);
will([]).beAn(Array);
// fail
will('').beA(Number);
Test for a defined value.
var foo = 123;
var bar;
// pass
will(foo).beDefined();
// fail
will(bar).beDefined();
Test for a falsy value.
// pass
will('').beFalsy();
// fail
will('asdf').beFalsy();
Test a value to see if it's greater than another.
// pass
will(4).beGreaterThan(3);
// fail
will(3).beGreaterThan(3);
Test a value to see if it's less than another.
// pass
will(3).beLessThan(4);
// fail
will(3).beLessThan(3);
Test equality.
// pass
will('').beLike(false);
// fail
will('false').beLike(false);
This also works on objects, including Arrays, recursively.
// pass
will({
foo: 'bar',
baz: [1, 2, 3],
quux: null
}).beLike({
foo: 'bar',
baz: [1, 2, 3],
quux: null
});
will([1, 2, 3]).beLike([1, 2, 3]);
// fail
will({
foo: {
bar: {
baz: {
quux: true
}
}
}
}).beLike({
foo: {
bar: {
baz: {
quux: false
}
}
}
});
will([1, 2, 3]).beLike([3, 2, 1]);
Test a value to see if it's more than another.
// pass
will(4).beMoreThan(3);
// fail
will(3).beMoreThan(3);
Test for null
.
// pass
will(null).beNull();
// fail
will(undefined).beNull();
Test for a truthy value.
// pass
will('asdf').beTruthy();
// fail
will('').beTruthy();
Test for an undefined
value.
var foo;
var bar = 123;
// pass
will(foo).beUndefined();
// fail
will(bar).beUndefined();
Test the existence of a property.
// pass
var foo = { bar: 1 };
will(foo.bar).exist();
// fail
will(foo.baz).exist();
Test the existence of multiple items/properties in an Array/Object. all must be present
// pass
will([1, 2, 3]).have(1);
will([1, 2, 3]).have([1, 2]);
will({ foo: 1, bar: 1 }).have('foo');
will({ foo: 1, bar: 1 }).have(['foo', 'bar']);
// fail
will([2, 3]).have(1);
will([1, 2]).have([1, 3]);
will({ foo: 1, bar: 1 }).have('baz');
will({ foo: 1, bar: 1 }).have(['foo', 'baz']);
Test the existence of one item/property in an Array/Object
// pass
will([1, 2, 3]).haveAny(1);
will([1, 2, 3]).haveAny([3, 6]);
will({ foo: 1, bar: 1 }).haveAny('foo');
will({ foo: 1, bar: 1 }).haveAny(['foo', 'baz']);
// fail
will([2, 3]).haveAny(1);
will([1, 2]).haveAny([3, 6]);
will({ foo: 1, bar: 1 }).haveAny('baz');
will({ foo: 1, bar: 1 }).haveAny(['baz', 'quux']);
Test an Array/Object for unexpected items/properties.
// pass
will([1]).haveOnly(1);
will([1, 2, 3]).haveOnly([1, 2, 3]);
will({ foo: 1 }).haveOnly('foo');
will({ foo: 1, bar: 1 }).haveOnly(['foo', 'bar']);
// fail
will([1, 2]).haveOnly(1);
will([1, 2, 3]).haveOnly([1, 2]);
will({ foo: 1, bar: 1 }).haveOnly('baz');
will({ foo: 1, bar: 1, baz: 1 }).haveOnly(['foo', 'bar']);
Test for an own property.
var Foo = function () {};
var foo = new Foo();
foo.bar = true;
Foo.prototype.baz = true;
// pass
will(foo).haveOwn('bar');
// fail
will(foo).haveOwn('baz');
Test against RegExp.
// pass
will('asdf').match(/SD/i);
// fail
will('asdf').match(/SD/);
Test for an error being thrown.
var bad = function () {
throw new Error('whoops');
};
var good = function () {};
// pass
will(bad).throw();
// fail
will(good).throw();
To define new tests, use willy.define
. The function should return an expression used to determine if the test passes or fails.
willy.define(function beASubstringOf() {
return this.expected.indexOf(this.actual) > -1;
});
will('potato').beASubstringOf('Bender Bending Rodriguez');
// expected 'potato' to be a substring of 'Bender Bending Rodriguez'
Inside every test function
this.actual
is the value passed towill()
this.expected
is the optional value passed to the test
Pass an object to willy.define
to give you more options. The object's properties should be:
- fn - The function used to perform the test.
- explanation (optional) - An explanation of what you were testing. If omitted, the test's name will be converted.
- name (optional) - The name of your test. This can usually be figured out, but ocassionally you may want to be explicit.
Changing the Explanation
// providing a better explanation
willy.define({
fn: function beASubstringOf() {
return this.expected.indexOf(this.actual) > -1;
},
explanation: 'be found inside of'
});
will('potato').beASubstringOf('Bender Bending Rodriguez');
// expected 'potato' to be found inside of 'Bender Bending Rodriguez'
Changing the Name
// providing a different name
willy.define({
fn: function () {
return this.expected.indexOf(this.actual) > -1;
},
name: 'lieWithin'
});
will('potato').lieWithin('Bender Bending Rodriguez');
// expected 'potato' to lie within 'Bender Bending Rodriguez'
If you're lazy, use willy.loadDefinitions
to define multiple tests at a time.
willy.loadDefinitions({
beASubstringOf: {
fn: function () {
return this.expected.indexOf(this.actual) > -1;
},
explanation: 'be found inside of'
},
lieWithin: {
fn: function () {
return this.expected.indexOf(this.actual) > -1;
}
}
});
For supreme laziness, keep your custom tests in a Node module. This will allow you to build up a collection of custom tests you can reuse with all your projects.
my-tests.js
exports.beASubstringOf = {
fn: function () {
return this.expected.indexOf(this.actual) > -1;
},
explanation: 'be found inside of'
};
exports.lieWithin = {
fn: function () {
return this.expected.indexOf(this.actual) > -1;
}
};
A Test Suite
var willy = require('willy'),
will = willy.will;
willy.loadDefinitions(require('./my-tests.js'));
describe('a test suite', function () {
it('should be pretty easy to share custom tests', function () {
will('potato').lieWithin('Bender Bending Rodriguez');
// expected 'potato' to lie within 'Bender Bending Rodriguez'
});
});