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.
 

619 lines
15 KiB

'use strict';
var path = require('path');
var figures = require('figures');
var rimraf = require('rimraf');
var fs = require('fs');
var test = require('tap').test;
var Api = require('../api');
test('must be called with new', function (t) {
t.throws(function () {
var api = Api;
api([path.join(__dirname, 'fixture/es2015.js')]);
}, {message: 'Class constructor Api cannot be invoked without \'new\''});
t.end();
});
test('ES2015 support', function (t) {
t.plan(1);
var api = new Api([path.join(__dirname, 'fixture/es2015.js')]);
api.run()
.then(function () {
t.is(api.passCount, 1);
});
});
test('generators support', function (t) {
t.plan(1);
var api = new Api([path.join(__dirname, 'fixture/generators.js')]);
api.run()
.then(function () {
t.is(api.passCount, 1);
});
});
test('async/await support', function (t) {
t.plan(1);
var api = new Api([path.join(__dirname, 'fixture/async-await.js')]);
api.run()
.then(function () {
t.is(api.passCount, 2);
});
});
test('test title prefixes — multiple files', function (t) {
t.plan(6);
var separator = ' ' + figures.pointerSmall + ' ';
var files = [
path.join(__dirname, 'fixture/async-await.js'),
path.join(__dirname, 'fixture/es2015.js'),
path.join(__dirname, 'fixture/generators.js'),
path.join(__dirname, 'fixture/subdir/in-a-subdir.js')
];
var expected = [
['async-await', 'async function'].join(separator),
['async-await', 'arrow async function'].join(separator),
['es2015', '[anonymous]'].join(separator),
['generators', 'generator function'].join(separator),
['subdir', 'in-a-subdir', 'subdir'].join(separator)
];
var index;
var api = new Api(files);
api.run()
.then(function () {
// if all lines were removed from expected output
// actual output matches expected output
t.is(expected.length, 0);
});
api.on('test', function (a) {
index = expected.indexOf(a.title);
t.true(index >= 0);
// remove line from expected output
expected.splice(index, 1);
});
});
test('test title prefixes — single file', function (t) {
t.plan(2);
var separator = ' ' + figures.pointerSmall + ' ';
var files = [
path.join(__dirname, 'fixture/generators.js')
];
var expected = [
['generator function'].join(separator)
];
var index;
var api = new Api(files);
api.run()
.then(function () {
// if all lines were removed from expected output
// actual output matches expected output
t.is(expected.length, 0);
});
api.on('test', function (a) {
index = expected.indexOf(a.title);
t.true(index >= 0);
// remove line from expected output
expected.splice(index, 1);
});
});
test('test title prefixes — single file (explicit)', function (t) {
t.plan(2);
var separator = ' ' + figures.pointerSmall + ' ';
var files = [
path.join(__dirname, 'fixture/generators.js')
];
var expected = [
['generators', 'generator function'].join(separator)
];
var index;
var api = new Api();
api.run(files)
.then(function () {
// if all lines were removed from expected output
// actual output matches expected output
t.is(expected.length, 0);
});
api.on('test', function (a) {
index = expected.indexOf(a.title);
t.true(index >= 0);
// remove line from expected output
expected.splice(index, 1);
});
});
test('display filename prefixes for failed test stack traces', function (t) {
t.plan(3);
var files = [
path.join(__dirname, 'fixture/es2015.js'),
path.join(__dirname, 'fixture/one-pass-one-fail.js')
];
var api = new Api(files);
api.run()
.then(function () {
t.is(api.passCount, 2);
t.is(api.failCount, 1);
t.match(api.errors[0].title, /one-pass-one-fail \S this is a failing test/);
});
});
// This is a seperate test because we can't ensure the order of the errors (to match them), and this is easier than
// sorting.
test('display filename prefixes for failed test stack traces in subdirs', function (t) {
t.plan(3);
var files = [
path.join(__dirname, 'fixture/es2015.js'),
path.join(__dirname, 'fixture/subdir/failing-subdir.js')
];
var api = new Api(files);
api.run()
.then(function () {
t.is(api.passCount, 1);
t.is(api.failCount, 1);
t.match(api.errors[0].title, /subdir \S failing-subdir \S subdir fail/);
});
});
test('fail-fast mode', function (t) {
t.plan(5);
var api = new Api([path.join(__dirname, 'fixture/fail-fast.js')], {
failFast: true
});
var tests = [];
api.on('test', function (test) {
tests.push({
ok: !test.error,
title: test.title
});
});
api.run()
.then(function () {
t.ok(api.options.failFast);
t.same(tests, [{
ok: true,
title: 'first pass'
}, {
ok: false,
title: 'second fail'
}]);
t.is(api.passCount, 1);
t.is(api.failCount, 1);
t.match(api.errors[0].error.message, /Test failed via t.fail()/);
});
});
test('serial execution mode', function (t) {
t.plan(3);
var api = new Api([path.join(__dirname, 'fixture/serial.js')], {
serial: true
});
api.run()
.then(function () {
t.ok(api.options.serial);
t.is(api.passCount, 3);
t.is(api.failCount, 0);
});
});
test('circular references on assertions do not break process.send', function (t) {
t.plan(2);
var api = new Api([path.join(__dirname, 'fixture/circular-reference-on-assertion.js')]);
api.run()
.then(function () {
t.is(api.failCount, 1);
t.match(api.errors[0].error.message, /'c'.*?'d'/);
});
});
test('change process.cwd() to a test\'s directory', function (t) {
t.plan(1);
var api = new Api([path.join(__dirname, 'fixture/process-cwd.js')]);
api.run()
.then(function () {
t.is(api.passCount, 1);
});
});
test('unhandled promises will throw an error', function (t) {
t.plan(3);
var api = new Api([path.join(__dirname, 'fixture/loud-rejection.js')]);
api.on('error', function (data) {
t.is(data.name, 'Error');
t.match(data.message, /You can\'t handle this!/);
});
api.run()
.then(function () {
t.is(api.passCount, 1);
});
});
test('uncaught exception will throw an error', function (t) {
t.plan(3);
var api = new Api([path.join(__dirname, 'fixture/uncaught-exception.js')]);
api.on('error', function (data) {
t.is(data.name, 'Error');
t.match(data.message, /Can\'t catch me!/);
});
api.run()
.then(function () {
t.is(api.passCount, 1);
});
});
test('stack traces for exceptions are corrected using a source map file', function (t) {
t.plan(4);
var api = new Api([path.join(__dirname, 'fixture/source-map-file.js')], {cacheEnabled: true});
api.on('error', function (data) {
t.match(data.message, /Thrown by source-map-fixtures/);
t.match(data.stack, /^.*?Object\.t.*?as run\b.*source-map-fixtures.src.throws.js:1.*$/m);
t.match(data.stack, /^.*?Immediate\b.*source-map-file.js:11.*$/m);
});
api.run()
.then(function () {
t.is(api.passCount, 1);
});
});
test('stack traces for exceptions are corrected using a source map file (cache off)', function (t) {
t.plan(4);
var api = new Api([path.join(__dirname, 'fixture/source-map-file.js')], {cacheEnabled: false});
api.on('error', function (data) {
t.match(data.message, /Thrown by source-map-fixtures/);
t.match(data.stack, /^.*?Object\.t.*?as run\b.*source-map-fixtures.src.throws.js:1.*$/m);
t.match(data.stack, /^.*?Immediate\b.*source-map-file.js:11.*$/m);
});
api.run()
.then(function () {
t.is(api.passCount, 1);
});
});
test('stack traces for exceptions are corrected using a source map, taking an initial source map for the test file into account (cache on)', function (t) {
t.plan(4);
var api = new Api([path.join(__dirname, 'fixture/source-map-initial.js')], {cacheEnabled: true});
api.on('error', function (data) {
t.match(data.message, /Thrown by source-map-fixtures/);
t.match(data.stack, /^.*?Object\.t.*?as run\b.*source-map-fixtures.src.throws.js:1.*$/m);
t.match(data.stack, /^.*?Immediate\b.*source-map-initial-input.js:7.*$/m);
});
api.run()
.then(function () {
t.is(api.passCount, 1);
});
});
test('stack traces for exceptions are corrected using a source map, taking an initial source map for the test file into account (cache off)', function (t) {
t.plan(4);
var api = new Api([path.join(__dirname, 'fixture/source-map-initial.js')], {cacheEnabled: false});
api.on('error', function (data) {
t.match(data.message, /Thrown by source-map-fixtures/);
t.match(data.stack, /^.*?Object\.t.*?as run\b.*source-map-fixtures.src.throws.js:1.*$/m);
t.match(data.stack, /^.*?Immediate\b.*source-map-initial-input.js:7.*$/m);
});
api.run()
.then(function () {
t.is(api.passCount, 1);
});
});
test('absolute paths', function (t) {
t.plan(1);
var api = new Api([path.resolve('test/fixture/es2015.js')]);
api.run()
.then(function () {
t.is(api.passCount, 1);
});
});
test('search directories recursively for files', function (t) {
t.plan(2);
var api = new Api([path.join(__dirname, 'fixture/subdir')]);
api.run()
.then(function () {
t.is(api.passCount, 2);
t.is(api.failCount, 1);
});
});
test('titles of both passing and failing tests and AssertionErrors are returned', function (t) {
t.plan(3);
var api = new Api([path.join(__dirname, 'fixture/one-pass-one-fail.js')]);
api.run()
.then(function () {
t.match(api.errors[0].title, /this is a failing test/);
t.match(api.tests[0].title, /this is a passing test/);
t.match(api.errors[0].error.name, /AssertionError/);
});
});
test('empty test files cause an AvaError to be emitted', function (t) {
t.plan(2);
var api = new Api([path.join(__dirname, 'fixture/empty.js')]);
api.on('error', function (err) {
t.is(err.name, 'AvaError');
t.match(err.message, /No tests found.*?import "ava"/);
});
return api.run();
});
test('test file with no tests causes an AvaError to be emitted', function (t) {
t.plan(2);
var api = new Api([path.join(__dirname, 'fixture/no-tests.js')]);
api.on('error', function (err) {
t.is(err.name, 'AvaError');
t.match(err.message, /No tests/);
});
return api.run();
});
test('test file that immediately exits with 0 exit code ', function (t) {
t.plan(2);
var api = new Api([path.join(__dirname, 'fixture/immediate-0-exit.js')]);
api.on('error', function (err) {
t.is(err.name, 'AvaError');
t.match(err.message, /Test results were not received from/);
});
return api.run();
});
test('testing nonexistent files causes an AvaError to be emitted', function (t) {
t.plan(2);
var api = new Api([path.join(__dirname, 'fixture/broken.js')]);
api.on('error', function (err) {
t.is(err.name, 'AvaError');
t.match(err.message, /Couldn't find any files to test/);
});
return api.run();
});
test('test file in node_modules is ignored', function (t) {
t.plan(2);
var api = new Api([path.join(__dirname, 'fixture/ignored-dirs/node_modules/test.js')]);
api.on('error', function (err) {
t.is(err.name, 'AvaError');
t.match(err.message, /Couldn't find any files to test/);
});
return api.run();
});
test('test file in node_modules is ignored (explicit)', function (t) {
t.plan(2);
var api = new Api();
api.on('error', function (err) {
t.is(err.name, 'AvaError');
t.match(err.message, /Couldn't find any files to test/);
});
return api.run([path.join(__dirname, 'fixture/ignored-dirs/node_modules/test.js')]);
});
test('test file in fixtures is ignored', function (t) {
t.plan(2);
var api = new Api([path.join(__dirname, 'fixture/ignored-dirs/fixtures/test.js')]);
api.on('error', function (err) {
t.is(err.name, 'AvaError');
t.match(err.message, /Couldn't find any files to test/);
});
return api.run();
});
test('test file in fixtures is ignored (explicit)', function (t) {
t.plan(2);
var api = new Api();
api.on('error', function (err) {
t.is(err.name, 'AvaError');
t.match(err.message, /Couldn't find any files to test/);
});
return api.run([path.join(__dirname, 'fixture/ignored-dirs/fixtures/test.js')]);
});
test('test file in helpers is ignored', function (t) {
t.plan(2);
var api = new Api([path.join(__dirname, 'fixture/ignored-dirs/helpers/test.js')]);
api.on('error', function (err) {
t.is(err.name, 'AvaError');
t.match(err.message, /Couldn't find any files to test/);
});
return api.run();
});
test('test file in helpers is ignored (explicit)', function (t) {
t.plan(2);
var api = new Api();
api.on('error', function (err) {
t.is(err.name, 'AvaError');
t.match(err.message, /Couldn't find any files to test/);
});
return api.run([path.join(__dirname, 'fixture/ignored-dirs/helpers/test.js')]);
});
test('Node.js-style --require CLI argument', function (t) {
t.plan(1);
var requirePath = './' + path.relative('.', path.join(__dirname, 'fixture/install-global.js')).replace(/\\/g, '/');
var api = new Api(
[path.join(__dirname, 'fixture/validate-installed-global.js')],
{require: [requirePath]}
);
api.run()
.then(function () {
t.is(api.passCount, 1);
});
});
test('power-assert support', function (t) {
t.plan(3);
var api = new Api([path.join(__dirname, 'fixture/power-assert.js')]);
api.run()
.then(function () {
t.ok(api.errors[0].error.powerAssertContext);
t.match(
api.errors[0].error.message,
/t\.ok\(a === 'bar'\)\s*\n\s+\|\s*\n\s+"foo"/m
);
t.match(
api.errors[1].error.message,
/with message\s+t\.ok\(a === 'foo', 'with message'\)\s*\n\s+\|\s*\n\s+"bar"/m
);
});
});
test('caching is enabled by default', function (t) {
t.plan(3);
rimraf.sync(path.join(__dirname, 'fixture/caching/node_modules'));
var api = new Api([path.join(__dirname, 'fixture/caching/test.js')]);
api.run()
.then(function () {
var files = fs.readdirSync(path.join(__dirname, 'fixture/caching/node_modules/.cache/ava'));
t.is(files.length, 2);
t.is(files.filter(endsWithJs).length, 1);
t.is(files.filter(endsWithMap).length, 1);
t.end();
});
function endsWithJs(filename) {
return /\.js$/.test(filename);
}
function endsWithMap(filename) {
return /\.js$/.test(filename);
}
});
test('caching can be disabled', function (t) {
t.plan(1);
rimraf.sync(path.join(__dirname, 'fixture/caching/node_modules'));
var api = new Api([path.join(__dirname, 'fixture/caching/test.js')], {cacheEnabled: false});
api.run()
.then(function () {
t.false(fs.existsSync(path.join(__dirname, 'fixture/caching/node_modules/.cache/ava')));
t.end();
});
});
test('test file with only skipped tests does not create a failure', function (t) {
t.plan(2);
var api = new Api([path.join(__dirname, 'fixture/skip-only.js')]);
api.run()
.then(function () {
t.is(api.tests.length, 1);
t.true(api.tests[0].skip);
});
});
test('resets state before running', function (t) {
t.plan(2);
var api = new Api([path.resolve('test/fixture/es2015.js')]);
api.run().then(function () {
t.is(api.passCount, 1);
return api.run();
}).then(function () {
t.is(api.passCount, 1);
});
});