blob: 8f84f3cdb23c32500b9ce55f9fab9dda4169c01a [file] [log] [blame]
"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