| // 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); |
| }); |
| }; |