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