This repository was archived by the owner on Jul 29, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
chore(promises): remove q promises and webdriver promises #5052
Merged
cnishina
merged 5 commits into
angular:selenium4
from
cnishina:you_made_me_promises_promises
Nov 27, 2018
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
08d3805
chore(promises): remove q promises and webdriver promises starting at…
cnishina 0a3b64b
resolve comments
cnishina 777a215
updating deprecated message. adding unhandledRejection
cnishina 0b95977
resolve comments
cnishina 4b57a18
travis?
cnishina File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,16 +3,15 @@ | |
* input configuration and launching test runners. | ||
*/ | ||
import * as fs from 'fs'; | ||
import * as q from 'q'; | ||
|
||
import {Config} from './config'; | ||
import {ConfigParser} from './configParser'; | ||
cnishina marked this conversation as resolved.
Show resolved
Hide resolved
|
||
import {ConfigError, ErrorHandler, ProtractorError} from './exitCodes'; | ||
import {Logger} from './logger'; | ||
import {Runner} from './runner'; | ||
import {TaskRunner} from './taskRunner'; | ||
import {TaskScheduler} from './taskScheduler'; | ||
import * as helper from './util'; | ||
import {runFilenameOrFn_} from './util'; | ||
|
||
|
||
let logger = new Logger('launcher'); | ||
let RUNNERS_FAILED_EXIT_CODE = 100; | ||
|
@@ -93,7 +92,7 @@ let taskResults_ = new TaskResults(); | |
* @param {string=} configFile | ||
* @param {Object=} additionalConfig | ||
*/ | ||
let initFn = function(configFile: string, additionalConfig: Config) { | ||
let initFn = async function(configFile: string, additionalConfig: Config) { | ||
let configParser = new ConfigParser(); | ||
if (configFile) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we need it check still here with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure. Could you clarify? |
||
configParser.addFileConfig(configFile); | ||
|
@@ -108,197 +107,159 @@ let initFn = function(configFile: string, additionalConfig: Config) { | |
logger.debug('Your base url for tests is ' + config.baseUrl); | ||
|
||
// Run beforeLaunch | ||
helper.runFilenameOrFn_(config.configDir, config.beforeLaunch) | ||
.then(() => { | ||
await runFilenameOrFn_(config.configDir, config.beforeLaunch); | ||
// 1) If getMultiCapabilities is set, resolve that as | ||
// `multiCapabilities`. | ||
if (config.getMultiCapabilities && typeof config.getMultiCapabilities === 'function') { | ||
if (config.multiCapabilities.length || config.capabilities) { | ||
logger.warn( | ||
'getMultiCapabilities() will override both capabilities ' + | ||
'and multiCapabilities'); | ||
} | ||
// If getMultiCapabilities is defined and a function, use this. | ||
const waitMultiConfig = await config.getMultiCapabilities(); | ||
config.multiCapabilities = waitMultiConfig; | ||
config.capabilities = null; | ||
} | ||
|
||
return q | ||
.Promise<any>((resolve: Function, reject: Function) => { | ||
// 1) If getMultiCapabilities is set, resolve that as | ||
// `multiCapabilities`. | ||
if (config.getMultiCapabilities && | ||
typeof config.getMultiCapabilities === 'function') { | ||
if (config.multiCapabilities.length || config.capabilities) { | ||
logger.warn( | ||
'getMultiCapabilities() will override both capabilities ' + | ||
'and multiCapabilities'); | ||
} | ||
// If getMultiCapabilities is defined and a function, use this. | ||
q(config.getMultiCapabilities()) | ||
.then((multiCapabilities) => { | ||
config.multiCapabilities = multiCapabilities; | ||
config.capabilities = null; | ||
}) | ||
.then(() => { | ||
resolve(); | ||
}) | ||
.catch(err => { | ||
reject(err); | ||
}); | ||
} else { | ||
resolve(); | ||
} | ||
}) | ||
.then(() => { | ||
// 2) Set `multicapabilities` using `capabilities`, | ||
// `multicapabilities`, | ||
// or default | ||
if (config.capabilities) { | ||
if (config.multiCapabilities.length) { | ||
logger.warn( | ||
'You have specified both capabilities and ' + | ||
'multiCapabilities. This will result in capabilities being ' + | ||
'ignored'); | ||
} else { | ||
// Use capabilities if multiCapabilities is empty. | ||
config.multiCapabilities = [config.capabilities]; | ||
} | ||
} else if (!config.multiCapabilities.length) { | ||
// Default to chrome if no capabilities given | ||
config.multiCapabilities = [{browserName: 'chrome'}]; | ||
} | ||
}); | ||
}) | ||
.then(() => { | ||
// 3) If we're in `elementExplorer` mode, run only that. | ||
if (config.elementExplorer || config.framework === 'explorer') { | ||
if (config.multiCapabilities.length != 1) { | ||
throw new Error('Must specify only 1 browser while using elementExplorer'); | ||
} else { | ||
config.capabilities = config.multiCapabilities[0]; | ||
} | ||
config.framework = 'explorer'; | ||
// 2) Set `multicapabilities` using `capabilities`, | ||
// `multicapabilities`, or default | ||
if (config.capabilities) { | ||
if (config.multiCapabilities.length) { | ||
logger.warn( | ||
'You have specified both capabilities and ' + | ||
'multiCapabilities. This will result in capabilities being ' + | ||
'ignored'); | ||
} else { | ||
// Use capabilities if multiCapabilities is empty. | ||
config.multiCapabilities = [config.capabilities]; | ||
} | ||
} else if (!config.multiCapabilities.length) { | ||
// Default to chrome if no capabilities given | ||
config.multiCapabilities = [{browserName: 'chrome'}]; | ||
} | ||
|
||
let runner = new Runner(config); | ||
return runner.run().then( | ||
(exitCode: number) => { | ||
process.exit(exitCode); | ||
}, | ||
(err: Error) => { | ||
logger.error(err); | ||
process.exit(1); | ||
}); | ||
} | ||
}) | ||
.then(() => { | ||
// 4) Run tests. | ||
let scheduler = new TaskScheduler(config); | ||
// 3) If we're in `elementExplorer` mode, throw an error and exit. | ||
if (config.elementExplorer || config.framework === 'explorer') { | ||
cnishina marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const err = new Error( | ||
'Deprecated: Element explorer depends on the ' + | ||
'WebDriver control flow, and thus is no longer supported.'); | ||
logger.error(err); | ||
process.exit(1); | ||
} | ||
|
||
process.on('uncaughtException', (exc: (Error|string)) => { | ||
let e = (exc instanceof Error) ? exc : new Error(exc); | ||
if (config.ignoreUncaughtExceptions) { | ||
// This can be a sign of a bug in the test framework, that it may | ||
// not be handling WebDriver errors properly. However, we don't | ||
// want these errors to prevent running the tests. | ||
logger.warn('Ignoring uncaught error ' + exc); | ||
return; | ||
} | ||
// 4) Run tests. | ||
let scheduler = new TaskScheduler(config); | ||
|
||
let errorCode = ErrorHandler.parseError(e); | ||
if (errorCode) { | ||
let protractorError = e as ProtractorError; | ||
ProtractorError.log(logger, errorCode, protractorError.message, protractorError.stack); | ||
process.exit(errorCode); | ||
} else { | ||
logger.error(e.message); | ||
logger.error(e.stack); | ||
process.exit(ProtractorError.CODE); | ||
} | ||
}); | ||
process.on('uncaughtException', (exc: (Error|string)) => { | ||
let e = (exc instanceof Error) ? exc : new Error(exc); | ||
if (config.ignoreUncaughtExceptions) { | ||
// This can be a sign of a bug in the test framework, that it may | ||
// not be handling WebDriver errors properly. However, we don't | ||
// want these errors to prevent running the tests. | ||
logger.warn('Ignoring uncaught error ' + exc); | ||
return; | ||
} | ||
logger.error(e.message); | ||
logger.error(e.stack); | ||
if (e instanceof ProtractorError) { | ||
let protractorError = e as ProtractorError; | ||
process.exit(protractorError.code); | ||
} else { | ||
process.exit(1); | ||
} | ||
}); | ||
|
||
process.on('exit', (code: number) => { | ||
if (code) { | ||
logger.error('Process exited with error code ' + code); | ||
} else if (scheduler.numTasksOutstanding() > 0) { | ||
logger.error( | ||
'BUG: launcher exited with ' + scheduler.numTasksOutstanding() + | ||
' tasks remaining'); | ||
process.exit(RUNNERS_FAILED_EXIT_CODE); | ||
} | ||
}); | ||
process.on('unhandledRejection', (reason: Error | any, p: Promise<any>) => { | ||
logger.warn('Unhandled rejection at:', p, 'reason:', reason); | ||
}); | ||
|
||
// Run afterlaunch and exit | ||
let cleanUpAndExit = (exitCode: number) => { | ||
return helper.runFilenameOrFn_(config.configDir, config.afterLaunch, [exitCode]) | ||
.then( | ||
(returned) => { | ||
if (typeof returned === 'number') { | ||
process.exit(returned); | ||
} else { | ||
process.exit(exitCode); | ||
} | ||
}, | ||
(err: Error) => { | ||
logger.error('Error:', err); | ||
process.exit(1); | ||
}); | ||
}; | ||
process.on('exit', (code: number) => { | ||
if (code) { | ||
logger.error('Process exited with error code ' + code); | ||
} else if (scheduler.numTasksOutstanding() > 0) { | ||
logger.error( | ||
'BUG: launcher exited with ' + scheduler.numTasksOutstanding() + ' tasks remaining'); | ||
process.exit(RUNNERS_FAILED_EXIT_CODE); | ||
} | ||
}); | ||
|
||
let totalTasks = scheduler.numTasksOutstanding(); | ||
let forkProcess = false; | ||
if (totalTasks > 1) { // Start new processes only if there are >1 tasks. | ||
forkProcess = true; | ||
if (config.debug) { | ||
throw new ConfigError( | ||
logger, 'Cannot run in debug mode with multiCapabilities, count > 1, or sharding'); | ||
} | ||
} | ||
// Run afterlaunch and exit | ||
const cleanUpAndExit = async (exitCode: number) => { | ||
try { | ||
const returned = await runFilenameOrFn_(config.configDir, config.afterLaunch, [exitCode]); | ||
if (typeof returned === 'number') { | ||
process.exit(returned); | ||
} else { | ||
process.exit(exitCode); | ||
} | ||
} catch (err) { | ||
logger.error('Error:', err); | ||
process.exit(1); | ||
} | ||
}; | ||
|
||
let deferred = q.defer<any>(); // Resolved when all tasks are completed | ||
let createNextTaskRunner = () => { | ||
let task = scheduler.nextTask(); | ||
if (task) { | ||
let taskRunner = new TaskRunner(configFile, additionalConfig, task, forkProcess); | ||
taskRunner.run() | ||
.then((result) => { | ||
if (result.exitCode && !result.failedCount) { | ||
logger.error( | ||
'Runner process exited unexpectedly with error code: ' + result.exitCode); | ||
} | ||
taskResults_.add(result); | ||
task.done(); | ||
createNextTaskRunner(); | ||
// If all tasks are finished | ||
if (scheduler.numTasksOutstanding() === 0) { | ||
deferred.resolve(); | ||
} | ||
logger.info( | ||
scheduler.countActiveTasks() + ' instance(s) of WebDriver still running'); | ||
}) | ||
.catch((err: Error) => { | ||
logger.error('Error:', (err as any).stack || err.message || err); | ||
cleanUpAndExit(RUNNERS_FAILED_EXIT_CODE); | ||
}); | ||
const totalTasks = scheduler.numTasksOutstanding(); | ||
let forkProcess = false; | ||
heathkit marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (totalTasks > 1) { // Start new processes only if there are >1 tasks. | ||
forkProcess = true; | ||
if (config.debug) { | ||
throw new ConfigError( | ||
logger, 'Cannot run in debug mode with multiCapabilities, count > 1, or sharding'); | ||
} | ||
} | ||
|
||
const createNextTaskRunner = async () => { | ||
return new Promise(async (resolve) => { | ||
const task = scheduler.nextTask(); | ||
if (task) { | ||
const taskRunner = new TaskRunner(configFile, additionalConfig, task, forkProcess); | ||
try { | ||
const result = await taskRunner.run(); | ||
if (result.exitCode && !result.failedCount) { | ||
logger.error('Runner process exited unexpectedly with error code: ' + result.exitCode); | ||
} | ||
}; | ||
// Start `scheduler.maxConcurrentTasks()` workers for handling tasks in | ||
// the beginning. As a worker finishes a task, it will pick up the next | ||
// task | ||
// from the scheduler's queue until all tasks are gone. | ||
for (let i = 0; i < scheduler.maxConcurrentTasks(); ++i) { | ||
taskResults_.add(result); | ||
task.done(); | ||
createNextTaskRunner(); | ||
// If all tasks are finished | ||
if (scheduler.numTasksOutstanding() === 0) { | ||
resolve(); | ||
} | ||
logger.info(scheduler.countActiveTasks() + ' instance(s) of WebDriver still running'); | ||
} catch (err) { | ||
const errorCode = ErrorHandler.parseError(err); | ||
logger.error('Error:', (err as any).stack || err.message || err); | ||
await cleanUpAndExit(errorCode ? errorCode : RUNNERS_FAILED_EXIT_CODE); | ||
} | ||
logger.info('Running ' + scheduler.countActiveTasks() + ' instances of WebDriver'); | ||
} | ||
}); | ||
}; | ||
|
||
cnishina marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const maxConcurrentTasks = scheduler.maxConcurrentTasks(); | ||
for (let i = 0; i < maxConcurrentTasks; ++i) { | ||
await createNextTaskRunner(); | ||
} | ||
logger.info('Running ' + scheduler.countActiveTasks() + ' instances of WebDriver'); | ||
|
||
// By now all runners have completed. | ||
deferred.promise | ||
.then(function() { | ||
// Save results if desired | ||
if (config.resultJsonOutputFile) { | ||
taskResults_.saveResults(config.resultJsonOutputFile); | ||
} | ||
// By now all runners have completed. | ||
// Save results if desired | ||
if (config.resultJsonOutputFile) { | ||
taskResults_.saveResults(config.resultJsonOutputFile); | ||
} | ||
|
||
taskResults_.reportSummary(); | ||
let exitCode = 0; | ||
if (taskResults_.totalProcessFailures() > 0) { | ||
exitCode = RUNNERS_FAILED_EXIT_CODE; | ||
} else if (taskResults_.totalSpecFailures() > 0) { | ||
exitCode = 1; | ||
} | ||
await cleanUpAndExit(exitCode); | ||
// Start `const maxConcurrentTasks` workers for handling tasks in | ||
// the beginning. As a worker finishes a task, it will pick up the next | ||
// task from the scheduler's queue until all tasks are gone. | ||
|
||
taskResults_.reportSummary(); | ||
let exitCode = 0; | ||
if (taskResults_.totalProcessFailures() > 0) { | ||
exitCode = RUNNERS_FAILED_EXIT_CODE; | ||
} else if (taskResults_.totalSpecFailures() > 0) { | ||
exitCode = 1; | ||
} | ||
return cleanUpAndExit(exitCode); | ||
}) | ||
.done(); | ||
}) | ||
.done(); | ||
}; | ||
|
||
export let init = initFn; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.