| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Copyright 2017 Google Inc. All rights reserved. | 
					
						
							| 
									
										
										
										
											2020-03-29 21:38:30 -07:00
										 |  |  |  * Modifications copyright (c) Microsoft Corporation. | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  * you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  * You may obtain a copy of the License at | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  |  * See the License for the specific language governing permissions and | 
					
						
							|  |  |  |  * limitations under the License. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  | const { SourceMapSupport } = require('./SourceMapSupport'); | 
					
						
							| 
									
										
										
										
											2020-02-14 15:21:08 -08:00
										 |  |  | const debug = require('debug'); | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  | const { TestExpectation } = require('./Test'); | 
					
						
							| 
									
										
										
										
											2019-12-19 15:47:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  | const TimeoutError = new Error('Timeout'); | 
					
						
							|  |  |  | const TerminatedError = new Error('Terminated'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-26 14:43:28 -07:00
										 |  |  | function runUserCallback(callback, timeout, args) { | 
					
						
							|  |  |  |   let terminateCallback; | 
					
						
							|  |  |  |   let timeoutId; | 
					
						
							|  |  |  |   const promise = Promise.race([ | 
					
						
							|  |  |  |     Promise.resolve().then(callback.bind(null, ...args)).then(() => null).catch(e => e), | 
					
						
							|  |  |  |     new Promise(resolve => { | 
					
						
							|  |  |  |       timeoutId = setTimeout(resolve.bind(null, TimeoutError), timeout); | 
					
						
							|  |  |  |     }), | 
					
						
							|  |  |  |     new Promise(resolve => terminateCallback = resolve), | 
					
						
							|  |  |  |   ]).catch(e => e).finally(() => clearTimeout(timeoutId)); | 
					
						
							|  |  |  |   const terminate = () => terminateCallback(TerminatedError); | 
					
						
							|  |  |  |   return { promise, terminate }; | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const TestResult = { | 
					
						
							|  |  |  |   Ok: 'ok', | 
					
						
							| 
									
										
										
										
											2020-03-02 14:57:09 -08:00
										 |  |  |   MarkedAsFailing: 'markedAsFailing', // User marked as failed
 | 
					
						
							|  |  |  |   Skipped: 'skipped', // User marked as skipped
 | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |   Failed: 'failed', // Exception happened during running
 | 
					
						
							|  |  |  |   TimedOut: 'timedout', // Timeout Exceeded while running
 | 
					
						
							|  |  |  |   Terminated: 'terminated', // Execution terminated
 | 
					
						
							|  |  |  |   Crashed: 'crashed', // If testrunner crashed due to this test
 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  | function isEmptyEnvironment(env) { | 
					
						
							|  |  |  |   return !env.afterEach && !env.afterAll && !env.beforeEach && !env.beforeAll && | 
					
						
							|  |  |  |     !env.globalSetup && !env.globalTeardown; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  | class TestRun { | 
					
						
							|  |  |  |   constructor(test) { | 
					
						
							|  |  |  |     this._test = test; | 
					
						
							|  |  |  |     this._result = null; | 
					
						
							|  |  |  |     this._error = null; | 
					
						
							|  |  |  |     this._startTimestamp = 0; | 
					
						
							|  |  |  |     this._endTimestamp = 0; | 
					
						
							|  |  |  |     this._workerId = null; | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  |     this._output = []; | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  |     this._environments = test._environments.filter(env => !isEmptyEnvironment(env)).reverse(); | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |     for (let suite = test.suite(); suite; suite = suite.parentSuite()) | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  |       this._environments.push(...suite._environments.filter(env => !isEmptyEnvironment(env)).reverse()); | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |     this._environments.reverse(); | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   finished() { | 
					
						
							|  |  |  |     return this._result !== null && this._result !== 'running'; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   isFailure() { | 
					
						
							|  |  |  |     return this._result === TestResult.Failed || this._result === TestResult.TimedOut || this._result === TestResult.Crashed; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ok() { | 
					
						
							|  |  |  |     return this._result === TestResult.Ok; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   result() { | 
					
						
							|  |  |  |     return this._result; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   error() { | 
					
						
							|  |  |  |     return this._error; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   duration() { | 
					
						
							|  |  |  |     return this._endTimestamp - this._startTimestamp; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   test() { | 
					
						
							|  |  |  |     return this._test; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   workerId() { | 
					
						
							|  |  |  |     return this._workerId; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   log(log) { | 
					
						
							|  |  |  |     this._output.push(log); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   output() { | 
					
						
							|  |  |  |     return this._output; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-12 17:32:53 -07:00
										 |  |  | class Result { | 
					
						
							|  |  |  |   constructor() { | 
					
						
							|  |  |  |     this.result = TestResult.Ok; | 
					
						
							|  |  |  |     this.exitCode = 0; | 
					
						
							|  |  |  |     this.message = ''; | 
					
						
							|  |  |  |     this.errors = []; | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |     this.runs = []; | 
					
						
							| 
									
										
										
										
											2020-03-12 17:32:53 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   setResult(result, message) { | 
					
						
							|  |  |  |     if (!this.ok()) | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     this.result = result; | 
					
						
							|  |  |  |     this.message = message || ''; | 
					
						
							|  |  |  |     if (result === TestResult.Ok) | 
					
						
							|  |  |  |       this.exitCode = 0; | 
					
						
							|  |  |  |     else if (result === TestResult.Terminated) | 
					
						
							|  |  |  |       this.exitCode = 130; | 
					
						
							|  |  |  |     else if (result === TestResult.Crashed) | 
					
						
							|  |  |  |       this.exitCode = 2; | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       this.exitCode = 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   addError(message, error, worker) { | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |     const data = { message, error, runs: [] }; | 
					
						
							|  |  |  |     if (worker) | 
					
						
							|  |  |  |       data.runs = worker._runs.slice(); | 
					
						
							| 
									
										
										
										
											2020-03-12 17:32:53 -07:00
										 |  |  |     this.errors.push(data); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ok() { | 
					
						
							|  |  |  |     return this.result === TestResult.Ok; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  | class TestWorker { | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |   constructor(testRunner, hookRunner, workerId, parallelIndex) { | 
					
						
							| 
									
										
										
										
											2020-04-03 15:47:25 -07:00
										 |  |  |     this._testRunner = testRunner; | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |     this._hookRunner = hookRunner; | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |     this._state = { parallelIndex }; | 
					
						
							| 
									
										
										
										
											2020-04-01 10:49:47 -07:00
										 |  |  |     this._environmentStack = []; | 
					
						
							| 
									
										
										
										
											2020-03-12 17:32:53 -07:00
										 |  |  |     this._terminating = false; | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |     this._workerId = workerId; | 
					
						
							| 
									
										
										
										
											2020-03-26 14:43:28 -07:00
										 |  |  |     this._runningTestTerminate = null; | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |     this._runs = []; | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-12 17:32:53 -07:00
										 |  |  |   terminate(terminateHooks) { | 
					
						
							|  |  |  |     this._terminating = true; | 
					
						
							| 
									
										
										
										
											2020-03-26 14:43:28 -07:00
										 |  |  |     if (this._runningTestTerminate) | 
					
						
							|  |  |  |       this._runningTestTerminate(); | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |     this._hookRunner.terminateWorker(this); | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |   _markTerminated(testRun) { | 
					
						
							| 
									
										
										
										
											2020-03-12 17:32:53 -07:00
										 |  |  |     if (!this._terminating) | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |       return false; | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |     testRun._result = TestResult.Terminated; | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |   async run(testRun) { | 
					
						
							|  |  |  |     this._runs.push(testRun); | 
					
						
							| 
									
										
										
										
											2020-03-12 17:32:53 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |     const test = testRun.test(); | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  |     let skipped = test.skipped(); | 
					
						
							| 
									
										
										
										
											2020-03-27 15:35:14 -07:00
										 |  |  |     for (let suite = test.suite(); suite; suite = suite.parentSuite()) | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  |       skipped = skipped || suite.skipped(); | 
					
						
							| 
									
										
										
										
											2020-03-27 15:35:14 -07:00
										 |  |  |     if (skipped) { | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |       await this._willStartTestRun(testRun); | 
					
						
							|  |  |  |       testRun._result = TestResult.Skipped; | 
					
						
							|  |  |  |       await this._didFinishTestRun(testRun); | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-27 15:35:14 -07:00
										 |  |  |     let expectedToFail = test.expectation() === TestExpectation.Fail; | 
					
						
							|  |  |  |     for (let suite = test.suite(); suite; suite = suite.parentSuite()) | 
					
						
							|  |  |  |       expectedToFail = expectedToFail || (suite.expectation() === TestExpectation.Fail); | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  |     if (expectedToFail) { | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |       await this._willStartTestRun(testRun); | 
					
						
							|  |  |  |       testRun._result = TestResult.MarkedAsFailing; | 
					
						
							|  |  |  |       await this._didFinishTestRun(testRun); | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |       return; | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |     const environmentStack = testRun._environments; | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |     let common = 0; | 
					
						
							| 
									
										
										
										
											2020-04-01 10:49:47 -07:00
										 |  |  |     while (common < environmentStack.length && this._environmentStack[common] === environmentStack[common]) | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |       common++; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-01 10:49:47 -07:00
										 |  |  |     while (this._environmentStack.length > common) { | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |       if (this._markTerminated(testRun)) | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2020-04-01 10:49:47 -07:00
										 |  |  |       const environment = this._environmentStack.pop(); | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  |       if (!await this._hookRunner.runHook(environment, 'afterAll', [this._state], this, testRun)) | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  |       if (!await this._hookRunner.maybeRunGlobalTeardown(environment)) | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-04-01 10:49:47 -07:00
										 |  |  |     while (this._environmentStack.length < environmentStack.length) { | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |       if (this._markTerminated(testRun)) | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2020-04-01 10:49:47 -07:00
										 |  |  |       const environment = environmentStack[this._environmentStack.length]; | 
					
						
							|  |  |  |       this._environmentStack.push(environment); | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  |       if (!await this._hookRunner.maybeRunGlobalSetup(environment)) | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  |       if (!await this._hookRunner.runHook(environment, 'beforeAll', [this._state], this, testRun)) | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |     if (this._markTerminated(testRun)) | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |       return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // From this point till the end, we have to run all hooks
 | 
					
						
							|  |  |  |     // no matter what happens.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |     await this._willStartTestRun(testRun); | 
					
						
							| 
									
										
										
										
											2020-04-01 10:49:47 -07:00
										 |  |  |     for (const environment of this._environmentStack) { | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  |       await this._hookRunner.runHook(environment, 'beforeEach', [this._state, testRun], this, testRun); | 
					
						
							| 
									
										
										
										
											2020-03-27 22:57:22 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |     if (!testRun._error && !this._markTerminated(testRun)) { | 
					
						
							|  |  |  |       await this._willStartTestBody(testRun); | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  |       const { promise, terminate } = runUserCallback(test.body(), test.timeout(), [this._state, testRun]); | 
					
						
							| 
									
										
										
										
											2020-03-26 14:43:28 -07:00
										 |  |  |       this._runningTestTerminate = terminate; | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |       testRun._error = await promise; | 
					
						
							| 
									
										
										
										
											2020-03-26 14:43:28 -07:00
										 |  |  |       this._runningTestTerminate = null; | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |       if (testRun._error && testRun._error.stack) | 
					
						
							| 
									
										
										
										
											2020-04-03 15:47:25 -07:00
										 |  |  |         await this._testRunner._sourceMapSupport.rewriteStackTraceWithSourceMaps(testRun._error); | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |       if (!testRun._error) | 
					
						
							|  |  |  |         testRun._result = TestResult.Ok; | 
					
						
							|  |  |  |       else if (testRun._error === TimeoutError) | 
					
						
							|  |  |  |         testRun._result = TestResult.TimedOut; | 
					
						
							|  |  |  |       else if (testRun._error === TerminatedError) | 
					
						
							|  |  |  |         testRun._result = TestResult.Terminated; | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |       else | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |         testRun._result = TestResult.Failed; | 
					
						
							|  |  |  |       await this._didFinishTestBody(testRun); | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |     for (const environment of this._environmentStack.slice().reverse()) | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  |       await this._hookRunner.runHook(environment, 'afterEach', [this._state, testRun], this, testRun); | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |     await this._didFinishTestRun(testRun); | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |   async _willStartTestRun(testRun) { | 
					
						
							|  |  |  |     testRun._startTimestamp = Date.now(); | 
					
						
							|  |  |  |     testRun._workerId = this._workerId; | 
					
						
							|  |  |  |     await this._testRunner._runDelegateCallback(this._testRunner._delegate.onTestRunStarted, [testRun]); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async _didFinishTestRun(testRun) { | 
					
						
							|  |  |  |     testRun._endTimestamp = Date.now(); | 
					
						
							|  |  |  |     testRun._workerId = this._workerId; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this._hookRunner.markFinishedTestRun(testRun); | 
					
						
							|  |  |  |     await this._testRunner._runDelegateCallback(this._testRunner._delegate.onTestRunFinished, [testRun]); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async _willStartTestBody(testRun) { | 
					
						
							|  |  |  |     debug('testrunner:test')(`[${this._workerId}] starting "${testRun.test().fullName()}" (${testRun.test().location()})`); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async _didFinishTestBody(testRun) { | 
					
						
							|  |  |  |     debug('testrunner:test')(`[${this._workerId}] ${testRun._result.toUpperCase()} "${testRun.test().fullName()}" (${testRun.test().location()})`); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async shutdown() { | 
					
						
							|  |  |  |     while (this._environmentStack.length > 0) { | 
					
						
							|  |  |  |       const environment = this._environmentStack.pop(); | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  |       await this._hookRunner.runHook(environment, 'afterAll', [this._state], this, null); | 
					
						
							|  |  |  |       await this._hookRunner.maybeRunGlobalTeardown(environment); | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class HookRunner { | 
					
						
							|  |  |  |   constructor(testRunner, testRuns) { | 
					
						
							|  |  |  |     this._testRunner = testRunner; | 
					
						
							|  |  |  |     this._runningHookTerminations = new Map(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this._environmentToGlobalState = new Map(); | 
					
						
							|  |  |  |     for (const testRun of testRuns) { | 
					
						
							|  |  |  |       for (const env of testRun._environments) { | 
					
						
							|  |  |  |         let globalState = this._environmentToGlobalState.get(env); | 
					
						
							|  |  |  |         if (!globalState) { | 
					
						
							|  |  |  |           globalState = { | 
					
						
							|  |  |  |             pendingTestRuns: new Set(), | 
					
						
							|  |  |  |             globalSetupPromise: null, | 
					
						
							|  |  |  |             globalTeardownPromise: null, | 
					
						
							|  |  |  |           }; | 
					
						
							|  |  |  |           this._environmentToGlobalState.set(env, globalState); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         globalState.pendingTestRuns.add(testRun); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   terminateWorker(worker) { | 
					
						
							|  |  |  |     let termination = this._runningHookTerminations.get(worker); | 
					
						
							|  |  |  |     this._runningHookTerminations.delete(worker); | 
					
						
							|  |  |  |     if (termination) | 
					
						
							|  |  |  |       termination(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   terminateAll() { | 
					
						
							|  |  |  |     for (const termination of this._runningHookTerminations.values()) | 
					
						
							|  |  |  |       termination(); | 
					
						
							|  |  |  |     this._runningHookTerminations.clear(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   markFinishedTestRun(testRun) { | 
					
						
							|  |  |  |     for (const environment of testRun._environments) { | 
					
						
							|  |  |  |       const globalState = this._environmentToGlobalState.get(environment); | 
					
						
							|  |  |  |       globalState.pendingTestRuns.delete(testRun); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  |   async _runHookInternal(worker, testRun, hook, fullName, hookArgs = []) { | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |     await this._willStartHook(worker, testRun, hook, fullName); | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  |     const timeout = this._testRunner._hookTimeout; | 
					
						
							| 
									
										
										
										
											2020-06-23 18:17:14 -07:00
										 |  |  |     const { promise, terminate } = runUserCallback(hook.body, timeout, hookArgs); | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |     this._runningHookTerminations.set(worker, terminate); | 
					
						
							| 
									
										
										
										
											2020-03-26 14:43:28 -07:00
										 |  |  |     let error = await promise; | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |     this._runningHookTerminations.delete(worker); | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (error) { | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |       if (testRun && testRun._result !== TestResult.Terminated) { | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |         // Prefer terminated result over any hook failures.
 | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |         testRun._result = error === TerminatedError ? TestResult.Terminated : TestResult.Crashed; | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-03-12 17:32:53 -07:00
										 |  |  |       let message; | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |       if (error === TimeoutError) { | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  |         message = `Timeout Exceeded ${timeout}ms while running "${hook.name}" in "${fullName}"`; | 
					
						
							| 
									
										
										
										
											2020-03-12 17:32:53 -07:00
										 |  |  |         error = null; | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |       } else if (error === TerminatedError) { | 
					
						
							| 
									
										
										
										
											2020-03-24 14:40:59 -07:00
										 |  |  |         // Do not report termination details - it's just noise.
 | 
					
						
							|  |  |  |         message = ''; | 
					
						
							| 
									
										
										
										
											2020-03-12 17:32:53 -07:00
										 |  |  |         error = null; | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |       } else { | 
					
						
							|  |  |  |         if (error.stack) | 
					
						
							| 
									
										
										
										
											2020-04-03 15:47:25 -07:00
										 |  |  |           await this._testRunner._sourceMapSupport.rewriteStackTraceWithSourceMaps(error); | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  |         message = `FAILED while running "${hook.name}" in suite "${fullName}": `; | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |       await this._didFailHook(worker, testRun, hook, fullName, message, error); | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |       if (testRun) | 
					
						
							|  |  |  |         testRun._error = error; | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |     await this._didCompleteHook(worker, testRun, hook, fullName); | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  |   async runHook(environment, hookName, hookArgs, worker = null, testRun = null) { | 
					
						
							|  |  |  |     const hookBody = environment[hookName]; | 
					
						
							|  |  |  |     if (!hookBody) | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     const envName = environment.name ? environment.name() : environment.constructor.name; | 
					
						
							|  |  |  |     return await this._runHookInternal(worker, testRun, {name: hookName, body: hookBody.bind(environment)}, envName, hookArgs); | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  |   async maybeRunGlobalSetup(environment) { | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |     const globalState = this._environmentToGlobalState.get(environment); | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  |     if (!globalState.globalSetupPromise) | 
					
						
							|  |  |  |       globalState.globalSetupPromise = this.runHook(environment, 'globalSetup', []); | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |     if (!await globalState.globalSetupPromise) { | 
					
						
							|  |  |  |       await this._testRunner._terminate(TestResult.Crashed, 'Global setup failed!', false, null); | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  |   async maybeRunGlobalTeardown(environment) { | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |     const globalState = this._environmentToGlobalState.get(environment); | 
					
						
							|  |  |  |     if (!globalState.globalTeardownPromise) { | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  |       if (!globalState.pendingTestRuns.size || (this._testRunner._terminating && globalState.globalSetupPromise)) | 
					
						
							|  |  |  |         globalState.globalTeardownPromise = this.runHook(environment, 'globalTeardown', []); | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (!globalState.globalTeardownPromise) | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     if (!await globalState.globalTeardownPromise) { | 
					
						
							|  |  |  |       await this._testRunner._terminate(TestResult.Crashed, 'Global teardown failed!', false, null); | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async _willStartHook(worker, testRun, hook, fullName) { | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  |     debug('testrunner:hook')(`${workerName(worker)} "${fullName}.${hook.name}" started for "${testRun ? testRun.test().fullName() : ''}"`); | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |   async _didFailHook(worker, testRun, hook, fullName, message, error) { | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  |     debug('testrunner:hook')(`${workerName(worker)} "${fullName}.${hook.name}" FAILED for "${testRun ? testRun.test().fullName() : ''}"`); | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |     if (message) | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |       this._testRunner._result.addError(message, error, worker); | 
					
						
							| 
									
										
										
										
											2020-04-03 15:47:25 -07:00
										 |  |  |     this._testRunner._result.setResult(TestResult.Crashed, message); | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |   async _didCompleteHook(worker, testRun, hook, fullName) { | 
					
						
							| 
									
										
										
										
											2020-07-02 11:05:38 -07:00
										 |  |  |     debug('testrunner:hook')(`${workerName(worker)} "${fullName}.${hook.name}" OK for "${testRun ? testRun.test().fullName() : ''}"`); | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  | function workerName(worker) { | 
					
						
							|  |  |  |   return worker ? `<worker ${worker._workerId}>` : `<_global_>`; | 
					
						
							| 
									
										
										
										
											2020-03-10 11:30:02 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 15:47:25 -07:00
										 |  |  | class TestRunner { | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  |   constructor() { | 
					
						
							| 
									
										
										
										
											2020-01-08 16:16:54 +00:00
										 |  |  |     this._sourceMapSupport = new SourceMapSupport(); | 
					
						
							| 
									
										
										
										
											2020-04-03 15:47:25 -07:00
										 |  |  |     this._nextWorkerId = 1; | 
					
						
							|  |  |  |     this._workers = []; | 
					
						
							|  |  |  |     this._terminating = false; | 
					
						
							|  |  |  |     this._result = null; | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |     this._hookRunner = null; | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-04-03 15:47:25 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-07 22:56:21 -07:00
										 |  |  |   async _runDelegateCallback(callback, args) { | 
					
						
							|  |  |  |     let { promise, terminate } = runUserCallback(callback, this._hookTimeout, args); | 
					
						
							|  |  |  |     // Note: we do not terminate the delegate to keep reporting even when terminating.
 | 
					
						
							|  |  |  |     const e = await promise; | 
					
						
							|  |  |  |     if (e) { | 
					
						
							|  |  |  |       debug('testrunner')(`Error while running delegate method: ${e}`); | 
					
						
							|  |  |  |       const { message, error } = this._toError('INTERNAL ERROR', e); | 
					
						
							|  |  |  |       this._terminate(TestResult.Crashed, message, false, error); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _toError(message, error) { | 
					
						
							|  |  |  |     if (!(error instanceof Error)) { | 
					
						
							|  |  |  |       message += ': ' + error; | 
					
						
							|  |  |  |       error = new Error(); | 
					
						
							|  |  |  |       error.stack = ''; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return { message, error }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  |   async run(testRuns, options = {}) { | 
					
						
							|  |  |  |     const { | 
					
						
							|  |  |  |       parallel = 1, | 
					
						
							|  |  |  |       breakOnFailure = false, | 
					
						
							|  |  |  |       hookTimeout = 10 * 1000, | 
					
						
							|  |  |  |       totalTimeout = 0, | 
					
						
							|  |  |  |       onStarted = async (testRuns) => {}, | 
					
						
							|  |  |  |       onFinished = async (result) => {}, | 
					
						
							| 
									
										
										
										
											2020-04-07 22:56:21 -07:00
										 |  |  |       onTestRunStarted = async (testRun) => {}, | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  |       onTestRunFinished = async (testRun) => {}, | 
					
						
							|  |  |  |     } = options; | 
					
						
							|  |  |  |     this._breakOnFailure = breakOnFailure; | 
					
						
							| 
									
										
										
										
											2020-04-13 14:30:51 -07:00
										 |  |  |     this._hookTimeout = hookTimeout === 0 ? 100000000 : hookTimeout; | 
					
						
							| 
									
										
										
										
											2020-04-03 15:47:25 -07:00
										 |  |  |     this._delegate = { | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  |       onStarted, | 
					
						
							|  |  |  |       onFinished, | 
					
						
							|  |  |  |       onTestRunStarted, | 
					
						
							|  |  |  |       onTestRunFinished | 
					
						
							| 
									
										
										
										
											2020-04-01 10:49:47 -07:00
										 |  |  |     }; | 
					
						
							| 
									
										
										
										
											2020-03-25 22:42:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  |     this._result = new Result(); | 
					
						
							|  |  |  |     this._result.runs = testRuns; | 
					
						
							| 
									
										
										
										
											2020-03-25 22:42:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-17 18:42:12 -07:00
										 |  |  |     const terminationPromises = []; | 
					
						
							| 
									
										
										
										
											2020-04-07 16:02:33 -07:00
										 |  |  |     const handleSIGINT = () => this._terminate(TestResult.Terminated, 'SIGINT received', false, null); | 
					
						
							|  |  |  |     const handleSIGHUP = () => this._terminate(TestResult.Terminated, 'SIGHUP received', false, null); | 
					
						
							|  |  |  |     const handleSIGTERM = () => this._terminate(TestResult.Terminated, 'SIGTERM received', true, null); | 
					
						
							| 
									
										
										
										
											2020-04-07 22:56:21 -07:00
										 |  |  |     const handleRejection = e => { | 
					
						
							|  |  |  |       const { message, error } = this._toError('UNHANDLED PROMISE REJECTION', e); | 
					
						
							| 
									
										
										
										
											2020-04-17 18:42:12 -07:00
										 |  |  |       terminationPromises.push(this._terminate(TestResult.Crashed, message, false, error)); | 
					
						
							| 
									
										
										
										
											2020-04-07 16:02:33 -07:00
										 |  |  |     }; | 
					
						
							| 
									
										
										
										
											2020-04-07 22:56:21 -07:00
										 |  |  |     const handleException = e => { | 
					
						
							|  |  |  |       const { message, error } = this._toError('UNHANDLED ERROR', e); | 
					
						
							| 
									
										
										
										
											2020-04-17 18:42:12 -07:00
										 |  |  |       terminationPromises.push(this._terminate(TestResult.Crashed, message, false, error)); | 
					
						
							| 
									
										
										
										
											2020-04-07 16:02:33 -07:00
										 |  |  |     }; | 
					
						
							|  |  |  |     process.on('SIGINT', handleSIGINT); | 
					
						
							|  |  |  |     process.on('SIGHUP', handleSIGHUP); | 
					
						
							|  |  |  |     process.on('SIGTERM', handleSIGTERM); | 
					
						
							|  |  |  |     process.on('unhandledRejection', handleRejection); | 
					
						
							|  |  |  |     process.on('uncaughtException', handleException); | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-07 22:56:21 -07:00
										 |  |  |     let timeoutId; | 
					
						
							|  |  |  |     if (totalTimeout) { | 
					
						
							|  |  |  |       timeoutId = setTimeout(() => { | 
					
						
							| 
									
										
										
										
											2020-04-17 18:42:12 -07:00
										 |  |  |         terminationPromises.push(this._terminate(TestResult.Terminated, `Total timeout of ${totalTimeout}ms reached.`, true /* force */, null /* error */)); | 
					
						
							| 
									
										
										
										
											2020-04-07 22:56:21 -07:00
										 |  |  |       }, totalTimeout); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     await this._runDelegateCallback(this._delegate.onStarted, [testRuns]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |     this._hookRunner = new HookRunner(this, testRuns); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  |     const workerCount = Math.min(parallel, testRuns.length); | 
					
						
							|  |  |  |     const workerPromises = []; | 
					
						
							|  |  |  |     for (let i = 0; i < workerCount; ++i) { | 
					
						
							|  |  |  |       const initialTestRunIndex = i * Math.floor(testRuns.length / workerCount); | 
					
						
							|  |  |  |       workerPromises.push(this._runWorker(initialTestRunIndex, testRuns, i)); | 
					
						
							| 
									
										
										
										
											2020-03-28 14:25:57 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  |     await Promise.all(workerPromises); | 
					
						
							| 
									
										
										
										
											2020-04-17 18:42:12 -07:00
										 |  |  |     await Promise.all(terminationPromises); | 
					
						
							| 
									
										
										
										
											2020-03-11 18:30:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  |     if (testRuns.some(run => run.isFailure())) | 
					
						
							|  |  |  |       this._result.setResult(TestResult.Failed, ''); | 
					
						
							| 
									
										
										
										
											2020-04-03 15:47:25 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-07 22:56:21 -07:00
										 |  |  |     await this._runDelegateCallback(this._delegate.onFinished, [this._result]); | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  |     clearTimeout(timeoutId); | 
					
						
							| 
									
										
										
										
											2020-04-03 15:47:25 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-07 22:56:21 -07:00
										 |  |  |     process.removeListener('SIGINT', handleSIGINT); | 
					
						
							|  |  |  |     process.removeListener('SIGHUP', handleSIGHUP); | 
					
						
							|  |  |  |     process.removeListener('SIGTERM', handleSIGTERM); | 
					
						
							|  |  |  |     process.removeListener('unhandledRejection', handleRejection); | 
					
						
							|  |  |  |     process.removeListener('uncaughtException', handleException); | 
					
						
							|  |  |  |     return this._result; | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-03 15:47:25 -07:00
										 |  |  |   async _runWorker(testRunIndex, testRuns, parallelIndex) { | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |     let worker = new TestWorker(this, this._hookRunner, this._nextWorkerId++, parallelIndex); | 
					
						
							| 
									
										
										
										
											2020-04-03 15:47:25 -07:00
										 |  |  |     this._workers[parallelIndex] = worker; | 
					
						
							|  |  |  |     while (!this._terminating) { | 
					
						
							|  |  |  |       let skipped = 0; | 
					
						
							|  |  |  |       while (skipped < testRuns.length && testRuns[testRunIndex]._result !== null) { | 
					
						
							|  |  |  |         testRunIndex = (testRunIndex + 1) % testRuns.length; | 
					
						
							|  |  |  |         skipped++; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       const testRun = testRuns[testRunIndex]; | 
					
						
							|  |  |  |       if (testRun._result !== null) { | 
					
						
							|  |  |  |         // All tests have been run.
 | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Mark as running so that other workers do not run it again.
 | 
					
						
							|  |  |  |       testRun._result = 'running'; | 
					
						
							|  |  |  |       await worker.run(testRun); | 
					
						
							|  |  |  |       if (testRun.isFailure()) { | 
					
						
							|  |  |  |         // Something went wrong during test run, let's use a fresh worker.
 | 
					
						
							|  |  |  |         await worker.shutdown(); | 
					
						
							|  |  |  |         if (this._breakOnFailure) { | 
					
						
							|  |  |  |           const message = `Terminating because a test has failed and |testRunner.breakOnFailure| is enabled`; | 
					
						
							|  |  |  |           await this._terminate(TestResult.Terminated, message, false /* force */, null /* error */); | 
					
						
							|  |  |  |           return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |         worker = new TestWorker(this, this._hookRunner, this._nextWorkerId++, parallelIndex); | 
					
						
							| 
									
										
										
										
											2020-04-03 15:47:25 -07:00
										 |  |  |         this._workers[parallelIndex] = worker; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     await worker.shutdown(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async _terminate(result, message, force, error) { | 
					
						
							|  |  |  |     debug('testrunner')(`TERMINATED result = ${result}, message = ${message}`); | 
					
						
							|  |  |  |     this._terminating = true; | 
					
						
							|  |  |  |     for (const worker of this._workers) | 
					
						
							|  |  |  |       worker.terminate(force /* terminateHooks */); | 
					
						
							| 
									
										
										
										
											2020-06-24 22:08:46 -07:00
										 |  |  |     if (this._hookRunner) | 
					
						
							|  |  |  |       this._hookRunner.terminateAll(); | 
					
						
							| 
									
										
										
										
											2020-04-03 15:47:25 -07:00
										 |  |  |     this._result.setResult(result, message); | 
					
						
							|  |  |  |     if (this._result.message === 'SIGINT received' && message === 'SIGTERM received') | 
					
						
							|  |  |  |       this._result.message = message; | 
					
						
							|  |  |  |     if (error) { | 
					
						
							|  |  |  |       if (error.stack) | 
					
						
							|  |  |  |         await this._sourceMapSupport.rewriteStackTraceWithSourceMaps(error); | 
					
						
							|  |  |  |       this._result.addError(message, error, this._workers.length === 1 ? this._workers[0] : null); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-09 16:37:19 +00:00
										 |  |  |   async terminate() { | 
					
						
							| 
									
										
										
										
											2020-04-03 15:47:25 -07:00
										 |  |  |     if (!this._result) | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |       return; | 
					
						
							| 
									
										
										
										
											2020-04-03 15:47:25 -07:00
										 |  |  |     await this._terminate(TestResult.Terminated, 'Terminated with |TestRunner.terminate()| call', true /* force */, null /* error */); | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-06 17:21:42 -07:00
										 |  |  | module.exports = { TestRunner, TestRun, TestResult, Result }; |