intern
Version:
Intern. A next-generation code testing stack for JavaScript.
542 lines • 21.8 kB
JavaScript
(function (factory) {
if (typeof module === "object" && typeof module.exports === "object") {
var v = factory(require, exports);
if (v !== undefined) module.exports = v;
}
else if (typeof define === "function" && define.amd) {
define(["require", "exports", "tslib", "@theintern/common", "./Deferred", "./Test", "./common/util", "./common/time"], factory);
}
})(function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isSuite = void 0;
var tslib_1 = require("tslib");
var common_1 = require("@theintern/common");
var Deferred_1 = tslib_1.__importDefault(require("./Deferred"));
var Test_1 = require("./Test");
var util_1 = require("./common/util");
var time_1 = require("./common/time");
var Suite = (function () {
function Suite(options) {
var _this = this;
this.publishAfterSetup = false;
this.tests = [];
Object.keys(options)
.filter(function (key) {
return key !== 'tests';
})
.forEach(function (option) {
var key = option;
_this[key] = options[key];
});
if (options.tests) {
options.tests.forEach(function (suiteOrTest) { return _this.add(suiteOrTest); });
}
if (!this.name && this.parent) {
throw new Error('A non-root Suite must have a name');
}
}
Object.defineProperty(Suite.prototype, "bail", {
get: function () {
return this._bail || (this.parent && this.parent.bail);
},
set: function (value) {
this._bail = value;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Suite.prototype, "executor", {
get: function () {
return (this.parent && this.parent.executor) || this._executor;
},
set: function (value) {
if (this._executor) {
var error = new Error('An executor may only be set once per suite');
error.name = 'AlreadyAssigned';
throw error;
}
this._executor = value;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Suite.prototype, "grep", {
get: function () {
return this._grep || (this.parent && this.parent.grep) || /.*/;
},
set: function (value) {
this._grep = value;
this._applyGrepToChildren();
},
enumerable: false,
configurable: true
});
Object.defineProperty(Suite.prototype, "name", {
get: function () {
return this._name;
},
set: function (value) {
this._name = value;
this._applyGrepToChildren();
},
enumerable: false,
configurable: true
});
Object.defineProperty(Suite.prototype, "id", {
get: function () {
var name = [];
var suite = this;
do {
suite.name != null && name.unshift(suite.name);
} while ((suite = suite.parent));
return name.join(' - ');
},
enumerable: false,
configurable: true
});
Object.defineProperty(Suite.prototype, "parentId", {
get: function () {
var parent = this.parent;
if (parent) {
return parent.id;
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(Suite.prototype, "remote", {
get: function () {
return this.parent && this.parent.remote
? this.parent.remote
: this._remote;
},
set: function (value) {
if (this._remote) {
throw new Error('AlreadyAssigned: remote may only be set once per suite');
}
this._remote = value;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Suite.prototype, "sessionId", {
get: function () {
if (this.parent) {
return this.parent.sessionId;
}
if (this._sessionId) {
return this._sessionId;
}
if (this.remote) {
return this.remote.session.sessionId;
}
return '';
},
set: function (value) {
this._sessionId = value;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Suite.prototype, "numTests", {
get: function () {
return this.tests.reduce(function (numTests, suiteOrTest) {
if (isSuite(suiteOrTest)) {
return numTests + suiteOrTest.numTests;
}
return numTests + 1;
}, 0);
},
enumerable: false,
configurable: true
});
Object.defineProperty(Suite.prototype, "numPassedTests", {
get: function () {
return this.tests.reduce(function (numPassedTests, suiteOrTest) {
if (isSuite(suiteOrTest)) {
return numPassedTests + suiteOrTest.numPassedTests;
}
else if (suiteOrTest.hasPassed) {
return numPassedTests + 1;
}
return numPassedTests;
}, 0);
},
enumerable: false,
configurable: true
});
Object.defineProperty(Suite.prototype, "numFailedTests", {
get: function () {
return this.tests.reduce(function (numFailedTests, suiteOrTest) {
if (isSuite(suiteOrTest)) {
return numFailedTests + suiteOrTest.numFailedTests;
}
else if (suiteOrTest.error) {
return numFailedTests + 1;
}
return numFailedTests;
}, 0);
},
enumerable: false,
configurable: true
});
Object.defineProperty(Suite.prototype, "numSkippedTests", {
get: function () {
return this.tests.reduce(function (numSkippedTests, suiteOrTest) {
if (isSuite(suiteOrTest)) {
return numSkippedTests + suiteOrTest.numSkippedTests;
}
else if (suiteOrTest.skipped) {
return numSkippedTests + 1;
}
return numSkippedTests;
}, 0);
},
enumerable: false,
configurable: true
});
Object.defineProperty(Suite.prototype, "hasParent", {
get: function () {
return Boolean(this.parent);
},
enumerable: false,
configurable: true
});
Object.defineProperty(Suite.prototype, "timeout", {
get: function () {
if (this._timeout != null) {
return this._timeout;
}
if (this.parent) {
return this.parent.timeout;
}
return 30000;
},
set: function (value) {
this._timeout = value;
},
enumerable: false,
configurable: true
});
Suite.prototype.add = function (suiteOrTest) {
if (!Test_1.isTest(suiteOrTest) && !isSuite(suiteOrTest)) {
throw new Error('Tried to add invalid suite or test');
}
if (suiteOrTest.parent != null && suiteOrTest.parent !== this) {
throw new Error('This Suite or Test already belongs to another parent');
}
this.tests.forEach(function (existingSuiteOrTest) {
if (existingSuiteOrTest.name === suiteOrTest.name) {
throw new Error("A suite or test named \"" + suiteOrTest.name + "\" has already been added");
}
});
suiteOrTest.parent = this;
this.tests.push(suiteOrTest);
this._applyGrepToSuiteOrTest(suiteOrTest);
if (Test_1.isTest(suiteOrTest)) {
this.executor.emit('testAdd', suiteOrTest);
}
else {
this.executor.emit('suiteAdd', suiteOrTest);
}
};
Suite.prototype._applyGrepToSuiteOrTest = function (suiteOrTest) {
if (suiteOrTest instanceof Suite) {
suiteOrTest._applyGrepToChildren();
}
else {
var grepSkipReason = 'grep';
if (suiteOrTest.skipped === grepSkipReason) {
suiteOrTest.skipped = undefined;
}
if (!this.grep.test(suiteOrTest.id)) {
suiteOrTest.skipped = grepSkipReason;
}
}
};
Suite.prototype._applyGrepToChildren = function () {
var _this = this;
this.tests.forEach(function (suiteOrTest) {
return _this._applyGrepToSuiteOrTest(suiteOrTest);
});
};
Suite.prototype.run = function () {
var _this = this;
var startTime;
var start = function () {
return _this.executor.emit('suiteStart', _this).then(function () {
startTime = time_1.now();
});
};
var end = function () {
_this.timeElapsed = time_1.now() - startTime;
return _this.executor.emit('suiteEnd', _this);
};
var allTestsSkipped = this.numTests === this.numSkippedTests;
var runLifecycleMethod = function (suite, name, test) {
var result;
if (!_this._executor && allTestsSkipped) {
return common_1.Task.resolve();
}
return new common_1.Task(function (resolve, reject) {
var dfd;
var timeout;
suite.async = function (_timeout) {
timeout = _timeout;
var _dfd = new Deferred_1.default();
dfd = _dfd;
suite.async = function () {
return _dfd;
};
return _dfd;
};
var suiteFunc = suite[name];
result =
suiteFunc &&
(test
? suiteFunc.call(suite, test, suite)
: suiteFunc.call(suite, suite));
if (dfd) {
var _dfd_1 = dfd;
if (timeout) {
var timer_1 = time_1.setTimeout(function () {
var error = new Error("Timeout reached on " + suite.id + "#" + name);
error.name = 'TimeoutError';
_dfd_1.reject(error);
}, timeout);
_dfd_1.promise
.catch(function (_error) { })
.then(function () { return timer_1 && time_1.clearTimeout(timer_1); });
}
if (common_1.isPromiseLike(result)) {
result.then(function () { return _dfd_1.resolve(); }, function (error) { return _dfd_1.reject(error); });
}
result = dfd.promise;
}
if (common_1.isPromiseLike(result)) {
result.then(function () { return resolve(); }, reject);
}
else {
resolve();
}
}, function () {
if (common_1.isTask(result)) {
result.cancel();
}
})
.finally(function () {
suite.async = undefined;
})
.catch(function (error) {
if (error !== Test_1.SKIP) {
if (test) {
test.suiteError = error;
}
if (!_this.error) {
_this.executor.log('Suite errored with non-skip error', error);
error.lifecycleMethod = name;
_this.error = error;
}
throw error;
}
});
};
var before = function () {
return runLifecycleMethod(_this, 'before');
};
var after = function () {
return runLifecycleMethod(_this, 'after');
};
this.error = undefined;
this.timeElapsed = 0;
var task;
var runTask;
try {
task = this.publishAfterSetup
? before().then(start)
: start().then(before);
}
catch (error) {
return common_1.Task.reject(error);
}
return task
.then(function () {
var runTestLifecycle = function (name, test) {
var methodQueue = [];
var suite = _this;
do {
if (name === 'beforeEach') {
methodQueue.push(suite);
}
else {
methodQueue.unshift(suite);
}
} while ((suite = suite.parent));
var currentMethod;
return new common_1.Task(function (resolve, reject) {
var firstError;
var handleError = function (error) {
if (name === 'afterEach') {
firstError = firstError || error;
next();
}
else {
reject(error);
}
};
var next = function () {
var suite = methodQueue.pop();
if (!suite) {
firstError ? reject(firstError) : resolve();
return;
}
currentMethod = runLifecycleMethod(suite, name, test).then(next, handleError);
};
next();
}, function () {
methodQueue.splice(0, methodQueue.length);
if (currentMethod) {
currentMethod.cancel();
}
});
};
var i = 0;
var tests = _this.tests;
var current;
runTask = new common_1.Task(function (resolve, reject) {
var firstError;
var testTask;
var next = function () {
var test = tests[i++];
if (!test) {
firstError ? reject(firstError) : resolve();
return;
}
var handleError = function (error) {
if (error && error.relatedTest == null) {
error.relatedTest = test;
}
};
var runTest = function () {
var result = test.run().catch(function (error) {
handleError(error);
});
testTask = new common_1.Task(function (resolve) {
result.then(resolve);
}, function () {
result.cancel();
});
return testTask;
};
if (_this.skipped != null) {
test.skipped = _this.skipped;
}
if (isSuite(test)) {
current = runTest();
}
else {
if (test.skipped != null) {
current = _this.executor.emit('testEnd', test);
}
else {
current = runTestLifecycle('beforeEach', test)
.then(function () {
if (test.skipped != null) {
return _this.executor.emit('testEnd', test);
}
else {
return runTest();
}
})
.finally(function () {
if (testTask) {
testTask.cancel();
}
testTask = undefined;
return runTestLifecycle('afterEach', test);
})
.catch(function (error) {
firstError = firstError || error;
return handleError(error);
});
}
}
current.then(function () {
var skipRestOfSuite = function () {
_this.skipped =
_this.skipped != null ? _this.skipped : BAIL_REASON;
};
if (isSuite(test) && test.skipped === BAIL_REASON) {
skipRestOfSuite();
}
else if (test.error && _this.bail) {
skipRestOfSuite();
}
next();
});
};
next();
}, function () {
i = Infinity;
if (current) {
current.cancel();
}
});
return runTask;
})
.finally(function () {
if (runTask) {
runTask.cancel();
}
})
.finally(function () { return (_this.publishAfterSetup ? end() : after()); })
.finally(function () { return (_this.publishAfterSetup ? after() : end()); });
};
Suite.prototype.skip = function (message) {
if (message === void 0) { message = 'suite skipped'; }
this.skipped = message;
throw Test_1.SKIP;
};
Suite.prototype.toJSON = function () {
var _this = this;
var json = {
hasParent: Boolean(this.parent),
tests: this.tests.map(function (test) { return test.toJSON(); })
};
var properties = [
'name',
'id',
'parentId',
'sessionId',
'timeElapsed',
'numTests',
'numPassedTests',
'numFailedTests',
'numSkippedTests',
'skipped'
];
properties.forEach(function (key) {
var value = _this[key];
if (typeof value !== 'undefined') {
json[key] = value;
}
});
if (this.error) {
json.error = util_1.errorToJSON(this.error);
if (this.error.relatedTest && this.error.relatedTest !== this) {
json.error.relatedTest = this.error.relatedTest.toJSON();
}
}
return json;
};
return Suite;
}());
exports.default = Suite;
function isSuite(value) {
return Array.isArray(value.tests) && typeof value.hasParent === 'boolean';
}
exports.isSuite = isSuite;
var BAIL_REASON = 'bailed';
});
//# sourceMappingURL=Suite.js.map