UNPKG

25.5 kBJavaScriptView Raw
1(function (factory) {
2 if (typeof module === "object" && typeof module.exports === "object") {
3 var v = factory(require, exports);
4 if (v !== undefined) module.exports = v;
5 }
6 else if (typeof define === "function" && define.amd) {
7 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);
8 }
9})(function (require, exports) {
10 "use strict";
11 Object.defineProperty(exports, "__esModule", { value: true });
12 var tslib_1 = require("tslib");
13 var chai = tslib_1.__importStar(require("chai"));
14 var common_1 = require("@theintern/common");
15 var Suite_1 = tslib_1.__importDefault(require("../Suite"));
16 var ErrorFormatter_1 = tslib_1.__importDefault(require("../common/ErrorFormatter"));
17 var path_1 = require("../common/path");
18 var util_1 = require("../common/util");
19 var object_1 = require("../interfaces/object");
20 var tdd_1 = require("../interfaces/tdd");
21 var bdd_1 = require("../interfaces/bdd");
22 var benchmark_1 = require("../interfaces/benchmark");
23 var console = tslib_1.__importStar(require("../common/console"));
24 var BaseExecutor = (function () {
25 function BaseExecutor(options) {
26 var _this = this;
27 this._hasSuiteErrors = false;
28 this._hasTestErrors = false;
29 this._hasEmittedErrors = false;
30 this._config = {
31 bail: false,
32 baseline: false,
33 benchmark: false,
34 browser: {
35 plugins: [],
36 reporters: [],
37 suites: []
38 },
39 coverageVariable: '__coverage__',
40 debug: false,
41 defaultTimeout: 30000,
42 filterErrorStack: false,
43 grep: new RegExp(''),
44 loader: { script: 'default' },
45 name: 'intern',
46 node: {
47 plugins: [],
48 reporters: [],
49 suites: []
50 },
51 plugins: [],
52 reporters: [],
53 sessionId: '',
54 suites: []
55 };
56 this._reportersInitialized = false;
57 this._events = [];
58 this._listeners = {};
59 this._reporters = [];
60 this._plugins = {};
61 this._loadingPlugins = [];
62 this.registerInterface('object', object_1.getInterface(this));
63 this.registerInterface('tdd', tdd_1.getInterface(this));
64 this.registerInterface('bdd', bdd_1.getInterface(this));
65 this.registerInterface('benchmark', benchmark_1.getInterface(this));
66 this.registerPlugin('chai', function () { return chai; });
67 if (options) {
68 this.configure(options);
69 }
70 this._rootSuite = new Suite_1.default({ executor: this });
71 this.on('suiteEnd', function (suite) {
72 if (suite.error) {
73 _this._hasSuiteErrors = true;
74 }
75 if (!suite.hasParent && !suite.sessionId) {
76 return _this._emitCoverage('unit tests');
77 }
78 });
79 this.on('testEnd', function (test) {
80 if (test.error) {
81 _this._hasTestErrors = true;
82 }
83 });
84 }
85 Object.defineProperty(BaseExecutor.prototype, "config", {
86 get: function () {
87 return this._config;
88 },
89 enumerable: false,
90 configurable: true
91 });
92 Object.defineProperty(BaseExecutor.prototype, "suites", {
93 get: function () {
94 return [this._rootSuite];
95 },
96 enumerable: false,
97 configurable: true
98 });
99 BaseExecutor.prototype.formatError = function (error, options) {
100 if (!this._errorFormatter) {
101 this._errorFormatter = new ErrorFormatter_1.default(this);
102 }
103 return this._errorFormatter.format(error, options);
104 };
105 BaseExecutor.prototype.addSuite = function (factory) {
106 factory(this._rootSuite);
107 };
108 BaseExecutor.prototype.configure = function (options) {
109 var _this = this;
110 Object.keys(options).forEach(function (option) {
111 var key = option;
112 _this._processOption(key, options[key]);
113 });
114 };
115 BaseExecutor.prototype.emit = function (eventName, data) {
116 var _this = this;
117 if (eventName === 'error') {
118 this._hasEmittedErrors = true;
119 }
120 if (eventName === 'log' && !this.config.debug) {
121 return common_1.Task.resolve();
122 }
123 if (!this._reportersInitialized) {
124 this._events.push({ eventName: eventName, data: data });
125 return common_1.Task.resolve();
126 }
127 var handleListenerError = function (error) {
128 if (eventName === 'error') {
129 console.error(_this.formatError(error));
130 }
131 else {
132 return _this.emit('error', error);
133 }
134 };
135 var error;
136 if (eventName === 'error') {
137 error = data;
138 }
139 var notifications = [];
140 var listeners = this._listeners[eventName];
141 if (listeners && listeners.length > 0) {
142 for (var _i = 0, listeners_1 = listeners; _i < listeners_1.length; _i++) {
143 var listener = listeners_1[_i];
144 notifications.push(common_1.Task.resolve(listener(data)).catch(handleListenerError));
145 }
146 }
147 var starListeners = this._listeners['*'];
148 if (starListeners && starListeners.length > 0) {
149 var starEvent = { name: eventName, data: data };
150 for (var _a = 0, starListeners_1 = starListeners; _a < starListeners_1.length; _a++) {
151 var listener = starListeners_1[_a];
152 notifications.push(common_1.Task.resolve(listener(starEvent)).catch(handleListenerError));
153 }
154 }
155 if (notifications.length === 0) {
156 if (error && error instanceof Error) {
157 console.error(this.formatError(error));
158 error.reported = true;
159 }
160 else if (eventName === 'warning') {
161 console.warn("WARNING: " + data);
162 }
163 else if (eventName === 'deprecated') {
164 var message = data;
165 console.warn("WARNING: " + message.original + " is deprecated, use " + message.replacement + " instead.");
166 }
167 return common_1.Task.resolve();
168 }
169 return common_1.Task.all(notifications)
170 .then(function () { return undefined; })
171 .finally(function () {
172 if (error && error instanceof Error) {
173 error.reported = true;
174 }
175 });
176 };
177 BaseExecutor.prototype.getInterface = function (name) {
178 return this.getPlugin("interface." + name);
179 };
180 BaseExecutor.prototype.getPlugin = function (type, name) {
181 var pluginName = typeof name === 'undefined' ? type : type + "." + name;
182 if (!(pluginName in this._plugins)) {
183 throw new Error("A plugin named \"" + pluginName + "\" has not been registered");
184 }
185 return this._plugins[pluginName];
186 };
187 BaseExecutor.prototype.log = function () {
188 var args = [];
189 for (var _i = 0; _i < arguments.length; _i++) {
190 args[_i] = arguments[_i];
191 }
192 if (this.config.debug) {
193 var message = args
194 .map(function (arg) {
195 var type = typeof arg;
196 if (type === 'string') {
197 return arg;
198 }
199 if (type === 'function' || arg instanceof RegExp) {
200 return arg.toString();
201 }
202 if (arg instanceof Error) {
203 arg = {
204 name: arg.name,
205 message: arg.message,
206 stack: arg.stack
207 };
208 }
209 try {
210 return JSON.stringify(arg);
211 }
212 catch (error) {
213 return arg.toString();
214 }
215 })
216 .join(' ');
217 return this.emit('log', message);
218 }
219 else {
220 return common_1.Task.resolve();
221 }
222 };
223 BaseExecutor.prototype.on = function (eventName, listener) {
224 var _eventName;
225 if (typeof listener === 'undefined') {
226 listener = eventName;
227 _eventName = '*';
228 }
229 else {
230 _eventName = eventName;
231 }
232 var listeners = this._listeners[_eventName];
233 if (!listeners) {
234 listeners = this._listeners[_eventName] = [];
235 }
236 if (listeners.indexOf(listener) === -1) {
237 listeners.push(listener);
238 }
239 var handle = {
240 destroy: function () {
241 this.destroy = function () { };
242 util_1.pullFromArray(listeners, listener);
243 }
244 };
245 return handle;
246 };
247 BaseExecutor.prototype.registerInterface = function (name, iface) {
248 this.registerPlugin("interface." + name, function () { return iface; });
249 };
250 BaseExecutor.prototype.registerLoader = function (init) {
251 var options = this._loaderOptions ? common_1.duplicate(this._loaderOptions) : {};
252 this._loaderInit = Promise.resolve(init(options));
253 };
254 BaseExecutor.prototype.registerPlugin = function (type, name, init) {
255 var pluginName = typeof init === 'undefined' ? type : type + "." + name;
256 var pluginInit = typeof init === 'undefined' ? name : init;
257 var options = this._loadingPluginOptions;
258 var result = options ? pluginInit(common_1.duplicate(options)) : pluginInit();
259 if (common_1.isPromiseLike(result)) {
260 this._loadingPlugins.push({
261 name: pluginName,
262 init: new common_1.Task(function (resolve, reject) { return result.then(function (value) { return resolve(value); }, reject); }, function () {
263 common_1.isTask(result) && result.cancel();
264 })
265 });
266 }
267 else {
268 this._assignPlugin(pluginName, result);
269 }
270 };
271 BaseExecutor.prototype.registerReporter = function (name, init) {
272 this.registerPlugin('reporter', name, function () { return init; });
273 };
274 BaseExecutor.prototype.run = function () {
275 var _this = this;
276 if (!this._runTask) {
277 var runError_1;
278 try {
279 this._runTask = this._resolveConfig();
280 if (this.config.showConfig) {
281 this._runTask = this._runTask
282 .then(function () {
283 var sort = function (value) {
284 if (Array.isArray(value)) {
285 value = value.map(sort).sort();
286 }
287 else if (typeof value === 'object' &&
288 value.constructor === Object) {
289 var newObj_1 = {};
290 Object.keys(value)
291 .sort()
292 .forEach(function (key) {
293 newObj_1[key] = sort(value[key]);
294 });
295 value = newObj_1;
296 }
297 return value;
298 };
299 console.log(JSON.stringify(sort(_this.config), function (_key, value) {
300 if (value instanceof RegExp) {
301 return value.toString();
302 }
303 return value;
304 }, ' '));
305 })
306 .catch(function (error) {
307 console.error(_this.formatError(error));
308 throw error;
309 });
310 }
311 else {
312 var currentTask_1;
313 this._runTask = this._runTask
314 .then(function () { return _this._loadPlugins(); })
315 .then(function () { return _this._loadLoader(); })
316 .then(function () { return _this._loadPluginsWithLoader(); })
317 .then(function () { return _this._initReporters(); })
318 .then(function () { return _this._loadSuites(); })
319 .then(function () { return _this._beforeRun(); })
320 .then(function (skipTests) {
321 if (skipTests) {
322 return;
323 }
324 var outerTask;
325 var testingTask;
326 currentTask_1 = new common_1.Task(function (resolve, reject) {
327 outerTask = _this.emit('beforeRun')
328 .then(function () {
329 return _this.emit('runStart')
330 .then(function () { return (testingTask = _this._runTests()); })
331 .catch(function (error) {
332 runError_1 = error;
333 return _this.emit('error', error);
334 })
335 .finally(function () { return _this.emit('runEnd'); });
336 })
337 .finally(function () { return _this.emit('afterRun'); })
338 .then(resolve, reject);
339 }, function () {
340 if (testingTask) {
341 testingTask.cancel();
342 }
343 if (outerTask) {
344 outerTask.cancel();
345 }
346 });
347 return currentTask_1;
348 })
349 .finally(function () {
350 _this._reportersInitialized = true;
351 return _this._drainEventQueue();
352 })
353 .finally(function () { return _this._afterRun(); })
354 .finally(function () {
355 if (currentTask_1) {
356 currentTask_1.cancel();
357 }
358 })
359 .catch(function (error) {
360 return _this.emit('error', error).finally(function () {
361 throw runError_1 || error;
362 });
363 })
364 .then(function () {
365 if (runError_1) {
366 throw runError_1;
367 }
368 var message = '';
369 if (_this._hasSuiteErrors) {
370 message = 'One or more suite errors occurred during testing';
371 }
372 else if (_this._hasTestErrors) {
373 message = 'One or more tests failed';
374 }
375 else if (_this._hasEmittedErrors) {
376 message = 'An error was emitted';
377 }
378 if (message) {
379 var error = new Error(message);
380 error.reported = true;
381 throw error;
382 }
383 });
384 }
385 }
386 catch (error) {
387 this._runTask = this.emit('error', error).then(function () {
388 return common_1.Task.reject(error);
389 });
390 }
391 }
392 return this._runTask;
393 };
394 BaseExecutor.prototype._afterRun = function () {
395 return common_1.Task.resolve();
396 };
397 BaseExecutor.prototype._assignPlugin = function (name, plugin) {
398 if (name.indexOf('reporter.') === 0 && typeof plugin !== 'function') {
399 throw new Error('A reporter plugin must be a constructor');
400 }
401 this._plugins[name] = plugin;
402 };
403 BaseExecutor.prototype._beforeRun = function () {
404 var _a = this.config, bail = _a.bail, grep = _a.grep, name = _a.name, sessionId = _a.sessionId, defaultTimeout = _a.defaultTimeout;
405 this._rootSuite.bail = bail;
406 this._rootSuite.grep = grep;
407 this._rootSuite.name = name;
408 this._rootSuite.sessionId = sessionId;
409 this._rootSuite.timeout = defaultTimeout;
410 return common_1.Task.resolve(false);
411 };
412 BaseExecutor.prototype._initReporters = function () {
413 var config = this.config;
414 var envReporters = config[this.environment].reporters;
415 var baseReporters = config.reporters.filter(function (reporter) {
416 return !envReporters.some(function (envReporter) { return envReporter.name === reporter.name; });
417 });
418 for (var _i = 0, _a = tslib_1.__spreadArray(tslib_1.__spreadArray([], baseReporters), envReporters); _i < _a.length; _i++) {
419 var reporter = _a[_i];
420 var initializer = this.getPlugin('reporter', reporter.name);
421 if (!initializer) {
422 throw new Error("A reporter named " + reporter.name + " hasn't been registered");
423 }
424 if (typeof initializer !== 'function') {
425 throw new Error("The reporter " + reporter.name + " isn't a valid initializer");
426 }
427 this._reporters.push(initializer(reporter.options));
428 }
429 this._reportersInitialized = true;
430 return this._drainEventQueue();
431 };
432 BaseExecutor.prototype._drainEventQueue = function () {
433 var _this = this;
434 var task = common_1.Task.resolve();
435 var _loop_1 = function () {
436 var event_1 = this_1._events.shift();
437 task = task.then(function () {
438 return _this.emit(event_1.eventName, event_1.data);
439 });
440 };
441 var this_1 = this;
442 while (this._events.length > 0) {
443 _loop_1();
444 }
445 return task;
446 };
447 BaseExecutor.prototype._emitCoverage = function (source) {
448 var coverage = common_1.global[this.config.coverageVariable];
449 if (coverage) {
450 return this.emit('coverage', {
451 coverage: coverage,
452 source: source,
453 sessionId: this.config.sessionId
454 });
455 }
456 };
457 BaseExecutor.prototype._loadLoader = function () {
458 var _this = this;
459 if (this._loaderInit) {
460 return this._loaderInit.then(function (loader) {
461 _this._loader = loader;
462 });
463 }
464 else {
465 var config = this.config;
466 var loader = config[this.environment].loader || config.loader;
467 var script_1 = loader.script;
468 switch (script_1) {
469 case 'default':
470 case 'dojo':
471 case 'dojo2':
472 case 'esm':
473 case 'systemjs':
474 script_1 = config.internPath + "loaders/" + script_1 + ".js";
475 }
476 this._loaderOptions = loader.options || {};
477 return this.loadScript(script_1)
478 .then(function () {
479 if (!_this._loaderInit) {
480 throw new Error("Loader script " + script_1 + " did not register a loader callback");
481 }
482 return _this._loaderInit;
483 })
484 .then(function (loader) {
485 _this._loader = loader;
486 });
487 }
488 };
489 BaseExecutor.prototype._loadPluginsWithLoader = function () {
490 var _this = this;
491 var scripts = tslib_1.__spreadArray(tslib_1.__spreadArray([], this.config.plugins), this.config[this.environment].plugins).filter(function (plugin) { return plugin.useLoader; });
492 return this._loadScripts(scripts, function (script) { return _this._loader([script]); });
493 };
494 BaseExecutor.prototype._loadPlugins = function () {
495 var _this = this;
496 var scripts = tslib_1.__spreadArray(tslib_1.__spreadArray([], this.config.plugins), this.config[this.environment].plugins).filter(function (plugin) { return !plugin.useLoader; });
497 return this._loadScripts(scripts, function (script) { return _this.loadScript(script); });
498 };
499 BaseExecutor.prototype._loadScripts = function (scripts, loader) {
500 var _this = this;
501 return scripts
502 .reduce(function (previous, script) {
503 if (typeof script === 'string') {
504 return previous.then(function () { return loader(script); });
505 }
506 else {
507 return previous
508 .then(function () {
509 _this._loadingPluginOptions = script.options;
510 })
511 .then(function () { return loader(script.script); })
512 .then(function () {
513 _this._loadingPluginOptions = undefined;
514 });
515 }
516 }, common_1.Task.resolve())
517 .then(function () {
518 return common_1.Task.all(_this._loadingPlugins.map(function (entry) { return entry.init; })).then(function (plugins) {
519 plugins.forEach(function (plugin, index) {
520 _this._assignPlugin(_this._loadingPlugins[index].name, plugin);
521 });
522 });
523 });
524 };
525 BaseExecutor.prototype._loadSuites = function () {
526 var _this = this;
527 var suites = this.config[this.environment].suites;
528 return common_1.Task.resolve(this._loader(suites)).then(function () {
529 _this.log('Loaded suites:', suites);
530 });
531 };
532 BaseExecutor.prototype._processOption = function (key, value) {
533 util_1.processOption(key, value, this.config, this);
534 };
535 BaseExecutor.prototype._resolveConfig = function () {
536 var config = this.config;
537 if (config.internPath != null) {
538 config.internPath = path_1.normalizePathEnding(config.internPath);
539 }
540 else {
541 config.internPath = '';
542 }
543 if (config.benchmark) {
544 config.benchmarkConfig = common_1.deepMixin({
545 mode: config.baseline ? 'baseline' : 'test',
546 id: 'Benchmark',
547 filename: 'baseline.json',
548 thresholds: {
549 warn: { rme: 3, mean: 5 },
550 fail: { rme: 6, mean: 10 }
551 },
552 verbosity: 0
553 }, config.benchmarkConfig || {});
554 }
555 return common_1.Task.resolve();
556 };
557 BaseExecutor.prototype._runTests = function () {
558 return this._rootSuite.run();
559 };
560 return BaseExecutor;
561 }());
562 exports.default = BaseExecutor;
563});
564//# sourceMappingURL=Executor.js.map
\No newline at end of file