108 lines
No EOL
3.9 KiB
JavaScript
Executable file
108 lines
No EOL
3.9 KiB
JavaScript
Executable file
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const webdriver_logger_1 = require("./webdriver_logger");
|
|
const angularWaits = require('./client_scripts/wait.js');
|
|
/**
|
|
* A barrier that uses Angular's Testability API to block commands until the application is stable.
|
|
*/
|
|
class AngularWaitBarrier {
|
|
constructor(client) {
|
|
this.client = client;
|
|
this.enabled = true;
|
|
this.rootSelector = '';
|
|
}
|
|
/**
|
|
* A CSS Selector for a DOM element within your Angular application.
|
|
* BlockingProxy will attempt to automatically find your application, but it is
|
|
* necessary to set rootElement in certain cases.
|
|
*
|
|
* In Angular 1, BlockingProxy will use the element your app bootstrapped to by
|
|
* default. If that doesn't work, it will then search for hooks in `body` or
|
|
* `ng-app` elements (details here: https://git.io/v1b2r).
|
|
*
|
|
* In later versions of Angular, BlockingProxy will try to hook into all angular
|
|
* apps on the page. Use rootElement to limit the scope of which apps
|
|
* BlockingProxy waits for and searches within.
|
|
*
|
|
* @param rootSelector A selector for the root element of the Angular app.
|
|
*/
|
|
setRootSelector(selector) {
|
|
this.rootSelector = selector;
|
|
}
|
|
waitForAngularData() {
|
|
return JSON.stringify({
|
|
script: 'return (' + angularWaits.NG_WAIT_FN + ').apply(null, arguments);',
|
|
args: [this.rootSelector]
|
|
});
|
|
}
|
|
/**
|
|
* Turn on WebDriver logging.
|
|
*
|
|
* @param logDir The directory to create logs in.
|
|
*/
|
|
enableLogging(logDir) {
|
|
if (!this.logger) {
|
|
this.logger = new webdriver_logger_1.WebDriverLogger();
|
|
}
|
|
this.logger.setLogDir(logDir);
|
|
}
|
|
/**
|
|
* Override the logger instance. Only used for testing.
|
|
*/
|
|
setLogger(logger) {
|
|
this.logger = logger;
|
|
}
|
|
sendRequestToStabilize(command) {
|
|
return this.client.executeAsync(command.sessionId, this.waitForAngularData()).then((value) => {
|
|
// waitForAngular only returns a value if there was an error
|
|
// in the browser.
|
|
if (value) {
|
|
throw new Error('Error from waitForAngular: ' + value);
|
|
}
|
|
});
|
|
}
|
|
shouldStabilize(command) {
|
|
const url = command.url;
|
|
if (!this.enabled) {
|
|
return false;
|
|
}
|
|
// TODO - should this implement some state, and be smart about whether
|
|
// stabilization is necessary or not? Would that be as simple as GET/POST?
|
|
// e.g. two gets in a row don't require a wait btwn.
|
|
//
|
|
// See https://code.google.com/p/selenium/wiki/JsonWireProtocol for
|
|
// descriptions of the paths.
|
|
// We shouldn't stabilize if we haven't loaded the page yet.
|
|
const parts = url.split('/');
|
|
if (parts.length < 4) {
|
|
return false;
|
|
}
|
|
const commandsToWaitFor = [
|
|
'executeScript', 'screenshot', 'source', 'title', 'element', 'elements', 'execute', 'keys',
|
|
'moveto', 'click', 'buttondown', 'buttonup', 'doubleclick', 'touch', 'get'
|
|
];
|
|
if (commandsToWaitFor.indexOf(parts[3]) != -1) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
onCommand(command) {
|
|
if (this.logger) {
|
|
command.on('data', () => {
|
|
this.logger.logWebDriverCommand(command);
|
|
});
|
|
}
|
|
if (this.shouldStabilize(command)) {
|
|
const started = Date.now();
|
|
return this.sendRequestToStabilize(command).then(() => {
|
|
const ended = Date.now();
|
|
if (this.logger) {
|
|
this.logger.logEvent('Waiting for Angular', command.sessionId, (ended - started));
|
|
}
|
|
});
|
|
}
|
|
return Promise.resolve(null);
|
|
}
|
|
}
|
|
exports.AngularWaitBarrier = AngularWaitBarrier;
|
|
//# sourceMappingURL=angular_wait_barrier.js.map
|