mirror of https://github.com/lukechilds/ava.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
563 lines
12 KiB
563 lines
12 KiB
'use strict';
|
|
var test = require('tap').test;
|
|
var Promise = global.Promise = require('bluebird');
|
|
var delay = require('delay');
|
|
var isPromise = require('is-promise');
|
|
var Test = require('../lib/test');
|
|
|
|
function ava(title, fn, contextRef, report) {
|
|
var t = new Test(title, fn, contextRef, report);
|
|
t.metadata = {callback: false};
|
|
return t;
|
|
}
|
|
|
|
ava.cb = function (title, fn, contextRef, report) {
|
|
var t = new Test(title, fn, contextRef, report);
|
|
t.metadata = {callback: true};
|
|
return t;
|
|
};
|
|
|
|
test('must be called with new', function (t) {
|
|
t.throws(function () {
|
|
var test = Test;
|
|
test();
|
|
}, {message: 'Class constructor Test cannot be invoked without \'new\''});
|
|
t.end();
|
|
});
|
|
|
|
test('run test', function (t) {
|
|
var result = ava('foo', function (a) {
|
|
a.fail();
|
|
}).run();
|
|
|
|
t.is(result.passed, false);
|
|
t.end();
|
|
});
|
|
|
|
test('title is optional', function (t) {
|
|
var result = ava(function (a) {
|
|
a.pass();
|
|
}).run();
|
|
|
|
t.is(result.passed, true);
|
|
t.is(result.result.title, '[anonymous]');
|
|
t.end();
|
|
});
|
|
|
|
test('callback is required', function (t) {
|
|
t.throws(function () {
|
|
ava();
|
|
}, /you must provide a callback/);
|
|
|
|
t.throws(function () {
|
|
ava('title');
|
|
}, /you must provide a callback/);
|
|
|
|
t.end();
|
|
});
|
|
|
|
test('infer name from function', function (t) {
|
|
var result = ava(function foo(a) {
|
|
a.pass();
|
|
}).run();
|
|
t.is(result.passed, true);
|
|
t.is(result.result.title, 'foo');
|
|
t.end();
|
|
});
|
|
|
|
test('multiple asserts', function (t) {
|
|
var result = ava(function (a) {
|
|
a.pass();
|
|
a.pass();
|
|
a.pass();
|
|
}).run();
|
|
|
|
t.is(result.passed, true);
|
|
t.is(result.result.assertCount, 3);
|
|
t.end();
|
|
});
|
|
|
|
test('plan assertions', function (t) {
|
|
var result = ava(function (a) {
|
|
a.plan(2);
|
|
a.pass();
|
|
a.pass();
|
|
}).run();
|
|
|
|
t.is(result.passed, true);
|
|
t.is(result.result.planCount, 2);
|
|
t.is(result.result.assertCount, 2);
|
|
t.end();
|
|
});
|
|
|
|
test('run more assertions than planned', function (t) {
|
|
var result = ava(function (a) {
|
|
a.plan(2);
|
|
a.pass();
|
|
a.pass();
|
|
a.pass();
|
|
}).run();
|
|
|
|
t.is(result.passed, false);
|
|
t.ok(result.reason);
|
|
t.is(result.reason.name, 'AssertionError');
|
|
t.is(result.reason.expected, 2);
|
|
t.is(result.reason.actual, 3);
|
|
t.match(result.reason.message, /count does not match planned/);
|
|
t.end();
|
|
});
|
|
|
|
test('handle non-assertion errors', function (t) {
|
|
var result = ava(function () {
|
|
throw new Error();
|
|
}).run();
|
|
|
|
t.is(result.passed, false);
|
|
t.is(result.reason.name, 'Error');
|
|
t.true(result.reason instanceof Error);
|
|
t.end();
|
|
});
|
|
|
|
test('end can be used as callback without maintaining thisArg', function (t) {
|
|
ava.cb(function (a) {
|
|
setTimeout(a.end);
|
|
}).run().then(function (result) {
|
|
t.is(result.passed, true);
|
|
t.end();
|
|
});
|
|
});
|
|
|
|
test('end can be used as callback with error', function (t) {
|
|
var err = new Error('failed');
|
|
ava.cb(function (a) {
|
|
a.end(err);
|
|
}).run().then(function (result) {
|
|
t.is(result.passed, false);
|
|
t.is(result.reason, err);
|
|
t.end();
|
|
});
|
|
});
|
|
|
|
test('end can be used as callback with a non-error as its error argument', function (t) {
|
|
var nonError = {foo: 'bar'};
|
|
ava.cb(function (a) {
|
|
a.end(nonError);
|
|
}).run().then(function (result) {
|
|
t.is(result.passed, false);
|
|
t.ok(result.reason);
|
|
t.is(result.reason.name, 'AssertionError');
|
|
t.is(result.reason.actual, nonError);
|
|
t.is(result.reason.message, 'Callback called with an error: { foo: \'bar\' }');
|
|
t.end();
|
|
});
|
|
});
|
|
|
|
test('handle non-assertion errors even when planned', function (t) {
|
|
var result = ava(function (a) {
|
|
a.plan(1);
|
|
throw new Error('bar');
|
|
}).run();
|
|
|
|
t.is(result.passed, false);
|
|
t.is(result.reason.name, 'Error');
|
|
t.is(result.reason.message, 'bar');
|
|
t.end();
|
|
});
|
|
|
|
test('handle testing of arrays', function (t) {
|
|
var result = ava(function (a) {
|
|
a.same(['foo', 'bar'], ['foo', 'bar']);
|
|
}).run();
|
|
|
|
t.is(result.passed, true);
|
|
t.is(result.result.assertCount, 1);
|
|
t.end();
|
|
});
|
|
|
|
test('handle falsy testing of arrays', function (t) {
|
|
var result = ava(function (a) {
|
|
a.notSame(['foo', 'bar'], ['foo', 'bar', 'cat']);
|
|
}).run();
|
|
|
|
t.is(result.passed, true);
|
|
t.is(result.result.assertCount, 1);
|
|
t.end();
|
|
});
|
|
|
|
test('handle testing of objects', function (t) {
|
|
var result = ava(function (a) {
|
|
a.same({foo: 'foo', bar: 'bar'}, {foo: 'foo', bar: 'bar'});
|
|
}).run();
|
|
|
|
t.is(result.passed, true);
|
|
t.is(result.result.assertCount, 1);
|
|
t.end();
|
|
});
|
|
|
|
test('handle falsy testing of objects', function (t) {
|
|
var result = ava(function (a) {
|
|
a.notSame({foo: 'foo', bar: 'bar'}, {foo: 'foo', bar: 'bar', cat: 'cake'});
|
|
}).run();
|
|
|
|
t.is(result.passed, true);
|
|
t.is(result.result.assertCount, 1);
|
|
t.end();
|
|
});
|
|
|
|
test('handle throws with error', function (t) {
|
|
var result = ava(function (a) {
|
|
a.throws(function () {
|
|
throw new Error('foo');
|
|
});
|
|
}).run();
|
|
|
|
t.is(result.passed, true);
|
|
t.is(result.result.assertCount, 1);
|
|
t.end();
|
|
});
|
|
|
|
test('handle throws without error', function (t) {
|
|
var result = ava(function (a) {
|
|
a.throws(function () {
|
|
return;
|
|
});
|
|
}).run();
|
|
|
|
t.is(result.passed, false);
|
|
t.ok(result.reason);
|
|
t.end();
|
|
});
|
|
|
|
test('handle notThrows with error', function (t) {
|
|
var result = ava(function (a) {
|
|
a.notThrows(function () {
|
|
throw new Error('foo');
|
|
});
|
|
}).run();
|
|
|
|
t.is(result.passed, false);
|
|
t.ok(result.reason);
|
|
t.is(result.reason.name, 'AssertionError');
|
|
t.end();
|
|
});
|
|
|
|
test('handle notThrows without error', function (t) {
|
|
var result = ava(function (a) {
|
|
a.notThrows(function () {
|
|
return;
|
|
});
|
|
}).run();
|
|
|
|
t.is(result.passed, true);
|
|
t.is(result.result.assertCount, 1);
|
|
t.end();
|
|
});
|
|
|
|
test('run functions after last planned assertion', function (t) {
|
|
var i = 0;
|
|
|
|
var result = ava(function (a) {
|
|
a.plan(1);
|
|
a.pass();
|
|
i++;
|
|
}).run();
|
|
|
|
t.is(i, 1);
|
|
t.is(result.passed, true);
|
|
t.end();
|
|
});
|
|
|
|
test('run async functions after last planned assertion', function (t) {
|
|
var i = 0;
|
|
|
|
ava.cb(function (a) {
|
|
a.plan(1);
|
|
a.pass();
|
|
a.end();
|
|
i++;
|
|
}).run().then(function (result) {
|
|
t.is(i, 1);
|
|
t.is(result.passed, true);
|
|
t.end();
|
|
});
|
|
});
|
|
|
|
test('planned async assertion', function (t) {
|
|
ava.cb(function (a) {
|
|
a.plan(1);
|
|
|
|
setTimeout(function () {
|
|
a.pass();
|
|
a.end();
|
|
}, 100);
|
|
}).run().then(function (result) {
|
|
t.is(result.passed, true);
|
|
t.is(result.result.assertCount, 1);
|
|
t.end();
|
|
});
|
|
});
|
|
|
|
test('async assertion with `.end()`', function (t) {
|
|
ava.cb(function (a) {
|
|
setTimeout(function () {
|
|
a.pass();
|
|
a.end();
|
|
}, 100);
|
|
}).run().then(function (result) {
|
|
t.is(result.passed, true);
|
|
t.is(result.result.assertCount, 1);
|
|
t.end();
|
|
});
|
|
});
|
|
|
|
test('more assertions than planned should emit an assertion error', function (t) {
|
|
var result = ava(function (a) {
|
|
a.plan(1);
|
|
a.pass();
|
|
a.pass();
|
|
}).run();
|
|
|
|
t.is(result.passed, false);
|
|
t.is(result.reason.name, 'AssertionError');
|
|
t.end();
|
|
});
|
|
|
|
test('record test duration', function (t) {
|
|
ava.cb(function (a) {
|
|
a.plan(1);
|
|
|
|
setTimeout(function () {
|
|
a.true(true);
|
|
a.end();
|
|
}, 1234);
|
|
}).run().then(function (result) {
|
|
t.is(result.passed, true);
|
|
t.true(result.result.duration >= 1234);
|
|
t.end();
|
|
});
|
|
});
|
|
|
|
test('wait for test to end', function (t) {
|
|
var avaTest;
|
|
|
|
ava.cb(function (a) {
|
|
a.plan(1);
|
|
|
|
avaTest = a;
|
|
}).run().then(function (result) {
|
|
t.is(result.passed, true);
|
|
t.is(result.result.planCount, 1);
|
|
t.is(result.result.assertCount, 1);
|
|
t.true(result.result.duration >= 1234);
|
|
t.end();
|
|
});
|
|
|
|
setTimeout(function () {
|
|
avaTest.pass();
|
|
avaTest.end();
|
|
}, 1234);
|
|
});
|
|
|
|
test('fails with the first assertError', function (t) {
|
|
var result = ava(function (a) {
|
|
a.plan(2);
|
|
a.is(1, 2);
|
|
a.is(3, 4);
|
|
}).run();
|
|
|
|
t.is(result.passed, false);
|
|
t.is(result.reason.actual, 1);
|
|
t.is(result.reason.expected, 2);
|
|
t.end();
|
|
});
|
|
|
|
test('fails with thrown falsy value', function (t) {
|
|
var result = ava(function () {
|
|
throw 0; // eslint-disable-line no-throw-literal
|
|
}).run();
|
|
|
|
t.is(result.passed, false);
|
|
t.is(result.reason.actual, 0);
|
|
t.is(result.reason.message, 'Non-error thrown with value: 0');
|
|
t.is(result.reason.name, 'AssertionError');
|
|
t.is(result.reason.operator, 'catch');
|
|
t.end();
|
|
});
|
|
|
|
test('fails with thrown non-error object', function (t) {
|
|
var obj = {foo: 'bar'};
|
|
var result = ava(function () {
|
|
throw obj;
|
|
}).run();
|
|
|
|
t.is(result.passed, false);
|
|
t.is(result.reason.actual, obj);
|
|
t.is(result.reason.message, 'Non-error thrown with value: { foo: \'bar\' }');
|
|
t.is(result.reason.name, 'AssertionError');
|
|
t.is(result.reason.operator, 'catch');
|
|
t.end();
|
|
});
|
|
|
|
test('skipped assertions count towards the plan', function (t) {
|
|
var result = ava(function (a) {
|
|
a.plan(2);
|
|
a.pass();
|
|
a.skip.fail();
|
|
}).run();
|
|
|
|
t.is(result.passed, true);
|
|
t.is(result.result.planCount, 2);
|
|
t.is(result.result.assertCount, 2);
|
|
t.end();
|
|
});
|
|
|
|
test('throws and notThrows work with promises', function (t) {
|
|
var asyncCalled = false;
|
|
ava(function (a) {
|
|
a.plan(2);
|
|
a.throws(delay.reject(10, new Error('foo')), 'foo');
|
|
a.notThrows(delay(20).then(function () {
|
|
asyncCalled = true;
|
|
}));
|
|
}).run().then(function (result) {
|
|
t.is(result.passed, true);
|
|
t.is(result.result.planCount, 2);
|
|
t.is(result.result.assertCount, 2);
|
|
t.is(asyncCalled, true);
|
|
t.end();
|
|
});
|
|
});
|
|
|
|
test('waits for t.throws to resolve after t.end is called', function (t) {
|
|
ava.cb(function (a) {
|
|
a.plan(1);
|
|
a.notThrows(delay(10), 'foo');
|
|
a.end();
|
|
}).run().then(function (result) {
|
|
t.is(result.passed, true);
|
|
t.is(result.result.planCount, 1);
|
|
t.is(result.result.assertCount, 1);
|
|
t.end();
|
|
});
|
|
});
|
|
|
|
test('waits for t.throws to reject after t.end is called', function (t) {
|
|
ava.cb(function (a) {
|
|
a.plan(1);
|
|
a.throws(delay.reject(10, new Error('foo')), 'foo');
|
|
a.end();
|
|
}).run().then(function (result) {
|
|
t.is(result.passed, true);
|
|
t.is(result.result.planCount, 1);
|
|
t.is(result.result.assertCount, 1);
|
|
t.end();
|
|
});
|
|
});
|
|
|
|
test('waits for t.throws to resolve after the promise returned from the test resolves', function (t) {
|
|
ava(function (a) {
|
|
a.plan(1);
|
|
a.notThrows(delay(10), 'foo');
|
|
return Promise.resolve();
|
|
}).run().then(function (result) {
|
|
t.is(result.passed, true);
|
|
t.is(result.result.planCount, 1);
|
|
t.is(result.result.assertCount, 1);
|
|
t.end();
|
|
});
|
|
});
|
|
|
|
test('waits for t.throws to reject after the promise returned from the test resolves', function (t) {
|
|
ava(function (a) {
|
|
a.plan(1);
|
|
a.throws(delay.reject(10, new Error('foo')), 'foo');
|
|
return Promise.resolve();
|
|
}).run().then(function (result) {
|
|
t.is(result.passed, true);
|
|
t.is(result.result.planCount, 1);
|
|
t.is(result.result.assertCount, 1);
|
|
t.end();
|
|
});
|
|
});
|
|
|
|
test('multiple resolving and rejecting promises passed to t.throws/t.notThrows', function (t) {
|
|
ava(function (a) {
|
|
a.plan(6);
|
|
for (var i = 0; i < 3; ++i) {
|
|
a.throws(delay.reject(10, new Error('foo')), 'foo');
|
|
a.notThrows(delay(10), 'foo');
|
|
}
|
|
}).run().then(function (result) {
|
|
t.is(result.passed, true);
|
|
t.is(result.result.planCount, 6);
|
|
t.is(result.result.assertCount, 6);
|
|
t.end();
|
|
});
|
|
});
|
|
|
|
test('number of assertions matches t.plan when the test exits, but before all promises resolve another is added', function (t) {
|
|
ava(function (a) {
|
|
a.plan(2);
|
|
a.throws(delay.reject(10, new Error('foo')), 'foo');
|
|
a.notThrows(delay(10), 'foo');
|
|
setTimeout(function () {
|
|
a.throws(Promise.reject(new Error('foo')), 'foo');
|
|
}, 5);
|
|
}).run().then(function (result) {
|
|
t.is(result.passed, false);
|
|
t.is(result.reason.operator, 'plan');
|
|
t.is(result.reason.actual, 3);
|
|
t.is(result.reason.expected, 2);
|
|
t.end();
|
|
});
|
|
});
|
|
|
|
test('number of assertions doesn\'t match plan when the test exits, but before all promises resolve another is added', function (t) {
|
|
ava(function (a) {
|
|
a.plan(3);
|
|
a.throws(delay.reject(10, new Error('foo')), 'foo');
|
|
a.notThrows(delay(10), 'foo');
|
|
setTimeout(function () {
|
|
a.throws(Promise.reject(new Error('foo')), 'foo');
|
|
}, 5);
|
|
}).run().then(function (result) {
|
|
t.is(result.passed, false);
|
|
t.is(result.reason.operator, 'plan');
|
|
t.is(result.reason.actual, 2);
|
|
t.is(result.reason.expected, 3);
|
|
t.end();
|
|
});
|
|
});
|
|
|
|
test('assertions return promises', function (t) {
|
|
ava(function (a) {
|
|
a.plan(2);
|
|
t.ok(isPromise(a.throws(Promise.reject(new Error('foo')))));
|
|
t.ok(isPromise(a.notThrows(Promise.resolve(true))));
|
|
}).run().then(function (result) {
|
|
t.is(result.passed, true);
|
|
t.end();
|
|
});
|
|
});
|
|
|
|
test('contextRef', function (t) {
|
|
new Test('foo',
|
|
function (a) {
|
|
t.same(a.context, {foo: 'bar'});
|
|
t.end();
|
|
},
|
|
{context: {foo: 'bar'}}
|
|
).run();
|
|
});
|
|
|
|
test('it is an error to set context in a hook', function (t) {
|
|
var avaTest = ava(function (a) {
|
|
a.context = 'foo';
|
|
});
|
|
avaTest.metadata.type = 'foo';
|
|
|
|
var result = avaTest.run();
|
|
t.is(result.passed, false);
|
|
t.match(result.reason.message, /t\.context is not available in foo tests/);
|
|
t.end();
|
|
});
|
|
|