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 |
|
\ | No newline at end of file |