expect-to is an assertion library based on pure functions. It is very easy to extend with new assertions, it can be used in most JavaScript testing frameworks and it works in both Node.js and browsers.
Why another assertion library?
$ npm install --save-dev expect-to
expect(foo).to(be('test'))
expect(foo).to(not(be('testing')))
expect(bar).to(be(false))
expect(bar).to(not(be(undefined)))
expect(obj).to(deepEqual({ foo: 'bar' }))
Or, e.g. within the Mocha BDD interface:
import expect, { not, be } from 'expect-to'
describe('my test', function() {
it('handles equality checks', function() {
expect('foo').to(be('foo'))
})
it('handles `not` for all assertions', function() {
expect('foo').to(not(be('bar')))
})
})
expect-to-core
contains core assertions, such asbe
,deepEqual
,match
andthrowError
. Included by default.expect-to-promises
contains the powerfuleventually
for promises.
Created other assertions on top of expect-to? Let me know!
As an example of how to create an assertion, this is how be
is implemented:
function be(expected) {
return function({ actual, assert }) {
return assert(actual === expected,
['Expected %j to be %j', actual, expected],
['Expected %j not to be %j', actual, expected])
}
}
And this is how you use it:
expect('foo').to(be('foo'))
expect('foo').to(not(be('bar')))
// And just to use the same variable names
// as in the implementation of be:
expect(actual).to(be(expected))
You can also write the assertion using arrow functions:
const be = expected => ({ actual, assert }) =>
assert(actual === expected,
['Expected %j to be %j', actual, expected],
['Expected %j not to be %j', actual, expected])
And if you want to create an assertion like beUndefined
, it would only be:
const beUndefined = ({ actual, assert }) =>
assert(actual === undefined,
['Expected %j to be undefined', actual],
['Expected %j to not be undefined', actual])
And you can use it like this:
expect(undefined).to(beUndefined)
expect('testing').to(not(beUndefined))
Also, what's up with those error messages?
We rely on util.format()
under the hood, so check out those docs
for an explanation of %j
and the other flags.
Note: You can also return a string if you want. This string will not be formatted in any way.
There are many assertion libraries out there, but I haven't found one that matches what I want in an assertion library. This is what I look for:
First, I want my assertions to feel like JavaScript, so I've never been a huge fan of this style of chaining assertions:
someVar.should.be.a('string')
should(null).not.be.ok()
should.not.exist(err)
expect(foo).to.be.a('string')
expect(obj).to.have.property('key')
.with.length(3)
expect(window).not.to.be.an(Image)
An assertion library must also have great error messages, which excludes basic asserts:
assert(user.name == 'kim')
assert(typeof user.age == 'number')
(Yep, I know Power Assert solves that problem.)
It must also be extremely simple to extend. I want assertions for React, Sinon.js and others, but they shouldn't be built into the core itself — the core should be framework agnostic. To me it's important that extensions are first class members, not something that is tacked onto a prototype or added to an instance. This exludes things like:
beforeEach(function () {
jasmine.addMatchers({
toBeDivisibleByTwo: function () {
return {
compare: function (actual, expected) {
return {
pass: (actual % 2) === 0
}
}
}
}
})
})
and:
chai.use(somePlugin)
On that note, I also don't want to mix the test library with the assertion library. This also excludes things like:
test('equal test', function (t) {
t.plan(1)
t.equal('test', 'test')
})
It must also end up calling a function, not assert on property access. What happens here?
foo.should.be.false
// or maybe a test with a small typo
bar.should.be.undefied
The latter doesn't fail no matter what bar
is because it
always returns undefined
. And on that note,
what about:
var bar = undefined
bar.should.not.be.ok
This doesn't work as you cannot add properties to undefined
and null
.
expect-to
is my attempt at building an assertion library that solves all of these problems.