Browse Source

clean up test-collection

babel-plugin-for-integration-tests
vdemedes 9 years ago
parent
commit
e9b69bb515
  1. 2
      index.js
  2. 4
      lib/runner.js
  3. 231
      lib/test-collection.js
  4. 111
      test/test-collection.js

2
index.js

@ -68,7 +68,7 @@ function exit() {
}
globals.setImmediate(function () {
var numberOfTests = runner.tests.concurrent.length + runner.tests.serial.length;
var numberOfTests = runner.tests.tests.concurrent.length + runner.tests.tests.serial.length;
if (numberOfTests === 0) {
send('no-tests', {avaRequired: true});

4
lib/runner.js

@ -96,7 +96,9 @@ Runner.prototype.run = function () {
testCount: 0
};
return Promise.resolve(this.tests.buildPhases(this._addTestResult, this._bail).run()).then(function () {
this.tests.on('test', this._addTestResult);
return Promise.resolve(this.tests.build(this._bail).run()).then(function () {
stats.passCount = stats.testCount - stats.failCount - stats.skipCount;
});
};

231
lib/test-collection.js

@ -1,4 +1,11 @@
'use strict';
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var fnName = require('fn-name');
var Concurrent = require('./concurrent');
var Sequence = require('./sequence');
var Test = require('./test');
module.exports = TestCollection;
function TestCollection() {
@ -6,158 +13,168 @@ function TestCollection() {
throw new TypeError('Class constructor TestCollection cannot be invoked without \'new\'');
}
this.serial = [];
this.concurrent = [];
EventEmitter.call(this);
this.hasExclusive = false;
this.tests = {
concurrent: [],
serial: []
};
this.hooks = {
before: [],
beforeEach: [],
after: [],
afterEach: []
};
this.hasExclusive = false;
this._emitTestResult = this._emitTestResult.bind(this);
}
util.inherits(TestCollection, EventEmitter);
TestCollection.prototype.add = function (test) {
var metadata = test.metadata;
var type = metadata.type;
if (!type) {
throw new Error('test type must be specified');
throw new Error('Test type must be specified');
}
if (!test.title && test.fn) {
test.title = fnName(test.fn);
}
// workaround for Babel giving anonymous functions a name
if (test.title === 'callee$0$0') {
test.title = null;
}
if (type === 'test') {
if (this.hasExclusive && !metadata.exclusive) {
return;
if (!test.title) {
if (type === 'test') {
test.title = '[anonymous]';
} else {
test.title = type;
}
}
if (metadata.exclusive && !this.hasExclusive) {
this.hasExclusive = true;
this.serial = [];
this.concurrent = [];
// add a hook
if (type !== 'test') {
if (metadata.exclusive) {
throw new Error('"only" cannot be used with a ' + type + ' test');
}
(metadata.serial ? this.serial : this.concurrent).push(test);
this.hooks[type].push(test);
return;
}
// add .only() tests if .only() was used previously
if (this.hasExclusive && !metadata.exclusive) {
return;
}
if (metadata.exclusive) {
throw new Error('you can\'t use "only" with a ' + type + ' test');
if (metadata.exclusive && !this.hasExclusive) {
this.tests.concurrent = [];
this.tests.serial = [];
this.hasExclusive = true;
}
this.tests[type].push(test);
if (metadata.serial) {
this.tests.serial.push(test);
} else {
this.tests.concurrent.push(test);
}
};
var fnName = require('fn-name');
var Sequence = require('./sequence');
var Concurrent = require('./concurrent');
var Test = require('./test');
TestCollection.prototype._skippedTest = function (test) {
var self = this;
function computeTitle(entry) {
entry.title = entry.title || fnName(entry.fn);
return {
run: function () {
var result = {
passed: true,
result: test
};
// workaround for Babel giving anonymous functions a name
if (entry.title === 'callee$0$0') {
entry.title = null;
}
self._emitTestResult(result);
if (!entry.title) {
if (entry.metadata.type === 'test') {
entry.title = '[anonymous]';
} else {
entry.title = entry.metadata.type;
return result;
}
}
}
};
};
TestCollection.prototype._emitTestResult = function (test) {
this.emit('test', test);
};
function buildHooks(hookArray, title, contextRef, report) {
return hookArray.map(function (hook) {
var test = buildHook(hook, title, contextRef, report);
TestCollection.prototype._buildHooks = function (hooks, testTitle, context) {
return hooks.map(function (hook) {
var test = this._buildHook(hook, testTitle, context);
if (hook.metadata.skipped) {
return skipRunner(test, report);
return this._skippedTest(test);
}
return test;
});
}
}, this);
};
TestCollection.prototype._buildHook = function (hook, testTitle, context) {
var title = hook.title;
if (testTitle) {
title += ' for ' + testTitle;
}
if (!context) {
context = null;
}
function buildHook(hook, title, contextRef, report) {
var test = new Test(hook.title + ' for ' + title, hook.fn, contextRef, report);
var test = new Test(title, hook.fn, context, this._emitTestResult);
test.metadata = hook.metadata;
return test;
}
function buildTest(entry, ctxRef, report) {
var test = new Test(entry.title, entry.fn, ctxRef, report);
test.metadata = entry.metadata;
return test;
}
};
function skipRunner(test, report) {
return {
run: function () {
var result = {
passed: true,
result: test
};
if (report) {
report(result);
}
return result;
}
};
}
TestCollection.prototype._buildTest = function (test, context) {
if (!context) {
context = null;
}
var metadata = test.metadata;
function buildTestWithHooks(entry, beforeEach, afterEach, report) {
if (entry.metadata.skipped) {
return [skipRunner(buildTest(entry), report)];
test = new Test(test.title, test.fn, context, this._emitTestResult);
test.metadata = metadata;
return test;
};
TestCollection.prototype._buildTestWithHooks = function (test) {
if (test.metadata.skipped) {
return [this._skippedTest(this._buildTest(test))];
}
var contextRef = {context: {}};
var arr = buildHooks(beforeEach, entry.title, contextRef, report);
arr.push(buildTest(entry, contextRef, report));
var context = {context: {}};
return arr.concat(buildHooks(afterEach, entry.title, contextRef, report));
}
var beforeHooks = this._buildHooks(this.hooks.beforeEach, test.title, context);
var afterHooks = this._buildHooks(this.hooks.afterEach, test.title, context);
return [].concat(beforeHooks, this._buildTest(test, context), afterHooks);
};
TestCollection.prototype._buildTests = function (tests) {
return tests.map(function (test) {
return new Sequence(this._buildTestWithHooks(test), true);
}, this);
};
TestCollection.prototype.build = function (bail) {
var beforeHooks = new Sequence(this._buildHooks(this.hooks.before));
var afterHooks = new Sequence(this._buildHooks(this.hooks.after));
var serialTests = new Sequence(this._buildTests(this.tests.serial), bail);
var concurrentTests = new Concurrent(this._buildTests(this.tests.concurrent), bail);
var allTests = new Sequence([serialTests, concurrentTests]);
TestCollection.prototype.buildPhases = function (report, bail) {
[
this.serial,
this.concurrent,
this.tests.before,
this.tests.beforeEach,
this.tests.after,
this.tests.afterEach
].forEach(function (arr) {
arr.forEach(computeTitle);
});
return new Sequence(
[
new Sequence(this.tests.before.map(function (entry) {
if (entry.metadata.skipped) {
return skipRunner(entry, report);
}
return buildTest(entry, null, report);
})),
new Sequence([
new Sequence(this.serial.map(function (entry) {
return new Sequence(buildTestWithHooks(entry, this.tests.beforeEach, this.tests.afterEach, report), true);
}, this), bail),
new Concurrent(this.concurrent.map(function (entry) {
return new Sequence(buildTestWithHooks(entry, this.tests.beforeEach, this.tests.afterEach, report), true);
}, this), bail)
], bail),
new Sequence(this.tests.after.map(function (entry) {
if (entry.metadata.skipped) {
return skipRunner(entry, report);
}
return buildTest(entry, null, report);
}))
],
true
);
return new Sequence([beforeHooks, allTests, afterHooks], true);
};

111
test/test-collection.js

@ -24,25 +24,56 @@ function mockTest(opts, title) {
}
function titles(tests) {
if (!tests) {
tests = [];
}
return tests.map(function (test) {
return test.title;
});
}
function removeEmptyProps(obj) {
if (Array.isArray(obj) && obj.length === 0) {
return null;
}
if (obj.constructor !== Object) {
return obj;
}
var cleanObj = null;
Object.keys(obj).forEach(function (key) {
var value = removeEmptyProps(obj[key]);
if (value) {
if (!cleanObj) {
cleanObj = {};
}
cleanObj[key] = value;
}
});
return cleanObj;
}
function serialize(collection) {
var ret = {};
function addTitles(name, source) {
if (source[name] && source[name].length) {
ret[name] = titles(source[name]);
var serialized = {
tests: {
concurrent: titles(collection.tests.concurrent),
serial: titles(collection.tests.serial)
},
hooks: {
before: titles(collection.hooks.before),
beforeEach: titles(collection.hooks.beforeEach),
after: titles(collection.hooks.after),
afterEach: titles(collection.hooks.afterEach)
}
}
addTitles('serial', collection);
addTitles('concurrent', collection);
addTitles('before', collection.tests);
addTitles('beforeEach', collection.tests);
addTitles('after', collection.tests);
addTitles('afterEach', collection.tests);
return ret;
};
return removeEmptyProps(serialized);
}
test('requires new', function (t) {
@ -57,7 +88,7 @@ test('throws if no type is supplied', function (t) {
var collection = new TestCollection();
t.throws(function () {
collection.add({title: 'someTitle', metadata: {}});
}, {message: 'test type must be specified'});
}, {message: 'Test type must be specified'});
t.end();
});
@ -65,7 +96,7 @@ test('throws if you try to set a hook as exclusive', function (t) {
var collection = new TestCollection();
t.throws(function () {
collection.add(mockTest({type: 'beforeEach', exclusive: true}));
}, {message: 'you can\'t use "only" with a beforeEach test'});
}, {message: '"only" cannot be used with a beforeEach test'});
t.end();
});
@ -80,42 +111,66 @@ test('hasExclusive is set when an exclusive test is added', function (t) {
test('adding a concurrent test', function (t) {
var collection = new TestCollection();
collection.add(mockTest({}, 'foo'));
t.same(serialize(collection), {concurrent: ['foo']});
t.same(serialize(collection), {
tests: {
concurrent: ['foo']
}
});
t.end();
});
test('adding a serial test', function (t) {
var collection = new TestCollection();
collection.add(mockTest({serial: true}, 'bar'));
t.same(serialize(collection), {serial: ['bar']});
t.same(serialize(collection), {
tests: {
serial: ['bar']
}
});
t.end();
});
test('adding a before test', function (t) {
var collection = new TestCollection();
collection.add(mockTest({type: 'before'}, 'baz'));
t.same(serialize(collection), {before: ['baz']});
t.same(serialize(collection), {
hooks: {
before: ['baz']
}
});
t.end();
});
test('adding a beforeEach test', function (t) {
var collection = new TestCollection();
collection.add(mockTest({type: 'beforeEach'}, 'foo'));
t.same(serialize(collection), {beforeEach: ['foo']});
t.same(serialize(collection), {
hooks: {
beforeEach: ['foo']
}
});
t.end();
});
test('adding a after test', function (t) {
var collection = new TestCollection();
collection.add(mockTest({type: 'after'}, 'bar'));
t.same(serialize(collection), {after: ['bar']});
t.same(serialize(collection), {
hooks: {
after: ['bar']
}
});
t.end();
});
test('adding a afterEach test', function (t) {
var collection = new TestCollection();
collection.add(mockTest({type: 'afterEach'}, 'baz'));
t.same(serialize(collection), {afterEach: ['baz']});
t.same(serialize(collection), {
hooks: {
afterEach: ['baz']
}
});
t.end();
});
@ -127,9 +182,13 @@ test('adding a bunch of different types', function (t) {
collection.add(mockTest({serial: true}, 'd'));
collection.add(mockTest({type: 'before'}, 'e'));
t.same(serialize(collection), {
concurrent: ['a', 'b'],
serial: ['c', 'd'],
before: ['e']
tests: {
concurrent: ['a', 'b'],
serial: ['c', 'd']
},
hooks: {
before: ['e']
}
});
t.end();
});
@ -162,7 +221,7 @@ test('foo', function (t) {
add('after2', {type: 'after'});
add('before2', {type: 'before'});
var result = collection.buildPhases().run();
var result = collection.build().run();
t.is(result.passed, true);
@ -217,7 +276,9 @@ test('foo', function (t) {
add('after2', {type: 'after'});
add('before2', {type: 'before'});
var result = collection.buildPhases(logger).run();
collection.on('test', logger);
var result = collection.build().run();
t.is(result.passed, true);

Loading…
Cancel
Save