123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- const blocking_proxy_1 = require("blocking-proxy");
- const selenium_webdriver_1 = require("selenium-webdriver");
- const url = require("url");
- const webdriver_js_extender_1 = require("webdriver-js-extender");
- const element_1 = require("./element");
- const expectedConditions_1 = require("./expectedConditions");
- const locators_1 = require("./locators");
- const logger_1 = require("./logger");
- const clientSideScripts = require('./clientsidescripts');
- // TODO: fix the typings for selenium-webdriver/lib/command
- const Command = require('selenium-webdriver/lib/command').Command;
- const CommandName = require('selenium-webdriver/lib/command').Name;
- // jshint browser: true
- const DEFER_LABEL = 'NG_DEFER_BOOTSTRAP!';
- const DEFAULT_RESET_URL = 'data:text/html,<html></html>';
- const DEFAULT_GET_PAGE_TIMEOUT = 10000;
- let logger = new logger_1.Logger('protractor');
- // TODO(cnishina): either remove for loop entirely since this does not export anything
- // the user might need since everything is composed (with caveat that this could be a
- // potential breaking change) or export the types with `export * from 'selenium-webdriver'`;
- /*
- * Mix in other webdriver functionality to be accessible via protractor.
- */
- for (let foo in require('selenium-webdriver')) {
- exports[foo] = require('selenium-webdriver')[foo];
- }
- // Explicitly define types for webdriver.WebDriver and ExtendedWebDriver.
- // We do this because we use composition over inheritance to implement polymorphism, and therefore
- // we don't want to inherit WebDriver's constructor.
- class AbstractWebDriver {
- }
- exports.AbstractWebDriver = AbstractWebDriver;
- class AbstractExtendedWebDriver extends AbstractWebDriver {
- }
- exports.AbstractExtendedWebDriver = AbstractExtendedWebDriver;
- /**
- * Mix a function from one object onto another. The function will still be
- * called in the context of the original object. Any arguments of type
- * `ElementFinder` will be unwrapped to their underlying `WebElement` instance
- *
- * @private
- * @param {Object} to
- * @param {Object} from
- * @param {string} fnName
- * @param {function=} setupFn
- */
- function ptorMixin(to, from, fnName, setupFn) {
- to[fnName] = function () {
- const args = arguments;
- for (let i = 0; i < args.length; i++) {
- if (args[i] instanceof element_1.ElementFinder) {
- args[i] = args[i].getWebElement();
- }
- }
- const run = () => {
- return from[fnName].apply(from, args);
- };
- if (setupFn) {
- const setupResult = setupFn();
- if (setupResult && (typeof setupResult.then === 'function')) {
- return setupResult.then(run);
- }
- }
- return run();
- };
- }
- ;
- /**
- * Build the helper 'element' function for a given instance of Browser.
- *
- * @private
- * @param {Browser} browser A browser instance.
- * @returns {function(webdriver.Locator): ElementFinder}
- */
- function buildElementHelper(browser) {
- let element = ((locator) => {
- return new element_1.ElementArrayFinder(browser).all(locator).toElementFinder_();
- });
- element.all = (locator) => {
- return new element_1.ElementArrayFinder(browser).all(locator);
- };
- return element;
- }
- ;
- /**
- * @alias browser
- * @constructor
- * @extends {webdriver_extensions.ExtendedWebDriver}
- * @param {webdriver.WebDriver} webdriver
- * @param {string=} opt_baseUrl A base URL to run get requests against.
- * @param {string|webdriver.promise.Promise<string>=} opt_rootElement Selector element that has an
- * ng-app in scope.
- * @param {boolean=} opt_untrackOutstandingTimeouts Whether Protractor should
- * stop tracking outstanding $timeouts.
- */
- class ProtractorBrowser extends AbstractExtendedWebDriver {
- constructor(webdriverInstance, opt_baseUrl, opt_rootElement, opt_untrackOutstandingTimeouts, opt_blockingProxyUrl) {
- super();
- // 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.
- let methodsToSync = ['getCurrentUrl', 'getPageSource', 'getTitle'];
- let extendWDInstance;
- try {
- extendWDInstance = webdriver_js_extender_1.extend(webdriverInstance);
- }
- catch (e) {
- // Probably not a driver that can be extended (e.g. gotten using
- // `directConnect: true` in the config)
- extendWDInstance = webdriverInstance;
- }
- // Mix all other driver functionality into Protractor.
- Object.getOwnPropertyNames(selenium_webdriver_1.WebDriver.prototype).forEach(method => {
- if (!this[method] && typeof extendWDInstance[method] === 'function') {
- if (methodsToSync.indexOf(method) !== -1) {
- ptorMixin(this, extendWDInstance, method, this.waitForAngular.bind(this));
- }
- else {
- ptorMixin(this, extendWDInstance, method);
- }
- }
- });
- this.driver = extendWDInstance;
- if (opt_blockingProxyUrl) {
- logger.info('Starting BP client for ' + opt_blockingProxyUrl);
- this.bpClient = new blocking_proxy_1.BPClient(opt_blockingProxyUrl);
- }
- this.element = buildElementHelper(this);
- this.$ = element_1.build$(this.element, selenium_webdriver_1.By);
- this.$$ = element_1.build$$(this.element, selenium_webdriver_1.By);
- this.baseUrl = opt_baseUrl || '';
- this.getPageTimeout = DEFAULT_GET_PAGE_TIMEOUT;
- this.params = {};
- this.resetUrl = DEFAULT_RESET_URL;
- let ng12Hybrid_ = false;
- Object.defineProperty(this, 'ng12Hybrid', {
- get: function () {
- return ng12Hybrid_;
- },
- set: function (ng12Hybrid) {
- if (ng12Hybrid) {
- logger.warn('You have set ng12Hybrid. As of Protractor 4.1.0, ' +
- 'Protractor can automatically infer if you are using an ' +
- 'ngUpgrade app (as long as ng1 is loaded before you call ' +
- 'platformBrowserDynamic()), and this flag is no longer needed ' +
- 'for most users');
- }
- ng12Hybrid_ = ng12Hybrid;
- }
- });
- this.ready = this.angularAppRoot(opt_rootElement || '')
- .then(() => {
- return this.driver.getSession();
- })
- .then((session) => {
- // Internet Explorer does not accept data URLs, which are the default
- // reset URL for Protractor.
- // Safari accepts data urls, but SafariDriver fails after one is used.
- // PhantomJS produces a "Detected a page unload event" if we use data urls
- let browserName = session.getCapabilities().get('browserName');
- if (browserName === 'internet explorer' || browserName === 'safari' ||
- browserName === 'phantomjs' || browserName === 'MicrosoftEdge') {
- this.resetUrl = 'about:blank';
- }
- return this;
- });
- this.trackOutstandingTimeouts_ = !opt_untrackOutstandingTimeouts;
- this.mockModules_ = [];
- this.addBaseMockModules_();
- // set up expected conditions
- this.ExpectedConditions = new expectedConditions_1.ProtractorExpectedConditions(this);
- }
- /**
- * The css selector for an element on which to find Angular. This is usually
- * 'body' but if your ng-app is on a subsection of the page it may be
- * a subelement.
- *
- * This property is deprecated - please use angularAppRoot() instead.
- *
- * @deprecated
- * @type {string}
- */
- set rootEl(value) {
- this.angularAppRoot(value);
- }
- get rootEl() {
- return this.internalRootEl;
- }
- /**
- * Set the css selector for an element on which to find Angular. This is usually
- * 'body' but if your ng-app is on a subsection of the page it may be
- * a subelement.
- *
- * The change will be made within WebDriver's control flow, so that commands after
- * this method is called use the new app root. Pass nothing to get a promise that
- * resolves to the value of the selector.
- *
- * @param {string|webdriver.promise.Promise<string>} value The new selector.
- * @returns A promise that resolves with the value of the selector.
- */
- angularAppRoot(value = null) {
- return this.driver.controlFlow().execute(() => {
- if (value != null) {
- return selenium_webdriver_1.promise.when(value).then((value) => {
- this.internalRootEl = value;
- if (this.bpClient) {
- const bpCommandPromise = this.bpClient.setWaitParams(value);
- // Convert to webdriver promise as best as possible
- return selenium_webdriver_1.promise.when(bpCommandPromise).then(() => this.internalRootEl);
- }
- return this.internalRootEl;
- });
- }
- return selenium_webdriver_1.promise.when(this.internalRootEl);
- }, `Set angular root selector to ${value}`);
- }
- /**
- * If true, Protractor will not attempt to synchronize with the page before
- * performing actions. This can be harmful because Protractor will not wait
- * until $timeouts and $http calls have been processed, which can cause
- * tests to become flaky. This should be used only when necessary, such as
- * when a page continuously polls an API using $timeout.
- *
- * Initialized to `false` by the runner.
- *
- * This property is deprecated - please use waitForAngularEnabled instead.
- *
- * @deprecated
- * @type {boolean}
- */
- set ignoreSynchronization(value) {
- this.waitForAngularEnabled(!value);
- }
- get ignoreSynchronization() {
- return this.internalIgnoreSynchronization;
- }
- /**
- * If set to false, Protractor will not wait for Angular $http and $timeout
- * tasks to complete before interacting with the browser. This can cause
- * flaky tests, but should be used if, for instance, your app continuously
- * polls an API with $timeout.
- *
- * Call waitForAngularEnabled() without passing a value to read the current
- * state without changing it.
- */
- waitForAngularEnabled(enabled = null) {
- if (enabled != null) {
- const ret = this.driver.controlFlow().execute(() => {
- return selenium_webdriver_1.promise.when(enabled).then((enabled) => {
- if (this.bpClient) {
- logger.debug('Setting waitForAngular' + !enabled);
- const bpCommandPromise = this.bpClient.setWaitEnabled(enabled);
- // Convert to webdriver promise as best as possible
- return selenium_webdriver_1.promise.when(bpCommandPromise).then(() => enabled);
- }
- });
- }, `Set proxy synchronization enabled to ${enabled}`);
- this.internalIgnoreSynchronization = !enabled;
- return ret;
- }
- return selenium_webdriver_1.promise.when(!this.ignoreSynchronization);
- }
- /**
- * Get the processed configuration object that is currently being run. This
- * will contain the specs and capabilities properties of the current runner
- * instance.
- *
- * Set by the runner.
- *
- * @returns {webdriver.promise.Promise} A promise which resolves to the
- * capabilities object.
- */
- getProcessedConfig() {
- return null;
- }
- /**
- * Fork another instance of browser for use in interactive tests.
- *
- * @example
- * // Running with control flow enabled
- * var fork = browser.forkNewDriverInstance();
- * fork.get('page1'); // 'page1' gotten by forked browser
- *
- * // Running with control flow disabled
- * var forked = await browser.forkNewDriverInstance().ready;
- * await forked.get('page1'); // 'page1' gotten by forked browser
- *
- * @param {boolean=} useSameUrl Whether to navigate to current url on creation
- * @param {boolean=} copyMockModules Whether to apply same mock modules on creation
- * @param {boolean=} copyConfigUpdates Whether to copy over changes to `baseUrl` and similar
- * properties initialized to values in the the config. Defaults to `true`
- *
- * @returns {ProtractorBrowser} A browser instance.
- */
- forkNewDriverInstance(useSameUrl, copyMockModules, copyConfigUpdates = true) {
- return null;
- }
- /**
- * Restart the browser. This is done by closing this browser instance and creating a new one.
- * A promise resolving to the new instance is returned, and if this function was called on the
- * global `browser` instance then Protractor will automatically overwrite the global `browser`
- * variable.
- *
- * When restarting a forked browser, it is the caller's job to overwrite references to the old
- * instance.
- *
- * This function behaves slightly differently depending on if the webdriver control flow is
- * enabled. If the control flow is enabled, the global `browser` object is synchronously
- * replaced. If the control flow is disabled, the global `browser` is replaced asynchronously
- * after the old driver quits.
- *
- * Set by the runner.
- *
- * @example
- * // Running against global browser, with control flow enabled
- * browser.get('page1');
- * browser.restart();
- * browser.get('page2'); // 'page2' gotten by restarted browser
- *
- * // Running against global browser, with control flow disabled
- * await browser.get('page1');
- * await browser.restart();
- * await browser.get('page2'); // 'page2' gotten by restarted browser
- *
- * // Running against forked browsers, with the control flow enabled
- * // In this case, you may prefer `restartSync` (documented below)
- * var forked = browser.forkNewDriverInstance();
- * fork.get('page1');
- * fork.restart().then(function(fork) {
- * fork.get('page2'); // 'page2' gotten by restarted fork
- * });
- *
- * // Running against forked browsers, with the control flow disabled
- * var forked = await browser.forkNewDriverInstance().ready;
- * await fork.get('page1');
- * fork = await fork.restart();
- * await fork.get('page2'); // 'page2' gotten by restarted fork
- *
- * // Unexpected behavior can occur if you save references to the global `browser`
- * var savedBrowser = browser;
- * browser.get('foo').then(function() {
- * console.log(browser === savedBrowser); // false
- * });
- * browser.restart();
- *
- * @returns {webdriver.promise.Promise<ProtractorBrowser>} A promise resolving to the restarted
- * browser
- */
- restart() {
- return;
- }
- /**
- * Like `restart`, but instead of returning a promise resolving to the new browser instance,
- * returns the new browser instance directly. Can only be used when the control flow is enabled.
- *
- * @example
- * // Running against global browser
- * browser.get('page1');
- * browser.restartSync();
- * browser.get('page2'); // 'page2' gotten by restarted browser
- *
- * // Running against forked browsers
- * var forked = browser.forkNewDriverInstance();
- * fork.get('page1');
- * fork = fork.restartSync();
- * fork.get('page2'); // 'page2' gotten by restarted fork
- *
- * @throws {TypeError} Will throw an error if the control flow is not enabled
- * @returns {ProtractorBrowser} The restarted browser
- */
- restartSync() {
- return;
- }
- /**
- * Instead of using a single root element, search through all angular apps
- * available on the page when finding elements or waiting for stability.
- * Only compatible with Angular2.
- */
- useAllAngular2AppRoots() {
- // The empty string is an invalid css selector, so we use it to easily
- // signal to scripts to not find a root element.
- this.angularAppRoot('');
- }
- /**
- * The same as {@code webdriver.WebDriver.prototype.executeScript},
- * but with a customized description for debugging.
- *
- * @private
- * @param {!(string|Function)} script The script to execute.
- * @param {string} description A description of the command for debugging.
- * @param {...*} var_args The arguments to pass to the script.
- * @returns {!webdriver.promise.Promise.<T>} A promise that will resolve to
- * the scripts return value.
- * @template T
- */
- executeScriptWithDescription(script, description, ...scriptArgs) {
- if (typeof script === 'function') {
- script = 'return (' + script + ').apply(null, arguments);';
- }
- return this.driver.schedule(new Command(CommandName.EXECUTE_SCRIPT)
- .setParameter('script', script)
- .setParameter('args', scriptArgs), description);
- }
- /**
- * The same as {@code webdriver.WebDriver.prototype.executeAsyncScript},
- * but with a customized description for debugging.
- *
- * @private
- * @param {!(string|Function)} script The script to execute.
- * @param {string} description A description for debugging purposes.
- * @param {...*} var_args The arguments to pass to the script.
- * @returns {!webdriver.promise.Promise.<T>} A promise that will resolve to
- * the
- * scripts return value.
- * @template T
- */
- executeAsyncScript_(script, description, ...scriptArgs) {
- if (typeof script === 'function') {
- script = 'return (' + script + ').apply(null, arguments);';
- }
- return this.driver.schedule(new Command(CommandName.EXECUTE_ASYNC_SCRIPT)
- .setParameter('script', script)
- .setParameter('args', scriptArgs), description);
- }
- /**
- * Instruct webdriver to wait until Angular has finished rendering and has
- * no outstanding $http or $timeout calls before continuing.
- * Note that Protractor automatically applies this command before every
- * WebDriver action.
- *
- * @param {string=} opt_description An optional description to be added
- * to webdriver logs.
- * @returns {!webdriver.promise.Promise} A promise that will resolve to the
- * scripts return value.
- */
- waitForAngular(opt_description) {
- let description = opt_description ? ' - ' + opt_description : '';
- if (this.ignoreSynchronization) {
- return this.driver.controlFlow().execute(() => {
- return true;
- }, 'Ignore Synchronization Protractor.waitForAngular()');
- }
- let runWaitForAngularScript = () => {
- if (this.plugins_.skipAngularStability() || this.bpClient) {
- return this.driver.controlFlow().execute(() => {
- return selenium_webdriver_1.promise.when(null);
- }, 'bpClient or plugin stability override');
- }
- else {
- // Need to wrap this so that we read rootEl in the control flow, not synchronously.
- return this.angularAppRoot().then((rootEl) => {
- return this.executeAsyncScript_(clientSideScripts.waitForAngular, 'Protractor.waitForAngular()' + description, rootEl);
- });
- }
- };
- return runWaitForAngularScript()
- .then((browserErr) => {
- if (browserErr) {
- throw new Error('Error while waiting for Protractor to ' +
- 'sync with the page: ' + JSON.stringify(browserErr));
- }
- })
- .then(() => {
- return this.driver.controlFlow()
- .execute(() => {
- return this.plugins_.waitForPromise(this);
- }, 'Plugins.waitForPromise()')
- .then(() => {
- return this.driver.wait(() => {
- return this.plugins_.waitForCondition(this).then((results) => {
- return results.reduce((x, y) => x && y, true);
- });
- }, this.allScriptsTimeout, 'Plugins.waitForCondition()');
- });
- }, (err) => {
- let timeout;
- if (/asynchronous script timeout/.test(err.message)) {
- // Timeout on Chrome
- timeout = /-?[\d\.]*\ seconds/.exec(err.message);
- }
- else if (/Timed out waiting for async script/.test(err.message)) {
- // Timeout on Firefox
- timeout = /-?[\d\.]*ms/.exec(err.message);
- }
- else if (/Timed out waiting for an asynchronous script/.test(err.message)) {
- // Timeout on Safari
- timeout = /-?[\d\.]*\ ms/.exec(err.message);
- }
- if (timeout) {
- let errMsg = `Timed out waiting for asynchronous Angular tasks to finish after ` +
- `${timeout}. This may be because the current page is not an Angular ` +
- `application. Please see the FAQ for more details: ` +
- `https://github.com/angular/protractor/blob/master/docs/timeouts.md#waiting-for-angular`;
- if (description.indexOf(' - Locator: ') == 0) {
- errMsg += '\nWhile waiting for element with locator' + description;
- }
- let pendingTimeoutsPromise;
- if (this.trackOutstandingTimeouts_) {
- pendingTimeoutsPromise = this.executeScriptWithDescription('return window.NG_PENDING_TIMEOUTS', 'Protractor.waitForAngular() - getting pending timeouts' + description);
- }
- else {
- pendingTimeoutsPromise = selenium_webdriver_1.promise.when({});
- }
- let pendingHttpsPromise = this.executeScriptWithDescription(clientSideScripts.getPendingHttpRequests, 'Protractor.waitForAngular() - getting pending https' + description, this.internalRootEl);
- return selenium_webdriver_1.promise.all([pendingTimeoutsPromise, pendingHttpsPromise])
- .then((arr) => {
- let pendingTimeouts = arr[0] || [];
- let pendingHttps = arr[1] || [];
- let key, pendingTasks = [];
- for (key in pendingTimeouts) {
- if (pendingTimeouts.hasOwnProperty(key)) {
- pendingTasks.push(' - $timeout: ' + pendingTimeouts[key]);
- }
- }
- for (key in pendingHttps) {
- pendingTasks.push(' - $http: ' + pendingHttps[key].url);
- }
- if (pendingTasks.length) {
- errMsg += '. \nThe following tasks were pending:\n';
- errMsg += pendingTasks.join('\n');
- }
- err.message = errMsg;
- throw err;
- }, () => {
- err.message = errMsg;
- throw err;
- });
- }
- else {
- throw err;
- }
- });
- }
- /**
- * Waits for Angular to finish rendering before searching for elements.
- * @see webdriver.WebDriver.findElement
- * @returns {!webdriver.WebElementPromise} A promise that will be resolved to
- * the located {@link webdriver.WebElement}.
- */
- findElement(locator) {
- return this.element(locator).getWebElement();
- }
- /**
- * Waits for Angular to finish rendering before searching for elements.
- * @see webdriver.WebDriver.findElements
- * @returns {!webdriver.promise.Promise} A promise that will be resolved to an
- * array of the located {@link webdriver.WebElement}s.
- */
- findElements(locator) {
- return this.element.all(locator).getWebElements();
- }
- /**
- * Tests if an element is present on the page.
- * @see webdriver.WebDriver.isElementPresent
- * @returns {!webdriver.promise.Promise} A promise that will resolve to whether
- * the element is present on the page.
- */
- isElementPresent(locatorOrElement) {
- let element;
- if (locatorOrElement instanceof element_1.ElementFinder) {
- element = locatorOrElement;
- }
- else if (locatorOrElement instanceof selenium_webdriver_1.WebElement) {
- element = element_1.ElementFinder.fromWebElement_(this, locatorOrElement);
- }
- else {
- element = this.element(locatorOrElement);
- }
- return element.isPresent();
- }
- /**
- * Add a module to load before Angular whenever Protractor.get is called.
- * Modules will be registered after existing modules already on the page,
- * so any module registered here will override preexisting modules with the
- * same name.
- *
- * @example
- * browser.addMockModule('modName', function() {
- * angular.module('modName', []).value('foo', 'bar');
- * });
- *
- * @param {!string} name The name of the module to load or override.
- * @param {!string|Function} script The JavaScript to load the module.
- * Note that this will be executed in the browser context, so it cannot
- * access variables from outside its scope.
- * @param {...*} varArgs Any additional arguments will be provided to
- * the script and may be referenced using the `arguments` object.
- */
- addMockModule(name, script, ...moduleArgs) {
- this.mockModules_.push({ name: name, script: script, args: moduleArgs });
- }
- /**
- * Clear the list of registered mock modules.
- */
- clearMockModules() {
- this.mockModules_ = [];
- this.addBaseMockModules_();
- }
- /**
- * Remove a registered mock module.
- *
- * @example
- * browser.removeMockModule('modName');
- *
- * @param {!string} name The name of the module to remove.
- */
- removeMockModule(name) {
- for (let i = 0; i < this.mockModules_.length; ++i) {
- if (this.mockModules_[i].name == name) {
- this.mockModules_.splice(i--, 1);
- }
- }
- }
- /**
- * Get a list of the current mock modules.
- *
- * @returns {Array.<!string|Function>} The list of mock modules.
- */
- getRegisteredMockModules() {
- return this.mockModules_.map(module => module.script);
- }
- ;
- /**
- * Add the base mock modules used for all Protractor tests.
- *
- * @private
- */
- addBaseMockModules_() {
- this.addMockModule('protractorBaseModule_', clientSideScripts.protractorBaseModuleFn, this.trackOutstandingTimeouts_);
- }
- /**
- * @see webdriver.WebDriver.get
- *
- * Navigate to the given destination and loads mock modules before
- * Angular. Assumes that the page being loaded uses Angular.
- * If you need to access a page which does not have Angular on load, use
- * the wrapped webdriver directly.
- *
- * @example
- * browser.get('https://angularjs.org/');
- * expect(browser.getCurrentUrl()).toBe('https://angularjs.org/');
- *
- * @param {string} destination Destination URL.
- * @param {number=} opt_timeout Number of milliseconds to wait for Angular to
- * start.
- */
- get(destination, timeout = this.getPageTimeout) {
- destination = this.baseUrl.indexOf('file://') === 0 ? this.baseUrl + destination :
- url.resolve(this.baseUrl, destination);
- if (this.ignoreSynchronization) {
- return this.driver.get(destination)
- .then(() => this.driver.controlFlow().execute(() => this.plugins_.onPageLoad(this)))
- .then(() => null);
- }
- let msg = (str) => {
- return 'Protractor.get(' + destination + ') - ' + str;
- };
- return this.driver.controlFlow()
- .execute(() => {
- return selenium_webdriver_1.promise.when(null);
- })
- .then(() => {
- if (this.bpClient) {
- return this.driver.controlFlow().execute(() => {
- return this.bpClient.setWaitEnabled(false);
- });
- }
- })
- .then(() => {
- // Go to reset url
- return this.driver.get(this.resetUrl);
- })
- .then(() => {
- // Set defer label and navigate
- return this.executeScriptWithDescription('window.name = "' + DEFER_LABEL + '" + window.name;' +
- 'window.location.replace("' + destination + '");', msg('reset url'));
- })
- .then(() => {
- // We need to make sure the new url has loaded before
- // we try to execute any asynchronous scripts.
- return this.driver.wait(() => {
- return this.executeScriptWithDescription('return window.location.href;', msg('get url'))
- .then((url) => {
- return url !== this.resetUrl;
- }, (err) => {
- if (err.code == 13 || err.name === 'JavascriptError') {
- // Ignore the error, and continue trying. This is
- // because IE driver sometimes (~1%) will throw an
- // unknown error from this execution. See
- // https://github.com/angular/protractor/issues/841
- // This shouldn't mask errors because it will fail
- // with the timeout anyway.
- return false;
- }
- else {
- throw err;
- }
- });
- }, timeout, 'waiting for page to load for ' + timeout + 'ms');
- })
- .then(() => {
- // Run Plugins
- return this.driver.controlFlow().execute(() => {
- return this.plugins_.onPageLoad(this);
- });
- })
- .then(() => {
- // Make sure the page is an Angular page.
- return this
- .executeAsyncScript_(clientSideScripts.testForAngular, msg('test for angular'), Math.floor(timeout / 1000), this.ng12Hybrid)
- .then((angularTestResult) => {
- let angularVersion = angularTestResult.ver;
- if (!angularVersion) {
- let message = angularTestResult.message;
- logger.error(`Could not find Angular on page ${destination} : ${message}`);
- throw new Error(`Angular could not be found on the page ${destination}. ` +
- `If this is not an Angular application, you may need to turn off waiting for Angular.
- Please see
- https://github.com/angular/protractor/blob/master/docs/timeouts.md#waiting-for-angular-on-page-load`);
- }
- return angularVersion;
- }, (err) => {
- throw new Error('Error while running testForAngular: ' + err.message);
- });
- })
- .then((angularVersion) => {
- // Load Angular Mocks
- if (angularVersion === 1) {
- // At this point, Angular will pause for us until angular.resumeBootstrap is called.
- let moduleNames = [];
- let modulePromise = selenium_webdriver_1.promise.when(null);
- for (const { name, script, args } of this.mockModules_) {
- moduleNames.push(name);
- let executeScriptArgs = [script, msg('add mock module ' + name), ...args];
- modulePromise = modulePromise.then(() => this.executeScriptWithDescription.apply(this, executeScriptArgs)
- .then(null, (err) => {
- throw new Error('Error while running module script ' + name + ': ' + err.message);
- }));
- }
- return modulePromise.then(() => this.executeScriptWithDescription('window.__TESTABILITY__NG1_APP_ROOT_INJECTOR__ = ' +
- 'angular.resumeBootstrap(arguments[0]);', msg('resume bootstrap'), moduleNames));
- }
- else {
- // TODO: support mock modules in Angular2. For now, error if someone
- // has tried to use one.
- if (this.mockModules_.length > 1) {
- throw 'Trying to load mock modules on an Angular v2+ app is not yet supported.';
- }
- }
- })
- .then(() => {
- // Reset bpClient sync
- if (this.bpClient) {
- return this.driver.controlFlow().execute(() => {
- return this.bpClient.setWaitEnabled(!this.internalIgnoreSynchronization);
- });
- }
- })
- .then(() => {
- // Run Plugins
- return this.driver.controlFlow().execute(() => {
- return this.plugins_.onPageStable(this);
- });
- })
- .then(() => null);
- }
- /**
- * @see webdriver.WebDriver.refresh
- *
- * Makes a full reload of the current page and loads mock modules before
- * Angular. Assumes that the page being loaded uses Angular.
- * If you need to access a page which does not have Angular on load, use
- * the wrapped webdriver directly.
- *
- * @param {number=} opt_timeout Number of milliseconds to wait for Angular to start.
- */
- refresh(opt_timeout) {
- if (this.ignoreSynchronization) {
- return this.driver.navigate().refresh();
- }
- return this
- .executeScriptWithDescription('return window.location.href', 'Protractor.refresh() - getUrl')
- .then((href) => {
- return this.get(href, opt_timeout);
- });
- }
- /**
- * Mixin navigation methods back into the navigation object so that
- * they are invoked as before, i.e. driver.navigate().refresh()
- */
- navigate() {
- let nav = this.driver.navigate();
- ptorMixin(nav, this, 'refresh');
- return nav;
- }
- /**
- * Browse to another page using in-page navigation.
- *
- * @example
- * browser.get('http://angular.github.io/protractor/#/tutorial');
- * browser.setLocation('api');
- * expect(browser.getCurrentUrl())
- * .toBe('http://angular.github.io/protractor/#/api');
- *
- * @param {string} url In page URL using the same syntax as $location.url()
- * @returns {!webdriver.promise.Promise} A promise that will resolve once
- * page has been changed.
- */
- setLocation(url) {
- return this.waitForAngular()
- .then(() => this.angularAppRoot())
- .then((rootEl) => this.executeScriptWithDescription(clientSideScripts.setLocation, 'Protractor.setLocation()', rootEl, url)
- .then((browserErr) => {
- if (browserErr) {
- throw 'Error while navigating to \'' + url +
- '\' : ' + JSON.stringify(browserErr);
- }
- }));
- }
- /**
- * Deprecated, use `browser.getCurrentUrl()` instead.
- *
- * Despite its name, this function will generally return `$location.url()`, though in some
- * cases it will return `$location.absUrl()` instead. This function is only here for legacy
- * users, and will probably be removed in Protractor 6.0.
- *
- * @deprecated Please use `browser.getCurrentUrl()`
- * @example
- * browser.get('http://angular.github.io/protractor/#/api');
- * expect(browser.getLocationAbsUrl())
- * .toBe('http://angular.github.io/protractor/#/api');
- * @returns {webdriver.promise.Promise<string>} The current absolute url from
- * AngularJS.
- */
- getLocationAbsUrl() {
- logger.warn('`browser.getLocationAbsUrl()` is deprecated, please use `browser.getCurrentUrl` instead.');
- return this.waitForAngular()
- .then(() => this.angularAppRoot())
- .then((rootEl) => this.executeScriptWithDescription(clientSideScripts.getLocationAbsUrl, 'Protractor.getLocationAbsUrl()', rootEl));
- }
- /**
- * Determine if the control flow is enabled.
- *
- * @returns true if the control flow is enabled, false otherwise.
- */
- controlFlowIsEnabled() {
- if (selenium_webdriver_1.promise.USE_PROMISE_MANAGER !== undefined) {
- return selenium_webdriver_1.promise.USE_PROMISE_MANAGER;
- }
- else {
- // True for old versions of `selenium-webdriver`, probably false in >=5.0.0
- return !!selenium_webdriver_1.promise.ControlFlow;
- }
- }
- }
- /**
- * @type {ProtractorBy}
- */
- ProtractorBrowser.By = new locators_1.ProtractorBy();
- exports.ProtractorBrowser = ProtractorBrowser;
- //# sourceMappingURL=browser.js.map
|