Skip to content

reergymerej/willy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build Status

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'

Installation

Use npm, man. Keep it simple.

npm install willy --save-dev

Usage

Built-in Tests

be

Test identity.

// pass
will(3).be(3);

// fail
will('3').be(3);

beA/beAn

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);

beDefined

Test for a defined value.

var foo = 123;
var bar;

// pass
will(foo).beDefined();

// fail
will(bar).beDefined();

beFalsy

Test for a falsy value.

// pass
will('').beFalsy();

// fail
will('asdf').beFalsy();

beGreaterThan

Test a value to see if it's greater than another.

// pass
will(4).beGreaterThan(3);

// fail
will(3).beGreaterThan(3);

beLessThan

Test a value to see if it's less than another.

// pass
will(3).beLessThan(4);

// fail
will(3).beLessThan(3);

beLike

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]);

beMoreThan

Test a value to see if it's more than another.

// pass
will(4).beMoreThan(3);

// fail
will(3).beMoreThan(3);

beNull

Test for null.

// pass
will(null).beNull();

// fail
will(undefined).beNull();

beTruthy

Test for a truthy value.

// pass
will('asdf').beTruthy();

// fail
will('').beTruthy();

beUndefined

Test for an undefined value.

var foo;
var bar = 123;

// pass
will(foo).beUndefined();

// fail
will(bar).beUndefined();

exist

Test the existence of a property.

// pass
var foo = { bar: 1 };

will(foo.bar).exist();

// fail
will(foo.baz).exist();

have

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']);

haveAny

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']);

haveOnly

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']);

haveOwn

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');

match

Test against RegExp.

// pass
will('asdf').match(/SD/i);

// fail
will('asdf').match(/SD/);

throw

Test for an error being thrown.

var bad = function () {
    throw new Error('whoops');
};

var good = function () {};

// pass
will(bad).throw();

// fail
will(good).throw();

Custom Tests

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 to will()
  • this.expected is the optional value passed to the test

Advanced

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'

Bulk Definitions

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;
        }
    }
});

Modularize It

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'
    });
});