diff --git a/docs/faq.md b/docs/faq.md index 0032c2118..9d7a5ea7d 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -193,7 +193,7 @@ You may need to insert a `browser.wait` condition to make sure the load is complete before continuing. How do I switch off an option in the CLI? ------------------------------------------------------------------------------- +----------------------------------------- i.e. `webdriver-manager update --chrome=false` does not work. This has to do with the way `optimist` parses command line args. In order to pass a false value, do one of the following: @@ -201,6 +201,12 @@ This has to do with the way `optimist` parses command line args. In order to pas 2) `webdriver-manager update --no-chrome` (see https://github.com/substack/node-optimist#negate-fields) +Why does Protractor fail when I decorate $timeout? +-------------------------------------------------- +Protractor tracks outstanding $timeouts by default, and reports them in the error message if Protractor fails to synchronize with Angular in time. + +However, in order to do this Protractor needs to decorate $timeout. This means if your app decorates $timeout, you must turn off this behavior for Protractor. To do so pass in the 'untrackOutstandingTimeouts' flag. + I still have a question ----------------------- diff --git a/docs/referenceConf.js b/docs/referenceConf.js index 2376f44b4..9ae715333 100644 --- a/docs/referenceConf.js +++ b/docs/referenceConf.js @@ -250,6 +250,13 @@ exports.config = { // CAUTION: This will cause your tests to slow down drastically. restartBrowserBetweenTests: false, + // Protractor will track outstanding $timeouts by default, and report them in + // the error message if Protractor fails to synchronize with Angular in time. + // In order to do this Protractor needs to decorate $timeout. + // CAUTION: If your app decorates $timeout, you must turn on this flag. This + // is false by default. + untrackOutstandingTimeouts: false, + // --------------------------------------------------------------------------- // ----- The test framework -------------------------------------------------- // --------------------------------------------------------------------------- diff --git a/lib/protractor.js b/lib/protractor.js index f8995068e..040e61e00 100644 --- a/lib/protractor.js +++ b/lib/protractor.js @@ -93,8 +93,11 @@ var buildElementHelper = function(ptor) { * @param {string=} opt_baseUrl A base URL to run get requests against. * @param {string=} opt_rootElement Selector element that has an ng-app in * scope. + * @param {boolean=} opt_untrackOutstandingTimeouts Whether Protractor should + * stop tracking outstanding $timeouts. */ -var Protractor = function(webdriverInstance, opt_baseUrl, opt_rootElement) { +var Protractor = function(webdriverInstance, opt_baseUrl, opt_rootElement, + opt_untrackOutstandingTimeouts) { // These functions should delegate to the webdriver instance, but should // wait for Angular to sync up before performing the action. This does not // include functions which are overridden by protractor below. @@ -216,6 +219,13 @@ var Protractor = function(webdriverInstance, opt_baseUrl, opt_rootElement) { } }); + /** + * If true, Protractor will track outstanding $timeouts and report them in the + * error message if Protractor fails to synchronize with Angular in time. + * @private {boolean} + */ + this.trackOutstandingTimeouts_ = !opt_untrackOutstandingTimeouts; + /** * Information about mock modules that will be installed during every * get(). @@ -382,10 +392,15 @@ Protractor.prototype.waitForAngular = function(opt_description) { var errMsg = 'Timed out waiting for Protractor to synchronize with ' + 'the page after ' + timeout + '. Please see ' + 'https://github.com/angular/protractor/blob/master/docs/faq.md'; - var pendingTimeoutsPromise = self.executeScript_( - 'return window.NG_PENDING_TIMEOUTS', - 'Protractor.waitForAngular() - getting pending timeouts' + description - ); + var pendingTimeoutsPromise; + if (self.trackOutstandingTimeouts_) { + pendingTimeoutsPromise = self.executeScript_( + 'return window.NG_PENDING_TIMEOUTS', + 'Protractor.waitForAngular() - getting pending timeouts' + description + ); + } else { + pendingTimeoutsPromise = webdriver.promise.fulfilled({}); + } var pendingHttpsPromise = self.executeScript_( clientSideScripts.getPendingHttpRequests, 'Protractor.waitForAngular() - getting pending https' + description, @@ -518,14 +533,15 @@ Protractor.prototype.getRegisteredMockModules = function() { * @private */ Protractor.prototype.addBaseMockModules_ = function() { - this.addMockModule('protractorBaseModule_', function() { - angular.module('protractorBaseModule_', []). + this.addMockModule('protractorBaseModule_', function(trackOutstandingTimeouts) { + var ngMod = angular.module('protractorBaseModule_', []). config(['$compileProvider', function($compileProvider) { if ($compileProvider.debugInfoEnabled) { $compileProvider.debugInfoEnabled(true); } - }]). - config(['$provide', function($provide) { + }]); + if (trackOutstandingTimeouts) { + ngMod.config(['$provide', function($provide) { $provide.decorator('$timeout', ['$delegate', function($delegate) { var $timeout = $delegate; @@ -567,7 +583,8 @@ Protractor.prototype.addBaseMockModules_ = function() { return extendedTimeout; }]); }]); - }); + } + }, this.trackOutstandingTimeouts_); }; /** @@ -1041,8 +1058,12 @@ Protractor.prototype.pause = function(opt_debugPort) { * * @param {webdriver.WebDriver} webdriver The configured webdriver instance. * @param {string=} opt_baseUrl A URL to prepend to relative gets. + * @param {boolean=} opt_untrackOutstandingTimeouts Whether Protractor should + * stop tracking outstanding $timeouts. * @return {Protractor} */ -exports.wrapDriver = function(webdriver, opt_baseUrl, opt_rootElement) { - return new Protractor(webdriver, opt_baseUrl, opt_rootElement); +exports.wrapDriver = function(webdriver, opt_baseUrl, opt_rootElement, + opt_untrackOutstandingTimeouts) { + return new Protractor(webdriver, opt_baseUrl, opt_rootElement, + opt_untrackOutstandingTimeouts); }; diff --git a/lib/runner.js b/lib/runner.js index ece9bd56e..9934e962d 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -182,7 +182,7 @@ Runner.prototype.createBrowser = function(plugins) { var driver = this.driverprovider_.getNewDriver(); var browser_ = protractor.wrapDriver(driver, - config.baseUrl, config.rootElement); + config.baseUrl, config.rootElement, config.untrackOutstandingTimeouts); browser_.params = config.params; if (plugins) { @@ -202,7 +202,6 @@ Runner.prototype.createBrowser = function(plugins) { } var self = this; - browser_.ready = driver.manage().timeouts().setScriptTimeout(config.allScriptsTimeout); diff --git a/scripts/test.js b/scripts/test.js index 38cc1d0a1..a1cdb0424 100755 --- a/scripts/test.js +++ b/scripts/test.js @@ -130,6 +130,14 @@ executor.addCommandlineTest('node lib/cli.js spec/errorTest/slowHttpAndTimeoutCo '*}'} ]); +executor.addCommandlineTest('node lib/cli.js spec/errorTest/slowHttpAndTimeoutConf.js ' + + '--untrackOutstandingTimeouts true') + .expectExitCode(1) + .expectErrors([ + {message: 'The following tasks were pending[\\s\\S]*\\$http: \/slowcall'}, + {message: '^((?!The following tasks were pending).)*$'} + ]); + // Check ngHint plugin executor.addCommandlineTest(