UNPKG

21.6 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", "@theintern/common", "./Deferred", "./Test", "./common/util"], factory);
8 }
9})(function (require, exports) {
10 "use strict";
11 Object.defineProperty(exports, "__esModule", { value: true });
12 var common_1 = require("@theintern/common");
13 var Deferred_1 = require("./Deferred");
14 var Test_1 = require("./Test");
15 var util_1 = require("./common/util");
16 var Suite = (function () {
17 function Suite(options) {
18 var _this = this;
19 this.publishAfterSetup = false;
20 this.tests = [];
21 Object.keys(options)
22 .filter(function (key) {
23 return key !== 'tests';
24 })
25 .forEach(function (option) {
26 var key = option;
27 _this[key] = options[key];
28 });
29 if (options.tests) {
30 options.tests.forEach(function (suiteOrTest) { return _this.add(suiteOrTest); });
31 }
32 if (!this.name && this.parent) {
33 throw new Error('A non-root Suite must have a name');
34 }
35 }
36 Object.defineProperty(Suite.prototype, "bail", {
37 get: function () {
38 return this._bail || (this.parent && this.parent.bail);
39 },
40 set: function (value) {
41 this._bail = value;
42 },
43 enumerable: true,
44 configurable: true
45 });
46 Object.defineProperty(Suite.prototype, "executor", {
47 get: function () {
48 return (this.parent && this.parent.executor) || this._executor;
49 },
50 set: function (value) {
51 if (this._executor) {
52 var error = new Error('An executor may only be set once per suite');
53 error.name = 'AlreadyAssigned';
54 throw error;
55 }
56 this._executor = value;
57 },
58 enumerable: true,
59 configurable: true
60 });
61 Object.defineProperty(Suite.prototype, "grep", {
62 get: function () {
63 return this._grep || (this.parent && this.parent.grep) || /.*/;
64 },
65 set: function (value) {
66 this._grep = value;
67 this._applyGrepToChildren();
68 },
69 enumerable: true,
70 configurable: true
71 });
72 Object.defineProperty(Suite.prototype, "name", {
73 get: function () {
74 return this._name;
75 },
76 set: function (value) {
77 this._name = value;
78 this._applyGrepToChildren();
79 },
80 enumerable: true,
81 configurable: true
82 });
83 Object.defineProperty(Suite.prototype, "id", {
84 get: function () {
85 var name = [];
86 var suite = this;
87 do {
88 suite.name != null && name.unshift(suite.name);
89 } while ((suite = suite.parent));
90 return name.join(' - ');
91 },
92 enumerable: true,
93 configurable: true
94 });
95 Object.defineProperty(Suite.prototype, "parentId", {
96 get: function () {
97 var parent = this.parent;
98 if (parent) {
99 return parent.id;
100 }
101 },
102 enumerable: true,
103 configurable: true
104 });
105 Object.defineProperty(Suite.prototype, "remote", {
106 get: function () {
107 return this.parent && this.parent.remote
108 ? this.parent.remote
109 : this._remote;
110 },
111 set: function (value) {
112 if (this._remote) {
113 throw new Error('AlreadyAssigned: remote may only be set once per suite');
114 }
115 this._remote = value;
116 },
117 enumerable: true,
118 configurable: true
119 });
120 Object.defineProperty(Suite.prototype, "sessionId", {
121 get: function () {
122 if (this.parent) {
123 return this.parent.sessionId;
124 }
125 if (this._sessionId) {
126 return this._sessionId;
127 }
128 if (this.remote) {
129 return this.remote.session.sessionId;
130 }
131 return '';
132 },
133 set: function (value) {
134 this._sessionId = value;
135 },
136 enumerable: true,
137 configurable: true
138 });
139 Object.defineProperty(Suite.prototype, "numTests", {
140 get: function () {
141 return this.tests.reduce(function (numTests, suiteOrTest) {
142 if (isSuite(suiteOrTest)) {
143 return numTests + suiteOrTest.numTests;
144 }
145 return numTests + 1;
146 }, 0);
147 },
148 enumerable: true,
149 configurable: true
150 });
151 Object.defineProperty(Suite.prototype, "numPassedTests", {
152 get: function () {
153 return this.tests.reduce(function (numPassedTests, suiteOrTest) {
154 if (isSuite(suiteOrTest)) {
155 return numPassedTests + suiteOrTest.numPassedTests;
156 }
157 else if (suiteOrTest.hasPassed) {
158 return numPassedTests + 1;
159 }
160 return numPassedTests;
161 }, 0);
162 },
163 enumerable: true,
164 configurable: true
165 });
166 Object.defineProperty(Suite.prototype, "numFailedTests", {
167 get: function () {
168 return this.tests.reduce(function (numFailedTests, suiteOrTest) {
169 if (isSuite(suiteOrTest)) {
170 return numFailedTests + suiteOrTest.numFailedTests;
171 }
172 else if (suiteOrTest.error) {
173 return numFailedTests + 1;
174 }
175 return numFailedTests;
176 }, 0);
177 },
178 enumerable: true,
179 configurable: true
180 });
181 Object.defineProperty(Suite.prototype, "numSkippedTests", {
182 get: function () {
183 return this.tests.reduce(function (numSkippedTests, suiteOrTest) {
184 if (isSuite(suiteOrTest)) {
185 return numSkippedTests + suiteOrTest.numSkippedTests;
186 }
187 else if (suiteOrTest.skipped) {
188 return numSkippedTests + 1;
189 }
190 return numSkippedTests;
191 }, 0);
192 },
193 enumerable: true,
194 configurable: true
195 });
196 Object.defineProperty(Suite.prototype, "hasParent", {
197 get: function () {
198 return Boolean(this.parent);
199 },
200 enumerable: true,
201 configurable: true
202 });
203 Object.defineProperty(Suite.prototype, "timeout", {
204 get: function () {
205 if (this._timeout != null) {
206 return this._timeout;
207 }
208 if (this.parent) {
209 return this.parent.timeout;
210 }
211 return 30000;
212 },
213 set: function (value) {
214 this._timeout = value;
215 },
216 enumerable: true,
217 configurable: true
218 });
219 Suite.prototype.add = function (suiteOrTest) {
220 if (!Test_1.isTest(suiteOrTest) && !isSuite(suiteOrTest)) {
221 throw new Error('Tried to add invalid suite or test');
222 }
223 if (suiteOrTest.parent != null && suiteOrTest.parent !== this) {
224 throw new Error('This Suite or Test already belongs to another parent');
225 }
226 this.tests.forEach(function (existingSuiteOrTest) {
227 if (existingSuiteOrTest.name === suiteOrTest.name) {
228 throw new Error("A suite or test named \"" + suiteOrTest.name + "\" has already been added");
229 }
230 });
231 suiteOrTest.parent = this;
232 this.tests.push(suiteOrTest);
233 this._applyGrepToSuiteOrTest(suiteOrTest);
234 if (Test_1.isTest(suiteOrTest)) {
235 this.executor.emit('testAdd', suiteOrTest);
236 }
237 else {
238 this.executor.emit('suiteAdd', suiteOrTest);
239 }
240 };
241 Suite.prototype._applyGrepToSuiteOrTest = function (suiteOrTest) {
242 if (suiteOrTest instanceof Suite) {
243 suiteOrTest._applyGrepToChildren();
244 }
245 else {
246 var grepSkipReason = 'grep';
247 if (suiteOrTest.skipped === grepSkipReason) {
248 suiteOrTest.skipped = undefined;
249 }
250 if (!this.grep.test(suiteOrTest.id)) {
251 suiteOrTest.skipped = grepSkipReason;
252 }
253 }
254 };
255 Suite.prototype._applyGrepToChildren = function () {
256 var _this = this;
257 this.tests.forEach(function (suiteOrTest) {
258 return _this._applyGrepToSuiteOrTest(suiteOrTest);
259 });
260 };
261 Suite.prototype.run = function () {
262 var _this = this;
263 var startTime;
264 var start = function () {
265 return _this.executor.emit('suiteStart', _this).then(function () {
266 startTime = Date.now();
267 });
268 };
269 var end = function () {
270 _this.timeElapsed = Date.now() - startTime;
271 return _this.executor.emit('suiteEnd', _this);
272 };
273 var allTestsSkipped = this.numTests === this.numSkippedTests;
274 var runLifecycleMethod = function (suite, name, test) {
275 var result;
276 if (!_this._executor && allTestsSkipped) {
277 return common_1.Task.resolve();
278 }
279 return new common_1.Task(function (resolve, reject) {
280 var dfd;
281 var timeout;
282 suite.async = function (_timeout) {
283 timeout = _timeout;
284 var _dfd = new Deferred_1.default();
285 dfd = _dfd;
286 suite.async = function () {
287 return _dfd;
288 };
289 return _dfd;
290 };
291 var suiteFunc = suite[name];
292 result =
293 suiteFunc &&
294 (test
295 ? suiteFunc.call(suite, test, suite)
296 : suiteFunc.call(suite, suite));
297 if (dfd) {
298 var _dfd_1 = dfd;
299 if (timeout) {
300 var timer_1 = setTimeout(function () {
301 var error = new Error("Timeout reached on " + suite.id + "#" + name);
302 error.name = 'TimeoutError';
303 _dfd_1.reject(error);
304 }, timeout);
305 _dfd_1.promise
306 .catch(function (_error) { })
307 .then(function () { return timer_1 && clearTimeout(timer_1); });
308 }
309 if (common_1.isPromiseLike(result)) {
310 result.then(function () { return _dfd_1.resolve(); }, function (error) { return _dfd_1.reject(error); });
311 }
312 result = dfd.promise;
313 }
314 if (common_1.isPromiseLike(result)) {
315 result.then(function () { return resolve(); }, reject);
316 }
317 else {
318 resolve();
319 }
320 }, function () {
321 if (common_1.isTask(result)) {
322 result.cancel();
323 }
324 })
325 .finally(function () {
326 suite.async = undefined;
327 })
328 .catch(function (error) {
329 if (error !== Test_1.SKIP) {
330 if (test) {
331 test.suiteError = error;
332 }
333 if (!_this.error) {
334 _this.executor.log('Suite errored with non-skip error', error);
335 error.lifecycleMethod = name;
336 _this.error = error;
337 }
338 throw error;
339 }
340 });
341 };
342 var before = function () {
343 return runLifecycleMethod(_this, 'before');
344 };
345 var after = function () {
346 return runLifecycleMethod(_this, 'after');
347 };
348 this.error = undefined;
349 this.timeElapsed = 0;
350 var task;
351 var runTask;
352 try {
353 task = this.publishAfterSetup
354 ? before().then(start)
355 : start().then(before);
356 }
357 catch (error) {
358 return common_1.Task.reject(error);
359 }
360 return task
361 .then(function () {
362 var runTestLifecycle = function (name, test) {
363 var methodQueue = [];
364 var suite = _this;
365 do {
366 if (name === 'beforeEach') {
367 methodQueue.push(suite);
368 }
369 else {
370 methodQueue.unshift(suite);
371 }
372 } while ((suite = suite.parent));
373 var currentMethod;
374 return new common_1.Task(function (resolve, reject) {
375 var firstError;
376 var handleError = function (error) {
377 if (name === 'afterEach') {
378 firstError = firstError || error;
379 next();
380 }
381 else {
382 reject(error);
383 }
384 };
385 var next = function () {
386 var suite = methodQueue.pop();
387 if (!suite) {
388 firstError ? reject(firstError) : resolve();
389 return;
390 }
391 currentMethod = runLifecycleMethod(suite, name, test).then(next, handleError);
392 };
393 next();
394 }, function () {
395 methodQueue.splice(0, methodQueue.length);
396 if (currentMethod) {
397 currentMethod.cancel();
398 }
399 });
400 };
401 var i = 0;
402 var tests = _this.tests;
403 var current;
404 runTask = new common_1.Task(function (resolve, reject) {
405 var firstError;
406 var testTask;
407 var next = function () {
408 var test = tests[i++];
409 if (!test) {
410 firstError ? reject(firstError) : resolve();
411 return;
412 }
413 var handleError = function (error) {
414 if (error && error.relatedTest == null) {
415 error.relatedTest = test;
416 }
417 };
418 var runTest = function () {
419 var result = test.run().catch(function (error) {
420 handleError(error);
421 });
422 testTask = new common_1.Task(function (resolve) {
423 result.then(resolve);
424 }, function () {
425 result.cancel();
426 });
427 return testTask;
428 };
429 if (_this.skipped != null) {
430 test.skipped = _this.skipped;
431 }
432 if (isSuite(test)) {
433 current = runTest();
434 }
435 else {
436 if (test.skipped != null) {
437 current = _this.executor.emit('testEnd', test);
438 }
439 else {
440 current = runTestLifecycle('beforeEach', test)
441 .then(function () {
442 if (test.skipped != null) {
443 return _this.executor.emit('testEnd', test);
444 }
445 else {
446 return runTest();
447 }
448 })
449 .finally(function () {
450 if (testTask) {
451 testTask.cancel();
452 }
453 testTask = undefined;
454 return runTestLifecycle('afterEach', test);
455 })
456 .catch(function (error) {
457 firstError = firstError || error;
458 return handleError(error);
459 });
460 }
461 }
462 current.then(function () {
463 var skipRestOfSuite = function () {
464 _this.skipped =
465 _this.skipped != null ? _this.skipped : BAIL_REASON;
466 };
467 if (isSuite(test) && test.skipped === BAIL_REASON) {
468 skipRestOfSuite();
469 }
470 else if (test.error && _this.bail) {
471 skipRestOfSuite();
472 }
473 next();
474 });
475 };
476 next();
477 }, function () {
478 i = Infinity;
479 if (current) {
480 current.cancel();
481 }
482 });
483 return runTask;
484 })
485 .finally(function () {
486 if (runTask) {
487 runTask.cancel();
488 }
489 })
490 .finally(function () { return (_this.publishAfterSetup ? end() : after()); })
491 .finally(function () { return (_this.publishAfterSetup ? after() : end()); });
492 };
493 Suite.prototype.skip = function (message) {
494 if (message === void 0) { message = 'suite skipped'; }
495 this.skipped = message;
496 throw Test_1.SKIP;
497 };
498 Suite.prototype.toJSON = function () {
499 var _this = this;
500 var json = {
501 hasParent: Boolean(this.parent),
502 tests: this.tests.map(function (test) { return test.toJSON(); })
503 };
504 var properties = [
505 'name',
506 'id',
507 'parentId',
508 'sessionId',
509 'timeElapsed',
510 'numTests',
511 'numPassedTests',
512 'numFailedTests',
513 'numSkippedTests',
514 'skipped'
515 ];
516 properties.forEach(function (key) {
517 var value = _this[key];
518 if (typeof value !== 'undefined') {
519 json[key] = value;
520 }
521 });
522 if (this.error) {
523 json.error = util_1.errorToJSON(this.error);
524 if (this.error.relatedTest && this.error.relatedTest !== this) {
525 json.error.relatedTest = this.error.relatedTest.toJSON();
526 }
527 }
528 return json;
529 };
530 return Suite;
531 }());
532 exports.default = Suite;
533 function isSuite(value) {
534 return Array.isArray(value.tests) && typeof value.hasParent === 'boolean';
535 }
536 exports.isSuite = isSuite;
537 var BAIL_REASON = 'bailed';
538});
539//# sourceMappingURL=Suite.js.map
\No newline at end of file