Browse Source

Simplify Concurrent and Sequence

There's no need to collect all results. Tests emit them directly.
master
Mark Wubben 8 years ago
parent
commit
88955027dc
  1. 100
      lib/concurrent.js
  2. 99
      lib/sequence.js
  3. 840
      test/concurrent.js
  4. 826
      test/sequence.js

100
lib/concurrent.js

@ -1,82 +1,64 @@
'use strict';
const Promise = require('bluebird');
const isPromise = require('is-promise');
const autoBind = require('auto-bind');
const AvaError = require('./ava-error');
class Concurrent {
constructor(tests, bail) {
if (!Array.isArray(tests)) {
throw new TypeError('Expected an array of tests');
constructor(runnables, bail) {
if (!Array.isArray(runnables)) {
throw new TypeError('Expected an array of runnables');
}
this.results = [];
this.passed = true;
this.reason = null;
this.tests = tests;
this.runnables = runnables;
this.bail = bail || false;
autoBind(this);
}
run() {
let results;
let allPassed = true;
try {
results = this.tests.map(this._runTest);
} catch (err) {
if (err instanceof AvaError) {
return this._results();
let pending;
let rejectPending;
let resolvePending;
const allPromises = [];
const handlePromise = promise => {
if (!pending) {
pending = new Promise((resolve, reject) => {
rejectPending = reject;
resolvePending = resolve;
});
}
throw err;
}
const isAsync = results.some(isPromise);
if (isAsync) {
return Promise.all(results)
.catch(AvaError, () => {})
.then(this._results);
}
return this._results();
}
_runTest(test, index) {
const result = test.run();
allPromises.push(promise.then(result => {
if (!result.passed) {
allPassed = false;
if (isPromise(result)) {
return result.then(result => this._addResult(result, index));
}
if (this.bail) {
// Stop if the test failed and bail mode is on.
resolvePending();
}
}
}, rejectPending));
};
return this._addResult(result, index);
}
_addResult(result, index) {
// Always save result when not in bail mode or all previous tests pass
if ((this.bail && this.passed) || !this.bail) {
this.results[index] = result;
}
for (const runnable of this.runnables) {
const result = runnable.run();
if (result.passed === false) {
this.passed = false;
if (isPromise(result)) {
handlePromise(result);
} else if (!result.passed) {
if (this.bail) {
// Stop if the test failed and bail mode is on.
return {passed: false};
}
// Only set reason once
if (!this.reason) {
this.reason = result.reason;
allPassed = false;
}
}
if (this.bail) {
throw new AvaError('Error in Concurrent while in bail mode');
}
if (pending) {
Promise.all(allPromises).then(resolvePending);
return pending.then(() => ({passed: allPassed}));
}
return result;
}
_results() {
return {
passed: this.passed,
reason: this.reason,
result: this.results
};
return {passed: allPassed};
}
}

99
lib/sequence.js

@ -1,86 +1,59 @@
'use strict';
const isPromise = require('is-promise');
const autoBind = require('auto-bind');
const AvaError = require('./ava-error');
class Sequence {
constructor(tests, bail) {
if (!tests) {
throw new Error('Sequence items can\'t be undefined');
constructor(runnables, bail) {
if (!Array.isArray(runnables)) {
throw new TypeError('Expected an array of runnables');
}
this.results = [];
this.passed = true;
this.reason = null;
this.tests = tests;
this.runnables = runnables;
this.bail = bail || false;
autoBind(this);
}
run() {
const length = this.tests.length;
const iterator = this.runnables[Symbol.iterator]();
for (let i = 0; i < length; i++) {
// If last item failed and we should bail, return results and stop
if (this.bail && !this.passed) {
return this._results();
}
let allPassed = true;
const runNext = () => {
let promise;
const result = this.tests[i].run();
for (let next = iterator.next(); !next.done; next = iterator.next()) {
const result = next.value.run();
if (isPromise(result)) {
promise = result;
break;
}
// If a Promise returned, we don't need to check for Promises after this test
// so we can just use Promise.each() on the rest of the tests
if (isPromise(result)) {
return result
.then(this._addResult)
.return(this.tests.slice(i + 1))
.each(this._runTest)
.catch(AvaError, () => {})
.then(this._results);
}
if (!result.passed) {
allPassed = false;
try {
this._addResult(result);
} catch (err) {
// In bail mode, don't execute the next tests
if (err instanceof AvaError) {
return this._results();
if (this.bail) {
// Stop if the test failed and bail mode is on.
break;
}
}
throw err;
}
}
return this._results();
}
_runTest(test) {
const result = test.run();
return isPromise(result) ? result.then(this._addResult) : this._addResult(result);
}
_addResult(result) {
this.results.push(result);
if (result.passed === false) {
this.passed = false;
// Only set reason once
if (!this.reason) {
this.reason = result.reason;
if (!promise) {
return {passed: allPassed};
}
if (this.bail) {
throw new AvaError('Error in Sequence while in bail mode');
}
}
return promise.then(result => {
if (!result.passed) {
allPassed = false;
return result;
}
_results() {
return {
passed: this.passed,
reason: this.reason,
result: this.results
if (this.bail) {
// Stop if the test failed and bail mode is on.
return {passed: false};
}
}
return runNext();
});
};
return runNext();
}
}

840
test/concurrent.js

File diff suppressed because it is too large

826
test/sequence.js

File diff suppressed because it is too large
Loading…
Cancel
Save