123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427 |
- // Licensed to the Software Freedom Conservancy (SFC) under one
- // or more contributor license agreements. See the NOTICE file
- // distributed with this work for additional information
- // regarding copyright ownership. The SFC licenses this file
- // to you under the Apache License, Version 2.0 (the
- // "License"); you may not use this file except in compliance
- // with the License. You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing,
- // software distributed under the License is distributed on an
- // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- // KIND, either express or implied. See the License for the
- // specific language governing permissions and limitations
- // under the License.
- /**
- * @fileoverview Defines common conditions for use with
- * {@link webdriver.WebDriver#wait WebDriver wait}.
- *
- * Sample usage:
- *
- * driver.get('http://www.google.com/ncr');
- *
- * var query = driver.wait(until.elementLocated(By.name('q')));
- * query.sendKeys('webdriver\n');
- *
- * driver.wait(until.titleIs('webdriver - Google Search'));
- *
- * To define a custom condition, simply call WebDriver.wait with a function
- * that will eventually return a truthy-value (neither null, undefined, false,
- * 0, or the empty string):
- *
- * driver.wait(function() {
- * return driver.getTitle().then(function(title) {
- * return title === 'webdriver - Google Search';
- * });
- * }, 1000);
- */
- 'use strict';
- const by = require('./by');
- const By = require('./by').By;
- const error = require('./error');
- const webdriver = require('./webdriver'),
- Condition = webdriver.Condition,
- WebElementCondition = webdriver.WebElementCondition;
- /**
- * Creates a condition that will wait until the input driver is able to switch
- * to the designated frame. The target frame may be specified as
- *
- * 1. a numeric index into
- * [window.frames](https://developer.mozilla.org/en-US/docs/Web/API/Window.frames)
- * for the currently selected frame.
- * 2. a {@link ./webdriver.WebElement}, which must reference a FRAME or IFRAME
- * element on the current page.
- * 3. a locator which may be used to first locate a FRAME or IFRAME on the
- * current page before attempting to switch to it.
- *
- * Upon successful resolution of this condition, the driver will be left
- * focused on the new frame.
- *
- * @param {!(number|./webdriver.WebElement|By|
- * function(!./webdriver.WebDriver): !./webdriver.WebElement)} frame
- * The frame identifier.
- * @return {!Condition<boolean>} A new condition.
- */
- exports.ableToSwitchToFrame = function ableToSwitchToFrame(frame) {
- var condition;
- if (typeof frame === 'number' || frame instanceof webdriver.WebElement) {
- condition = driver => attemptToSwitchFrames(driver, frame);
- } else {
- condition = function(driver) {
- let locator = /** @type {!(By|Function)} */(frame);
- return driver.findElements(locator).then(function(els) {
- if (els.length) {
- return attemptToSwitchFrames(driver, els[0]);
- }
- });
- };
- }
- return new Condition('to be able to switch to frame', condition);
- function attemptToSwitchFrames(driver, frame) {
- return driver.switchTo().frame(frame).then(
- function() { return true; },
- function(e) {
- if (!(e instanceof error.NoSuchFrameError)) {
- throw e;
- }
- });
- }
- };
- /**
- * Creates a condition that waits for an alert to be opened. Upon success, the
- * returned promise will be fulfilled with the handle for the opened alert.
- *
- * @return {!Condition<!./webdriver.Alert>} The new condition.
- */
- exports.alertIsPresent = function alertIsPresent() {
- return new Condition('for alert to be present', function(driver) {
- return driver.switchTo().alert().catch(function(e) {
- if (!(e instanceof error.NoSuchAlertError
- // XXX: Workaround for GeckoDriver error `TypeError: can't convert null
- // to object`. For more details, see
- // https://github.com/SeleniumHQ/selenium/pull/2137
- || (e instanceof error.WebDriverError
- && e.message === `can't convert null to object`)
- )) {
- throw e;
- }
- });
- });
- };
- /**
- * Creates a condition that will wait for the current page's title to match the
- * given value.
- *
- * @param {string} title The expected page title.
- * @return {!Condition<boolean>} The new condition.
- */
- exports.titleIs = function titleIs(title) {
- return new Condition(
- 'for title to be ' + JSON.stringify(title),
- function(driver) {
- return driver.getTitle().then(function(t) {
- return t === title;
- });
- });
- };
- /**
- * Creates a condition that will wait for the current page's title to contain
- * the given substring.
- *
- * @param {string} substr The substring that should be present in the page
- * title.
- * @return {!Condition<boolean>} The new condition.
- */
- exports.titleContains = function titleContains(substr) {
- return new Condition(
- 'for title to contain ' + JSON.stringify(substr),
- function(driver) {
- return driver.getTitle().then(function(title) {
- return title.indexOf(substr) !== -1;
- });
- });
- };
- /**
- * Creates a condition that will wait for the current page's title to match the
- * given regular expression.
- *
- * @param {!RegExp} regex The regular expression to test against.
- * @return {!Condition<boolean>} The new condition.
- */
- exports.titleMatches = function titleMatches(regex) {
- return new Condition('for title to match ' + regex, function(driver) {
- return driver.getTitle().then(function(title) {
- return regex.test(title);
- });
- });
- };
- /**
- * Creates a condition that will wait for the current page's url to match the
- * given value.
- *
- * @param {string} url The expected page url.
- * @return {!Condition<boolean>} The new condition.
- */
- exports.urlIs = function urlIs(url) {
- return new Condition(
- 'for URL to be ' + JSON.stringify(url),
- function(driver) {
- return driver.getCurrentUrl().then(function(u) {
- return u === url;
- });
- });
- };
- /**
- * Creates a condition that will wait for the current page's url to contain
- * the given substring.
- *
- * @param {string} substrUrl The substring that should be present in the current
- * URL.
- * @return {!Condition<boolean>} The new condition.
- */
- exports.urlContains = function urlContains(substrUrl) {
- return new Condition(
- 'for URL to contain ' + JSON.stringify(substrUrl),
- function(driver) {
- return driver.getCurrentUrl().then(function(url) {
- return url.indexOf(substrUrl) !== -1;
- });
- });
- };
- /**
- * Creates a condition that will wait for the current page's url to match the
- * given regular expression.
- *
- * @param {!RegExp} regex The regular expression to test against.
- * @return {!Condition<boolean>} The new condition.
- */
- exports.urlMatches = function urlMatches(regex) {
- return new Condition('for URL to match ' + regex, function(driver) {
- return driver.getCurrentUrl().then(function(url) {
- return regex.test(url);
- });
- });
- };
- /**
- * Creates a condition that will loop until an element is
- * {@link ./webdriver.WebDriver#findElement found} with the given locator.
- *
- * @param {!(By|Function)} locator The locator to use.
- * @return {!WebElementCondition} The new condition.
- */
- exports.elementLocated = function elementLocated(locator) {
- locator = by.checkedLocator(locator);
- let locatorStr =
- typeof locator === 'function' ? 'by function()' : locator + '';
- return new WebElementCondition('for element to be located ' + locatorStr,
- function(driver) {
- return driver.findElements(locator).then(function(elements) {
- return elements[0];
- });
- });
- };
- /**
- * Creates a condition that will loop until at least one element is
- * {@link ./webdriver.WebDriver#findElement found} with the given locator.
- *
- * @param {!(By|Function)} locator The locator to use.
- * @return {!Condition<!Array<!./webdriver.WebElement>>} The new
- * condition.
- */
- exports.elementsLocated = function elementsLocated(locator) {
- locator = by.checkedLocator(locator);
- let locatorStr =
- typeof locator === 'function' ? 'by function()' : locator + '';
- return new Condition(
- 'for at least one element to be located ' + locatorStr,
- function(driver) {
- return driver.findElements(locator).then(function(elements) {
- return elements.length > 0 ? elements : null;
- });
- });
- };
- /**
- * Creates a condition that will wait for the given element to become stale. An
- * element is considered stale once it is removed from the DOM, or a new page
- * has loaded.
- *
- * @param {!./webdriver.WebElement} element The element that should become stale.
- * @return {!Condition<boolean>} The new condition.
- */
- exports.stalenessOf = function stalenessOf(element) {
- return new Condition('element to become stale', function() {
- return element.getTagName().then(
- function() { return false; },
- function(e) {
- if (e instanceof error.StaleElementReferenceError) {
- return true;
- }
- throw e;
- });
- });
- };
- /**
- * Creates a condition that will wait for the given element to become visible.
- *
- * @param {!./webdriver.WebElement} element The element to test.
- * @return {!WebElementCondition} The new condition.
- * @see ./webdriver.WebDriver#isDisplayed
- */
- exports.elementIsVisible = function elementIsVisible(element) {
- return new WebElementCondition('until element is visible', function() {
- return element.isDisplayed().then(v => v ? element : null);
- });
- };
- /**
- * Creates a condition that will wait for the given element to be in the DOM,
- * yet not visible to the user.
- *
- * @param {!./webdriver.WebElement} element The element to test.
- * @return {!WebElementCondition} The new condition.
- * @see ./webdriver.WebDriver#isDisplayed
- */
- exports.elementIsNotVisible = function elementIsNotVisible(element) {
- return new WebElementCondition('until element is not visible', function() {
- return element.isDisplayed().then(v => v ? null : element);
- });
- };
- /**
- * Creates a condition that will wait for the given element to be enabled.
- *
- * @param {!./webdriver.WebElement} element The element to test.
- * @return {!WebElementCondition} The new condition.
- * @see webdriver.WebDriver#isEnabled
- */
- exports.elementIsEnabled = function elementIsEnabled(element) {
- return new WebElementCondition('until element is enabled', function() {
- return element.isEnabled().then(v => v ? element : null);
- });
- };
- /**
- * Creates a condition that will wait for the given element to be disabled.
- *
- * @param {!./webdriver.WebElement} element The element to test.
- * @return {!WebElementCondition} The new condition.
- * @see webdriver.WebDriver#isEnabled
- */
- exports.elementIsDisabled = function elementIsDisabled(element) {
- return new WebElementCondition('until element is disabled', function() {
- return element.isEnabled().then(v => v ? null : element);
- });
- };
- /**
- * Creates a condition that will wait for the given element to be selected.
- * @param {!./webdriver.WebElement} element The element to test.
- * @return {!WebElementCondition} The new condition.
- * @see webdriver.WebDriver#isSelected
- */
- exports.elementIsSelected = function elementIsSelected(element) {
- return new WebElementCondition('until element is selected', function() {
- return element.isSelected().then(v => v ? element : null);
- });
- };
- /**
- * Creates a condition that will wait for the given element to be deselected.
- *
- * @param {!./webdriver.WebElement} element The element to test.
- * @return {!WebElementCondition} The new condition.
- * @see webdriver.WebDriver#isSelected
- */
- exports.elementIsNotSelected = function elementIsNotSelected(element) {
- return new WebElementCondition('until element is not selected', function() {
- return element.isSelected().then(v => v ? null : element);
- });
- };
- /**
- * Creates a condition that will wait for the given element's
- * {@link webdriver.WebDriver#getText visible text} to match the given
- * {@code text} exactly.
- *
- * @param {!./webdriver.WebElement} element The element to test.
- * @param {string} text The expected text.
- * @return {!WebElementCondition} The new condition.
- * @see webdriver.WebDriver#getText
- */
- exports.elementTextIs = function elementTextIs(element, text) {
- return new WebElementCondition('until element text is', function() {
- return element.getText().then(t => t === text ? element : null);
- });
- };
- /**
- * Creates a condition that will wait for the given element's
- * {@link webdriver.WebDriver#getText visible text} to contain the given
- * substring.
- *
- * @param {!./webdriver.WebElement} element The element to test.
- * @param {string} substr The substring to search for.
- * @return {!WebElementCondition} The new condition.
- * @see webdriver.WebDriver#getText
- */
- exports.elementTextContains = function elementTextContains(element, substr) {
- return new WebElementCondition('until element text contains', function() {
- return element.getText()
- .then(t => t.indexOf(substr) != -1 ? element : null);
- });
- };
- /**
- * Creates a condition that will wait for the given element's
- * {@link webdriver.WebDriver#getText visible text} to match a regular
- * expression.
- *
- * @param {!./webdriver.WebElement} element The element to test.
- * @param {!RegExp} regex The regular expression to test against.
- * @return {!WebElementCondition} The new condition.
- * @see webdriver.WebDriver#getText
- */
- exports.elementTextMatches = function elementTextMatches(element, regex) {
- return new WebElementCondition('until element text matches', function() {
- return element.getText().then(t => regex.test(t) ? element : null);
- });
- };
|