"use strict"; 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