intern
Version:
Intern. A next-generation code testing stack for JavaScript.
564 lines • 25.5 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", "chai", "@theintern/common", "../Suite", "../common/ErrorFormatter", "../common/path", "../common/util", "../interfaces/object", "../interfaces/tdd", "../interfaces/bdd", "../interfaces/benchmark", "../common/console"], factory);
}
})(function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var chai = tslib_1.__importStar(require("chai"));
var common_1 = require("@theintern/common");
var Suite_1 = tslib_1.__importDefault(require("../Suite"));
var ErrorFormatter_1 = tslib_1.__importDefault(require("../common/ErrorFormatter"));
var path_1 = require("../common/path");
var util_1 = require("../common/util");
var object_1 = require("../interfaces/object");
var tdd_1 = require("../interfaces/tdd");
var bdd_1 = require("../interfaces/bdd");
var benchmark_1 = require("../interfaces/benchmark");
var console = tslib_1.__importStar(require("../common/console"));
var BaseExecutor = (function () {
function BaseExecutor(options) {
var _this = this;
this._hasSuiteErrors = false;
this._hasTestErrors = false;
this._hasEmittedErrors = false;
this._config = {
bail: false,
baseline: false,
benchmark: false,
browser: {
plugins: [],
reporters: [],
suites: []
},
coverageVariable: '__coverage__',
debug: false,
defaultTimeout: 30000,
filterErrorStack: false,
grep: new RegExp(''),
loader: { script: 'default' },
name: 'intern',
node: {
plugins: [],
reporters: [],
suites: []
},
plugins: [],
reporters: [],
sessionId: '',
suites: []
};
this._reportersInitialized = false;
this._events = [];
this._listeners = {};
this._reporters = [];
this._plugins = {};
this._loadingPlugins = [];
this.registerInterface('object', object_1.getInterface(this));
this.registerInterface('tdd', tdd_1.getInterface(this));
this.registerInterface('bdd', bdd_1.getInterface(this));
this.registerInterface('benchmark', benchmark_1.getInterface(this));
this.registerPlugin('chai', function () { return chai; });
if (options) {
this.configure(options);
}
this._rootSuite = new Suite_1.default({ executor: this });
this.on('suiteEnd', function (suite) {
if (suite.error) {
_this._hasSuiteErrors = true;
}
if (!suite.hasParent && !suite.sessionId) {
return _this._emitCoverage('unit tests');
}
});
this.on('testEnd', function (test) {
if (test.error) {
_this._hasTestErrors = true;
}
});
}
Object.defineProperty(BaseExecutor.prototype, "config", {
get: function () {
return this._config;
},
enumerable: false,
configurable: true
});
Object.defineProperty(BaseExecutor.prototype, "suites", {
get: function () {
return [this._rootSuite];
},
enumerable: false,
configurable: true
});
BaseExecutor.prototype.formatError = function (error, options) {
if (!this._errorFormatter) {
this._errorFormatter = new ErrorFormatter_1.default(this);
}
return this._errorFormatter.format(error, options);
};
BaseExecutor.prototype.addSuite = function (factory) {
factory(this._rootSuite);
};
BaseExecutor.prototype.configure = function (options) {
var _this = this;
Object.keys(options).forEach(function (option) {
var key = option;
_this._processOption(key, options[key]);
});
};
BaseExecutor.prototype.emit = function (eventName, data) {
var _this = this;
if (eventName === 'error') {
this._hasEmittedErrors = true;
}
if (eventName === 'log' && !this.config.debug) {
return common_1.Task.resolve();
}
if (!this._reportersInitialized) {
this._events.push({ eventName: eventName, data: data });
return common_1.Task.resolve();
}
var handleListenerError = function (error) {
if (eventName === 'error') {
console.error(_this.formatError(error));
}
else {
return _this.emit('error', error);
}
};
var error;
if (eventName === 'error') {
error = data;
}
var notifications = [];
var listeners = this._listeners[eventName];
if (listeners && listeners.length > 0) {
for (var _i = 0, listeners_1 = listeners; _i < listeners_1.length; _i++) {
var listener = listeners_1[_i];
notifications.push(common_1.Task.resolve(listener(data)).catch(handleListenerError));
}
}
var starListeners = this._listeners['*'];
if (starListeners && starListeners.length > 0) {
var starEvent = { name: eventName, data: data };
for (var _a = 0, starListeners_1 = starListeners; _a < starListeners_1.length; _a++) {
var listener = starListeners_1[_a];
notifications.push(common_1.Task.resolve(listener(starEvent)).catch(handleListenerError));
}
}
if (notifications.length === 0) {
if (error && error instanceof Error) {
console.error(this.formatError(error));
error.reported = true;
}
else if (eventName === 'warning') {
console.warn("WARNING: " + data);
}
else if (eventName === 'deprecated') {
var message = data;
console.warn("WARNING: " + message.original + " is deprecated, use " + message.replacement + " instead.");
}
return common_1.Task.resolve();
}
return common_1.Task.all(notifications)
.then(function () { return undefined; })
.finally(function () {
if (error && error instanceof Error) {
error.reported = true;
}
});
};
BaseExecutor.prototype.getInterface = function (name) {
return this.getPlugin("interface." + name);
};
BaseExecutor.prototype.getPlugin = function (type, name) {
var pluginName = typeof name === 'undefined' ? type : type + "." + name;
if (!(pluginName in this._plugins)) {
throw new Error("A plugin named \"" + pluginName + "\" has not been registered");
}
return this._plugins[pluginName];
};
BaseExecutor.prototype.log = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
if (this.config.debug) {
var message = args
.map(function (arg) {
var type = typeof arg;
if (type === 'string') {
return arg;
}
if (type === 'function' || arg instanceof RegExp) {
return arg.toString();
}
if (arg instanceof Error) {
arg = {
name: arg.name,
message: arg.message,
stack: arg.stack
};
}
try {
return JSON.stringify(arg);
}
catch (error) {
return arg.toString();
}
})
.join(' ');
return this.emit('log', message);
}
else {
return common_1.Task.resolve();
}
};
BaseExecutor.prototype.on = function (eventName, listener) {
var _eventName;
if (typeof listener === 'undefined') {
listener = eventName;
_eventName = '*';
}
else {
_eventName = eventName;
}
var listeners = this._listeners[_eventName];
if (!listeners) {
listeners = this._listeners[_eventName] = [];
}
if (listeners.indexOf(listener) === -1) {
listeners.push(listener);
}
var handle = {
destroy: function () {
this.destroy = function () { };
util_1.pullFromArray(listeners, listener);
}
};
return handle;
};
BaseExecutor.prototype.registerInterface = function (name, iface) {
this.registerPlugin("interface." + name, function () { return iface; });
};
BaseExecutor.prototype.registerLoader = function (init) {
var options = this._loaderOptions ? common_1.duplicate(this._loaderOptions) : {};
this._loaderInit = Promise.resolve(init(options));
};
BaseExecutor.prototype.registerPlugin = function (type, name, init) {
var pluginName = typeof init === 'undefined' ? type : type + "." + name;
var pluginInit = typeof init === 'undefined' ? name : init;
var options = this._loadingPluginOptions;
var result = options ? pluginInit(common_1.duplicate(options)) : pluginInit();
if (common_1.isPromiseLike(result)) {
this._loadingPlugins.push({
name: pluginName,
init: new common_1.Task(function (resolve, reject) { return result.then(function (value) { return resolve(value); }, reject); }, function () {
common_1.isTask(result) && result.cancel();
})
});
}
else {
this._assignPlugin(pluginName, result);
}
};
BaseExecutor.prototype.registerReporter = function (name, init) {
this.registerPlugin('reporter', name, function () { return init; });
};
BaseExecutor.prototype.run = function () {
var _this = this;
if (!this._runTask) {
var runError_1;
try {
this._runTask = this._resolveConfig();
if (this.config.showConfig) {
this._runTask = this._runTask
.then(function () {
var sort = function (value) {
if (Array.isArray(value)) {
value = value.map(sort).sort();
}
else if (typeof value === 'object' &&
value.constructor === Object) {
var newObj_1 = {};
Object.keys(value)
.sort()
.forEach(function (key) {
newObj_1[key] = sort(value[key]);
});
value = newObj_1;
}
return value;
};
console.log(JSON.stringify(sort(_this.config), function (_key, value) {
if (value instanceof RegExp) {
return value.toString();
}
return value;
}, ' '));
})
.catch(function (error) {
console.error(_this.formatError(error));
throw error;
});
}
else {
var currentTask_1;
this._runTask = this._runTask
.then(function () { return _this._loadPlugins(); })
.then(function () { return _this._loadLoader(); })
.then(function () { return _this._loadPluginsWithLoader(); })
.then(function () { return _this._initReporters(); })
.then(function () { return _this._loadSuites(); })
.then(function () { return _this._beforeRun(); })
.then(function (skipTests) {
if (skipTests) {
return;
}
var outerTask;
var testingTask;
currentTask_1 = new common_1.Task(function (resolve, reject) {
outerTask = _this.emit('beforeRun')
.then(function () {
return _this.emit('runStart')
.then(function () { return (testingTask = _this._runTests()); })
.catch(function (error) {
runError_1 = error;
return _this.emit('error', error);
})
.finally(function () { return _this.emit('runEnd'); });
})
.finally(function () { return _this.emit('afterRun'); })
.then(resolve, reject);
}, function () {
if (testingTask) {
testingTask.cancel();
}
if (outerTask) {
outerTask.cancel();
}
});
return currentTask_1;
})
.finally(function () {
_this._reportersInitialized = true;
return _this._drainEventQueue();
})
.finally(function () { return _this._afterRun(); })
.finally(function () {
if (currentTask_1) {
currentTask_1.cancel();
}
})
.catch(function (error) {
return _this.emit('error', error).finally(function () {
throw runError_1 || error;
});
})
.then(function () {
if (runError_1) {
throw runError_1;
}
var message = '';
if (_this._hasSuiteErrors) {
message = 'One or more suite errors occurred during testing';
}
else if (_this._hasTestErrors) {
message = 'One or more tests failed';
}
else if (_this._hasEmittedErrors) {
message = 'An error was emitted';
}
if (message) {
var error = new Error(message);
error.reported = true;
throw error;
}
});
}
}
catch (error) {
this._runTask = this.emit('error', error).then(function () {
return common_1.Task.reject(error);
});
}
}
return this._runTask;
};
BaseExecutor.prototype._afterRun = function () {
return common_1.Task.resolve();
};
BaseExecutor.prototype._assignPlugin = function (name, plugin) {
if (name.indexOf('reporter.') === 0 && typeof plugin !== 'function') {
throw new Error('A reporter plugin must be a constructor');
}
this._plugins[name] = plugin;
};
BaseExecutor.prototype._beforeRun = function () {
var _a = this.config, bail = _a.bail, grep = _a.grep, name = _a.name, sessionId = _a.sessionId, defaultTimeout = _a.defaultTimeout;
this._rootSuite.bail = bail;
this._rootSuite.grep = grep;
this._rootSuite.name = name;
this._rootSuite.sessionId = sessionId;
this._rootSuite.timeout = defaultTimeout;
return common_1.Task.resolve(false);
};
BaseExecutor.prototype._initReporters = function () {
var config = this.config;
var envReporters = config[this.environment].reporters;
var baseReporters = config.reporters.filter(function (reporter) {
return !envReporters.some(function (envReporter) { return envReporter.name === reporter.name; });
});
for (var _i = 0, _a = tslib_1.__spreadArray(tslib_1.__spreadArray([], baseReporters), envReporters); _i < _a.length; _i++) {
var reporter = _a[_i];
var initializer = this.getPlugin('reporter', reporter.name);
if (!initializer) {
throw new Error("A reporter named " + reporter.name + " hasn't been registered");
}
if (typeof initializer !== 'function') {
throw new Error("The reporter " + reporter.name + " isn't a valid initializer");
}
this._reporters.push(initializer(reporter.options));
}
this._reportersInitialized = true;
return this._drainEventQueue();
};
BaseExecutor.prototype._drainEventQueue = function () {
var _this = this;
var task = common_1.Task.resolve();
var _loop_1 = function () {
var event_1 = this_1._events.shift();
task = task.then(function () {
return _this.emit(event_1.eventName, event_1.data);
});
};
var this_1 = this;
while (this._events.length > 0) {
_loop_1();
}
return task;
};
BaseExecutor.prototype._emitCoverage = function (source) {
var coverage = common_1.global[this.config.coverageVariable];
if (coverage) {
return this.emit('coverage', {
coverage: coverage,
source: source,
sessionId: this.config.sessionId
});
}
};
BaseExecutor.prototype._loadLoader = function () {
var _this = this;
if (this._loaderInit) {
return this._loaderInit.then(function (loader) {
_this._loader = loader;
});
}
else {
var config = this.config;
var loader = config[this.environment].loader || config.loader;
var script_1 = loader.script;
switch (script_1) {
case 'default':
case 'dojo':
case 'dojo2':
case 'esm':
case 'systemjs':
script_1 = config.internPath + "loaders/" + script_1 + ".js";
}
this._loaderOptions = loader.options || {};
return this.loadScript(script_1)
.then(function () {
if (!_this._loaderInit) {
throw new Error("Loader script " + script_1 + " did not register a loader callback");
}
return _this._loaderInit;
})
.then(function (loader) {
_this._loader = loader;
});
}
};
BaseExecutor.prototype._loadPluginsWithLoader = function () {
var _this = this;
var scripts = tslib_1.__spreadArray(tslib_1.__spreadArray([], this.config.plugins), this.config[this.environment].plugins).filter(function (plugin) { return plugin.useLoader; });
return this._loadScripts(scripts, function (script) { return _this._loader([script]); });
};
BaseExecutor.prototype._loadPlugins = function () {
var _this = this;
var scripts = tslib_1.__spreadArray(tslib_1.__spreadArray([], this.config.plugins), this.config[this.environment].plugins).filter(function (plugin) { return !plugin.useLoader; });
return this._loadScripts(scripts, function (script) { return _this.loadScript(script); });
};
BaseExecutor.prototype._loadScripts = function (scripts, loader) {
var _this = this;
return scripts
.reduce(function (previous, script) {
if (typeof script === 'string') {
return previous.then(function () { return loader(script); });
}
else {
return previous
.then(function () {
_this._loadingPluginOptions = script.options;
})
.then(function () { return loader(script.script); })
.then(function () {
_this._loadingPluginOptions = undefined;
});
}
}, common_1.Task.resolve())
.then(function () {
return common_1.Task.all(_this._loadingPlugins.map(function (entry) { return entry.init; })).then(function (plugins) {
plugins.forEach(function (plugin, index) {
_this._assignPlugin(_this._loadingPlugins[index].name, plugin);
});
});
});
};
BaseExecutor.prototype._loadSuites = function () {
var _this = this;
var suites = this.config[this.environment].suites;
return common_1.Task.resolve(this._loader(suites)).then(function () {
_this.log('Loaded suites:', suites);
});
};
BaseExecutor.prototype._processOption = function (key, value) {
util_1.processOption(key, value, this.config, this);
};
BaseExecutor.prototype._resolveConfig = function () {
var config = this.config;
if (config.internPath != null) {
config.internPath = path_1.normalizePathEnding(config.internPath);
}
else {
config.internPath = '';
}
if (config.benchmark) {
config.benchmarkConfig = common_1.deepMixin({
mode: config.baseline ? 'baseline' : 'test',
id: 'Benchmark',
filename: 'baseline.json',
thresholds: {
warn: { rme: 3, mean: 5 },
fail: { rme: 6, mean: 10 }
},
verbosity: 0
}, config.benchmarkConfig || {});
}
return common_1.Task.resolve();
};
BaseExecutor.prototype._runTests = function () {
return this._rootSuite.run();
};
return BaseExecutor;
}());
exports.default = BaseExecutor;
});
//# sourceMappingURL=Executor.js.map