Skip to content
This repository was archived by the owner on Jul 29, 2024. It is now read-only.

Commit c9db3f3

Browse files
committed
chore(promises): remove q promises and webdriver promises (#5052)
- remove q promises and webdriver promises from the runner, launcher, plugins, and taskRunner - add deprecated message to element explorer. - add unhandledRejection - update browser versions used in travis tests
1 parent c0917aa commit c9db3f3

File tree

7 files changed

+365
-492
lines changed

7 files changed

+365
-492
lines changed

lib/config.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,11 @@ export interface Config {
723723
nodeDebug?: boolean;
724724
debuggerServerPort?: number;
725725
frameworkPath?: string;
726+
727+
/**
728+
* Deprecated: Element explorer depends on the WebDriver control flow, and
729+
* thus is no longer supported.
730+
*/
726731
elementExplorer?: any;
727732
debug?: boolean;
728733
unknownFlags_?: string[];

lib/launcher.ts

Lines changed: 143 additions & 182 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,15 @@
33
* input configuration and launching test runners.
44
*/
55
import * as fs from 'fs';
6-
import * as q from 'q';
76

87
import {Config} from './config';
98
import {ConfigParser} from './configParser';
109
import {ConfigError, ErrorHandler, ProtractorError} from './exitCodes';
1110
import {Logger} from './logger';
12-
import {Runner} from './runner';
1311
import {TaskRunner} from './taskRunner';
1412
import {TaskScheduler} from './taskScheduler';
15-
import * as helper from './util';
13+
import {runFilenameOrFn_} from './util';
14+
1615

1716
let logger = new Logger('launcher');
1817
let RUNNERS_FAILED_EXIT_CODE = 100;
@@ -93,7 +92,7 @@ let taskResults_ = new TaskResults();
9392
* @param {string=} configFile
9493
* @param {Object=} additionalConfig
9594
*/
96-
let initFn = function(configFile: string, additionalConfig: Config) {
95+
let initFn = async function(configFile: string, additionalConfig: Config) {
9796
let configParser = new ConfigParser();
9897
if (configFile) {
9998
configParser.addFileConfig(configFile);
@@ -108,197 +107,159 @@ let initFn = function(configFile: string, additionalConfig: Config) {
108107
logger.debug('Your base url for tests is ' + config.baseUrl);
109108

110109
// Run beforeLaunch
111-
helper.runFilenameOrFn_(config.configDir, config.beforeLaunch)
112-
.then(() => {
110+
await runFilenameOrFn_(config.configDir, config.beforeLaunch);
111+
// 1) If getMultiCapabilities is set, resolve that as
112+
// `multiCapabilities`.
113+
if (config.getMultiCapabilities && typeof config.getMultiCapabilities === 'function') {
114+
if (config.multiCapabilities.length || config.capabilities) {
115+
logger.warn(
116+
'getMultiCapabilities() will override both capabilities ' +
117+
'and multiCapabilities');
118+
}
119+
// If getMultiCapabilities is defined and a function, use this.
120+
const waitMultiConfig = await config.getMultiCapabilities();
121+
config.multiCapabilities = waitMultiConfig;
122+
config.capabilities = null;
123+
}
113124

114-
return q
115-
.Promise<any>((resolve: Function, reject: Function) => {
116-
// 1) If getMultiCapabilities is set, resolve that as
117-
// `multiCapabilities`.
118-
if (config.getMultiCapabilities &&
119-
typeof config.getMultiCapabilities === 'function') {
120-
if (config.multiCapabilities.length || config.capabilities) {
121-
logger.warn(
122-
'getMultiCapabilities() will override both capabilities ' +
123-
'and multiCapabilities');
124-
}
125-
// If getMultiCapabilities is defined and a function, use this.
126-
q(config.getMultiCapabilities())
127-
.then((multiCapabilities) => {
128-
config.multiCapabilities = multiCapabilities;
129-
config.capabilities = null;
130-
})
131-
.then(() => {
132-
resolve();
133-
})
134-
.catch(err => {
135-
reject(err);
136-
});
137-
} else {
138-
resolve();
139-
}
140-
})
141-
.then(() => {
142-
// 2) Set `multicapabilities` using `capabilities`,
143-
// `multicapabilities`,
144-
// or default
145-
if (config.capabilities) {
146-
if (config.multiCapabilities.length) {
147-
logger.warn(
148-
'You have specified both capabilities and ' +
149-
'multiCapabilities. This will result in capabilities being ' +
150-
'ignored');
151-
} else {
152-
// Use capabilities if multiCapabilities is empty.
153-
config.multiCapabilities = [config.capabilities];
154-
}
155-
} else if (!config.multiCapabilities.length) {
156-
// Default to chrome if no capabilities given
157-
config.multiCapabilities = [{browserName: 'chrome'}];
158-
}
159-
});
160-
})
161-
.then(() => {
162-
// 3) If we're in `elementExplorer` mode, run only that.
163-
if (config.elementExplorer || config.framework === 'explorer') {
164-
if (config.multiCapabilities.length != 1) {
165-
throw new Error('Must specify only 1 browser while using elementExplorer');
166-
} else {
167-
config.capabilities = config.multiCapabilities[0];
168-
}
169-
config.framework = 'explorer';
125+
// 2) Set `multicapabilities` using `capabilities`,
126+
// `multicapabilities`, or default
127+
if (config.capabilities) {
128+
if (config.multiCapabilities.length) {
129+
logger.warn(
130+
'You have specified both capabilities and ' +
131+
'multiCapabilities. This will result in capabilities being ' +
132+
'ignored');
133+
} else {
134+
// Use capabilities if multiCapabilities is empty.
135+
config.multiCapabilities = [config.capabilities];
136+
}
137+
} else if (!config.multiCapabilities.length) {
138+
// Default to chrome if no capabilities given
139+
config.multiCapabilities = [{browserName: 'chrome'}];
140+
}
170141

171-
let runner = new Runner(config);
172-
return runner.run().then(
173-
(exitCode: number) => {
174-
process.exit(exitCode);
175-
},
176-
(err: Error) => {
177-
logger.error(err);
178-
process.exit(1);
179-
});
180-
}
181-
})
182-
.then(() => {
183-
// 4) Run tests.
184-
let scheduler = new TaskScheduler(config);
142+
// 3) If we're in `elementExplorer` mode, throw an error and exit.
143+
if (config.elementExplorer || config.framework === 'explorer') {
144+
const err = new Error(
145+
'Deprecated: Element explorer depends on the ' +
146+
'WebDriver control flow, and thus is no longer supported.');
147+
logger.error(err);
148+
process.exit(1);
149+
}
185150

186-
process.on('uncaughtException', (exc: (Error|string)) => {
187-
let e = (exc instanceof Error) ? exc : new Error(exc);
188-
if (config.ignoreUncaughtExceptions) {
189-
// This can be a sign of a bug in the test framework, that it may
190-
// not be handling WebDriver errors properly. However, we don't
191-
// want these errors to prevent running the tests.
192-
logger.warn('Ignoring uncaught error ' + exc);
193-
return;
194-
}
151+
// 4) Run tests.
152+
let scheduler = new TaskScheduler(config);
195153

196-
let errorCode = ErrorHandler.parseError(e);
197-
if (errorCode) {
198-
let protractorError = e as ProtractorError;
199-
ProtractorError.log(logger, errorCode, protractorError.message, protractorError.stack);
200-
process.exit(errorCode);
201-
} else {
202-
logger.error(e.message);
203-
logger.error(e.stack);
204-
process.exit(ProtractorError.CODE);
205-
}
206-
});
154+
process.on('uncaughtException', (exc: (Error|string)) => {
155+
let e = (exc instanceof Error) ? exc : new Error(exc);
156+
if (config.ignoreUncaughtExceptions) {
157+
// This can be a sign of a bug in the test framework, that it may
158+
// not be handling WebDriver errors properly. However, we don't
159+
// want these errors to prevent running the tests.
160+
logger.warn('Ignoring uncaught error ' + exc);
161+
return;
162+
}
163+
logger.error(e.message);
164+
logger.error(e.stack);
165+
if (e instanceof ProtractorError) {
166+
let protractorError = e as ProtractorError;
167+
process.exit(protractorError.code);
168+
} else {
169+
process.exit(1);
170+
}
171+
});
207172

208-
process.on('exit', (code: number) => {
209-
if (code) {
210-
logger.error('Process exited with error code ' + code);
211-
} else if (scheduler.numTasksOutstanding() > 0) {
212-
logger.error(
213-
'BUG: launcher exited with ' + scheduler.numTasksOutstanding() +
214-
' tasks remaining');
215-
process.exit(RUNNERS_FAILED_EXIT_CODE);
216-
}
217-
});
173+
process.on('unhandledRejection', (reason: Error | any, p: Promise<any>) => {
174+
logger.warn('Unhandled rejection at:', p, 'reason:', reason);
175+
});
218176

219-
// Run afterlaunch and exit
220-
let cleanUpAndExit = (exitCode: number) => {
221-
return helper.runFilenameOrFn_(config.configDir, config.afterLaunch, [exitCode])
222-
.then(
223-
(returned) => {
224-
if (typeof returned === 'number') {
225-
process.exit(returned);
226-
} else {
227-
process.exit(exitCode);
228-
}
229-
},
230-
(err: Error) => {
231-
logger.error('Error:', err);
232-
process.exit(1);
233-
});
234-
};
177+
process.on('exit', (code: number) => {
178+
if (code) {
179+
logger.error('Process exited with error code ' + code);
180+
} else if (scheduler.numTasksOutstanding() > 0) {
181+
logger.error(
182+
'BUG: launcher exited with ' + scheduler.numTasksOutstanding() + ' tasks remaining');
183+
process.exit(RUNNERS_FAILED_EXIT_CODE);
184+
}
185+
});
235186

236-
let totalTasks = scheduler.numTasksOutstanding();
237-
let forkProcess = false;
238-
if (totalTasks > 1) { // Start new processes only if there are >1 tasks.
239-
forkProcess = true;
240-
if (config.debug) {
241-
throw new ConfigError(
242-
logger, 'Cannot run in debug mode with multiCapabilities, count > 1, or sharding');
243-
}
244-
}
187+
// Run afterlaunch and exit
188+
const cleanUpAndExit = async (exitCode: number) => {
189+
try {
190+
const returned = await runFilenameOrFn_(config.configDir, config.afterLaunch, [exitCode]);
191+
if (typeof returned === 'number') {
192+
process.exit(returned);
193+
} else {
194+
process.exit(exitCode);
195+
}
196+
} catch (err) {
197+
logger.error('Error:', err);
198+
process.exit(1);
199+
}
200+
};
245201

246-
let deferred = q.defer<any>(); // Resolved when all tasks are completed
247-
let createNextTaskRunner = () => {
248-
let task = scheduler.nextTask();
249-
if (task) {
250-
let taskRunner = new TaskRunner(configFile, additionalConfig, task, forkProcess);
251-
taskRunner.run()
252-
.then((result) => {
253-
if (result.exitCode && !result.failedCount) {
254-
logger.error(
255-
'Runner process exited unexpectedly with error code: ' + result.exitCode);
256-
}
257-
taskResults_.add(result);
258-
task.done();
259-
createNextTaskRunner();
260-
// If all tasks are finished
261-
if (scheduler.numTasksOutstanding() === 0) {
262-
deferred.resolve();
263-
}
264-
logger.info(
265-
scheduler.countActiveTasks() + ' instance(s) of WebDriver still running');
266-
})
267-
.catch((err: Error) => {
268-
logger.error('Error:', (err as any).stack || err.message || err);
269-
cleanUpAndExit(RUNNERS_FAILED_EXIT_CODE);
270-
});
202+
const totalTasks = scheduler.numTasksOutstanding();
203+
let forkProcess = false;
204+
if (totalTasks > 1) { // Start new processes only if there are >1 tasks.
205+
forkProcess = true;
206+
if (config.debug) {
207+
throw new ConfigError(
208+
logger, 'Cannot run in debug mode with multiCapabilities, count > 1, or sharding');
209+
}
210+
}
211+
212+
const createNextTaskRunner = async () => {
213+
return new Promise(async (resolve) => {
214+
const task = scheduler.nextTask();
215+
if (task) {
216+
const taskRunner = new TaskRunner(configFile, additionalConfig, task, forkProcess);
217+
try {
218+
const result = await taskRunner.run();
219+
if (result.exitCode && !result.failedCount) {
220+
logger.error('Runner process exited unexpectedly with error code: ' + result.exitCode);
271221
}
272-
};
273-
// Start `scheduler.maxConcurrentTasks()` workers for handling tasks in
274-
// the beginning. As a worker finishes a task, it will pick up the next
275-
// task
276-
// from the scheduler's queue until all tasks are gone.
277-
for (let i = 0; i < scheduler.maxConcurrentTasks(); ++i) {
222+
taskResults_.add(result);
223+
task.done();
278224
createNextTaskRunner();
225+
// If all tasks are finished
226+
if (scheduler.numTasksOutstanding() === 0) {
227+
resolve();
228+
}
229+
logger.info(scheduler.countActiveTasks() + ' instance(s) of WebDriver still running');
230+
} catch (err) {
231+
const errorCode = ErrorHandler.parseError(err);
232+
logger.error('Error:', (err as any).stack || err.message || err);
233+
await cleanUpAndExit(errorCode ? errorCode : RUNNERS_FAILED_EXIT_CODE);
279234
}
280-
logger.info('Running ' + scheduler.countActiveTasks() + ' instances of WebDriver');
235+
}
236+
});
237+
};
238+
239+
const maxConcurrentTasks = scheduler.maxConcurrentTasks();
240+
for (let i = 0; i < maxConcurrentTasks; ++i) {
241+
await createNextTaskRunner();
242+
}
243+
logger.info('Running ' + scheduler.countActiveTasks() + ' instances of WebDriver');
281244

282-
// By now all runners have completed.
283-
deferred.promise
284-
.then(function() {
285-
// Save results if desired
286-
if (config.resultJsonOutputFile) {
287-
taskResults_.saveResults(config.resultJsonOutputFile);
288-
}
245+
// By now all runners have completed.
246+
// Save results if desired
247+
if (config.resultJsonOutputFile) {
248+
taskResults_.saveResults(config.resultJsonOutputFile);
249+
}
250+
251+
taskResults_.reportSummary();
252+
let exitCode = 0;
253+
if (taskResults_.totalProcessFailures() > 0) {
254+
exitCode = RUNNERS_FAILED_EXIT_CODE;
255+
} else if (taskResults_.totalSpecFailures() > 0) {
256+
exitCode = 1;
257+
}
258+
await cleanUpAndExit(exitCode);
259+
// Start `const maxConcurrentTasks` workers for handling tasks in
260+
// the beginning. As a worker finishes a task, it will pick up the next
261+
// task from the scheduler's queue until all tasks are gone.
289262

290-
taskResults_.reportSummary();
291-
let exitCode = 0;
292-
if (taskResults_.totalProcessFailures() > 0) {
293-
exitCode = RUNNERS_FAILED_EXIT_CODE;
294-
} else if (taskResults_.totalSpecFailures() > 0) {
295-
exitCode = 1;
296-
}
297-
return cleanUpAndExit(exitCode);
298-
})
299-
.done();
300-
})
301-
.done();
302263
};
303264

304265
export let init = initFn;

0 commit comments

Comments
 (0)