All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.seleniumtests.uipage.htmlelements.HtmlElement Maven / Gradle / Ivy

There is a newer version: 4.23.18
Show newest version
/**
 * Orignal work: Copyright 2015 www.seleniumtests.com
 * Modified work: Copyright 2016 www.infotel.com
 * 				Copyright 2017-2019 B.Hecquet
 *
 * Licensed 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.
 */
package com.seleniumtests.uipage.htmlelements;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.imageio.ImageIO;

import org.apache.log4j.Logger;
import org.openqa.selenium.By;
import org.openqa.selenium.By.ByXPath;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.ElementNotVisibleException;
import org.openqa.selenium.HasCapabilities;
import org.openqa.selenium.InvalidElementStateException;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.NoSuchFrameException;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.Point;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.interactions.Coordinates;
import org.openqa.selenium.interactions.Locatable;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.RemoteWebElement;
import org.openqa.selenium.remote.ScreenshotException;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import com.seleniumtests.browserfactory.FirefoxDriverFactory;
import com.seleniumtests.core.SeleniumTestsContextManager;
import com.seleniumtests.core.testretry.TestRetryAnalyzer;
import com.seleniumtests.customexception.ConfigurationException;
import com.seleniumtests.customexception.CustomSeleniumTestsException;
import com.seleniumtests.customexception.DriverExceptions;
import com.seleniumtests.customexception.ScenarioException;
import com.seleniumtests.driver.BrowserType;
import com.seleniumtests.driver.CustomEventFiringWebDriver;
import com.seleniumtests.driver.DriverConfig;
import com.seleniumtests.driver.TestType;
import com.seleniumtests.driver.WebUIDriver;
import com.seleniumtests.driver.screenshots.ScreenshotUtil;
import com.seleniumtests.driver.screenshots.SnapshotTarget;
import com.seleniumtests.uipage.ExpectedConditionsC;
import com.seleniumtests.uipage.PageObject;
import com.seleniumtests.uipage.ReplayOnError;
import com.seleniumtests.util.helper.WaitHelper;
import com.seleniumtests.util.imaging.ImageDetector;
import com.seleniumtests.util.imaging.ImageProcessor;
import com.seleniumtests.util.logging.DebugMode;
import com.seleniumtests.util.logging.ScenarioLogger;
import com.seleniumtests.util.logging.SeleniumRobotLogger;

import io.appium.java_client.MobileElement;
import io.appium.java_client.MultiTouchAction;
import io.appium.java_client.PerformsTouchActions;
import io.appium.java_client.TouchAction;
import io.appium.java_client.touch.WaitOptions;
import io.appium.java_client.touch.offset.ElementOption;
import io.appium.java_client.touch.offset.PointOption;

/**
 * Provides methods to interact with a web page. All HTML element
 * (ButtonElement, LinkElement, TextFieldElement, etc.) extends from this class.
 * 
 * 
 */
public class HtmlElement extends Element implements WebElement, Locatable {

	static {
		UiLibraryRegistry.register(PageObject.HTML_UI_LIBRARY);
	}

	// WARNING!!!: we use the deprecated Locatable interface because it's used by
	// Actions class
	// unit test TestPicutreElement.testClick() fails if the new interface is used
	// so wait to this old interface to be really removed

	protected static Logger logger = SeleniumRobotLogger.getLogger(HtmlElement.class);
	private static ScenarioLogger scenarioLogger = ScenarioLogger.getScenarioLogger(TestRetryAnalyzer.class);

	public static final Integer FIRST_VISIBLE = Integer.MAX_VALUE;
	public static final Integer OPTIMAL_SCROLLING = Integer.MAX_VALUE;

	private static final String JS_CLICK_TRIPLE = "var target = arguments[0];" + "emit('mousedown', {buttons: 1}); "
			+ "emit('mouseup',   {});" + "emit('mousedown', {buttons: 1}); " + "emit('mouseup',   {});"
			+ "emit('mousedown', {buttons: 1}); " + "emit('mouseup',   {});" + "emit('click',     {detail: 3});  " + ""
			+ "function emit(name, init) {" + "target.dispatchEvent(new MouseEvent(name, init));" + "}";

	private static final String JS_CLICK_DOUBLE = "if(document.createEvent){"
			+ "   var evObj = document.createEvent('MouseEvents');" + "   evObj.initEvent('dblclick', true, false); "
			+ "   arguments[0].dispatchEvent(evObj);" + "} else if(document.createEventObject) { "
			+ "   arguments[0].fireEvent('ondblclick');" + "}";

	private ThreadLocal driver = new ThreadLocal<>();
	private ThreadLocal element = new ThreadLocal<>();
	protected String label = null;
	protected HtmlElement parent = null;
	protected FrameElement frameElement = null;
	private boolean scrollToElementBeforeAction = false;
	private Integer elementIndex = -1;
	private By by = null;
	private String origin = null;

	public HtmlElement() {
		this("", By.id(""));
	}

	/**
	 * Find element using BY locator. Make sure to initialize the driver before
	 * calling findElement()
	 *
	 * @param label - element name for logging
	 * @param by    - By type
	 *
	 * @sample {@code new HtmlElement("UserId", By.id(userid))}
	 */

	public HtmlElement(String label, By by) {
		this(label, by, (Integer) null);
	}

	/**
	 * Find element using BY locator.
	 *
	 * @param label - element name for logging
	 * @param by    - By type
	 * @param index - index of the element to find. In this case, robot will search
	 *              the Nth element corresponding to the By parameter. Equivalent to
	 *              new HtmlElement(label, by).findElements().get(N) If index is
	 *              null, use driver.findElement(By) intenally If index
	 *              is negative, search from the last one (-1) If index is
	 *              HtmlElement.FIRST_VISIBLE, search the first visible element
	 *
	 * @sample {@code new HtmlElement("UserId", By.id(userid), 2)}
	 */
	public HtmlElement(String label, By by, Integer index) {
		this(label, by, (FrameElement) null, index);
	}

	public HtmlElement(String label, By by, Integer index, Integer replayTimeout) {
		this(label, by, null, index, replayTimeout);
	}

	/**
	 * Find element using BY locator into a frame
	 *
	 * @param label - element name for logging
	 * @param by    - By type
	 * @param frame - frame element into which we must switch before searching the
	 *              element
	 */
	public HtmlElement(String label, By by, FrameElement frame) {
		this(label, by, frame, null);
	}

	/**
	 * Find the nth element using BY locator into a frame
	 *
	 * @param label - element name for logging
	 * @param by    - By type
	 * @param frame - frame element into which we must switch before searching the
	 *              element
	 * @param index - index of the element to find. In this case, robot will search
	 *              the Nth element corresponding to the By parameter. Equivalent to
	 *              new HtmlElement(label, by).findElements().get(N) If index is
	 *              null, use driver.findElement(By) intenally If index
	 *              is negative, search from the last one (-1) If index is
	 *              HtmlElement.FIRST_VISIBLE, search the first visible element
	 */
	public HtmlElement(String label, By by, FrameElement frame, Integer index) {
		this(label, by, frame, null, index, null);
	}

	public HtmlElement(String label, By by, FrameElement frame, Integer index, Integer replayTimeout) {
		this(label, by, frame, null, index, replayTimeout);
	}

	/**
	 * Find element using BY locator into an other element.This help focusing on a
	 * page zone for searching an element
	 *
	 * @param label  - element name for logging
	 * @param by     - By type
	 * @param parent - Parent element to search before searching this element
	 */
	public HtmlElement(String label, By by, HtmlElement parent) {
		this(label, by, parent, null);
	}

	/**
	 * Find the nth element using BY locator into an other element.This help
	 * focusing on a page zone for searching an element
	 *
	 * @param label  - element name for logging
	 * @param by     - By type
	 * @param parent - Parent element to search before searching this element
	 * @param index  - index of the element to find. In this case, robot will search
	 *               the Nth element corresponding to the By parameter. Equivalent
	 *               to new HtmlElement(label, by).findElements().get(N) If index is
	 *               null, use driver.findElement(By) intenally If
	 *               index is negative, search from the last one (-1) If index is
	 *               HtmlElement.FIRST_VISIBLE, search the first visible element
	 */
	public HtmlElement(String label, By by, HtmlElement parent, Integer index) {
		this(label, by, null, parent, index, null);
	}

	public HtmlElement(String label, By by, HtmlElement parent, Integer index, Integer replayTimeout) {
		this(label, by, null, parent, index, replayTimeout);
	}

	/**
	 * @deprecated Should not be used as the element is either directly search in a
	 *             frame or in a parent element which itself is in a frame, not both
	 */
	@Deprecated
	public HtmlElement(String label, By by, FrameElement frame, HtmlElement parent, Integer index) {
		this(label, by, frame, parent, index, null);
	}

	/**
	 * Find the nth element using BY locator into an other element or a frame.This
	 * help focusing on a page zone for searching an element Frame and parent
	 * element are mutually exclusive
	 *
	 * @param label         - element name for logging
	 * @param by            - By type
	 * @param frame         - frame element into which we must switch before
	 *                      searching the element
	 * @param parent        - Parent element to search before searching this element
	 * @param index         - index of the element to find. In this case, robot will
	 *                      search the Nth element corresponding to the By
	 *                      parameter. Equivalent to new HtmlElement(label,
	 *                      by).findElements().get(N) If index is null, use
	 *                      driver.findElement(By) intenally If index
	 *                      is negative, search from the last one (-1) If index is
	 *                      HtmlElement.FIRST_VISIBLE, search the first visible
	 *                      element
	 * @param replayTimeout - how much time we must wait for the element to be
	 *                      present for playing with it
	 */
	protected HtmlElement(String label, By by, FrameElement frame, HtmlElement parent, Integer index,
			Integer replayTimeout) {
		this.label = label;
		this.by = by;
		this.elementIndex = index;
		this.parent = parent;

		if (parent != null && frame != null) {
			scenarioLogger.error(
					"parent element and frame cannot be set together. If you want to search a element with parent in a frame, define a frame for this parent");
		} else {
			this.frameElement = frame;
		}
		this.replayTimeout = replayTimeout;

		origin = PageObject.getCallingPage(Thread.currentThread().getStackTrace());
	}

	/**
	 * Native click
	 */
	@ReplayOnError(waitAfterAction = true)
	public void click() {
		findElement(true);

		outlineElement(getRealElementNoSearch());
		getRealElementNoSearch().click();
	}

	/**
	 * Click with CompositeActions
	 */
	@ReplayOnError(waitAfterAction = true)
	public void clickAction() {
		findElement(true);

		outlineElement(getRealElementNoSearch());
		try {
			new Actions(getDriver()).click(getRealElementNoSearch()).perform();
		} catch (InvalidElementStateException e) {
			logger.error(e);
		}
	}

	/**
	 * Double Click with CompositeActions
	 */
	@ReplayOnError(waitAfterAction = true)
	public void doubleClickAction() {
		findElement(true);

		outlineElement(getRealElementNoSearch());
		try {
			new Actions(getDriver()).doubleClick(getRealElementNoSearch()).perform();
		} catch (InvalidElementStateException e) {
			logger.error(e);
		}
	}

	@ReplayOnError(waitAfterAction = true)
	public void clickMouse() {

		Rectangle viewportPosition = detectViewPortPosition();

		// always scroll to element so that we can click on it with mouse
		setScrollToElementBeforeAction(true);
		findElement(true);

		outlineElement(getRealElementNoSearch());

		Rectangle elementRect = getRect();
		Point scrollPosition = ((CustomEventFiringWebDriver) getDriver()).getScrollPosition();

		CustomEventFiringWebDriver.leftClicOnDesktopAt(true,
				elementRect.x + elementRect.width / 2 + viewportPosition.x - scrollPosition.x,
				elementRect.y + elementRect.height / 2 + viewportPosition.y - scrollPosition.y,
				SeleniumTestsContextManager.getThreadContext().getRunMode(),
				SeleniumTestsContextManager.getThreadContext().getSeleniumGridConnector());

	}

	private File getDesktopScreenshotFile() {
		ScreenshotUtil screenshotUtil = new ScreenshotUtil(); // update driver
		return screenshotUtil.capture(SnapshotTarget.MAIN_SCREEN, File.class, true);
	}

	private File getViewportScreenshotFile() {
		ScreenshotUtil screenshotUtil = new ScreenshotUtil(); // update driver
		return screenshotUtil.capture(SnapshotTarget.VIEWPORT, File.class, true);
	}

	private Rectangle detectViewPortPosition() {
		BufferedImage image;
		try {
			image = ImageProcessor.loadFromFile(getViewportScreenshotFile());

			BufferedImage croppedImage = ImageProcessor.cropImage(image, 0, 0, image.getWidth(), 150);
			File cropScreenshotFile = File.createTempFile("img", ".png");
			ImageIO.write(croppedImage, "png", cropScreenshotFile);

			File desktopScreenshotFile = getDesktopScreenshotFile();
			if (desktopScreenshotFile == null) {
				throw new ScreenshotException("Desktop screenshot does not exist");
			}

			ImageDetector imageDetector = new ImageDetector(desktopScreenshotFile, cropScreenshotFile, 0.2);
			imageDetector.detectExactZoneWithoutScale();
			org.openqa.selenium.Rectangle detectedRectangle = imageDetector.getDetectedRectangle();
			return new Rectangle(detectedRectangle.x, detectedRectangle.y, detectedRectangle.height,
					detectedRectangle.width);

		} catch (IOException e) {
			throw new ScreenshotException("Error getting position of viewport: " + e.getMessage());
		}
	}

	/**
	 * Click element in native way by Actions.
	 *
	 * 

* *

	 * clickAt(1, 1);
	 * 
* * @param value */ @ReplayOnError(waitAfterAction = true) public void clickAt(int xOffset, int yOffset) { findElement(); ((CustomEventFiringWebDriver) getDriver()).scrollToElement(getRealElementNoSearch(), yOffset); outlineElement(getRealElementNoSearch()); try { new Actions(getDriver()).moveToElement(getRealElementNoSearch(), xOffset, yOffset).click().perform(); } catch (InvalidElementStateException e) { logger.error(e); getRealElementNoSearch().click(); } } /** * Click with javascript */ @ReplayOnError(waitAfterAction = true) public void simulateClick() { if (SeleniumTestsContextManager.isWebTest()) { ((CustomEventFiringWebDriver) updateDriver()).updateWindowsHandles(); } findElement(true); outlineElement(getRealElementNoSearch()); DriverConfig driverConfig = WebUIDriver.getWebUIDriver(false).getConfig(); String mouseOverScript; if ((driverConfig.getBrowserType() == BrowserType.FIREFOX && FirefoxDriverFactory.isMarionetteMode()) || driverConfig.getBrowserType() == BrowserType.EDGE || (driverConfig.getBrowserType() == BrowserType.CHROME && driverConfig.getMajorBrowserVersion() >= 75)) { mouseOverScript = "var event = new MouseEvent('mouseover', {view: window, bubbles: true, cancelable: true}) ; arguments[0].dispatchEvent(event);"; } else { mouseOverScript = "if(document.createEvent){var evObj = document.createEvent('MouseEvents');evObj.initEvent('mouseover', true, false); arguments[0].dispatchEvent(evObj);} else if(document.createEventObject) { arguments[0].fireEvent('onmouseover');}"; } executeScript(mouseOverScript, getRealElementNoSearch()); WaitHelper.waitForSeconds(2); String clickScript = ""; if ((driverConfig.getBrowserType() == BrowserType.FIREFOX && FirefoxDriverFactory.isMarionetteMode()) || driverConfig.getBrowserType() == BrowserType.EDGE || (driverConfig.getBrowserType() == BrowserType.CHROME && driverConfig.getMajorBrowserVersion() >= 75)) { clickScript = "var event = new MouseEvent('click', {view: window, bubbles: true, cancelable: true}) ;" + "arguments[0].dispatchEvent(event);"; } else { clickScript = "if(document.createEvent){var evObj = document.createEvent('MouseEvents');evObj.initEvent('click', true, false); arguments[0].dispatchEvent(evObj);} else if(document.createEventObject) { arguments[0].fireEvent('onclick');}"; } executeScript(clickScript, getRealElementNoSearch()); WaitHelper.waitForSeconds(2); } @ReplayOnError(waitAfterAction = true) public void simulateDoubleClick() { findElement(true); outlineElement(getRealElementNoSearch()); DriverConfig driverConfig = WebUIDriver.getWebUIDriver(false).getConfig(); String doubleClickScript; if ((driverConfig.getBrowserType() == BrowserType.FIREFOX && FirefoxDriverFactory.isMarionetteMode()) || driverConfig.getBrowserType() == BrowserType.EDGE || (driverConfig.getBrowserType() == BrowserType.CHROME && driverConfig.getMajorBrowserVersion() >= 75)) { doubleClickScript = "var event = new MouseEvent('dblclick', {view: window, bubbles: true, cancelable: true}) ;" + "arguments[0].dispatchEvent(event);"; } else { doubleClickScript = JS_CLICK_DOUBLE; } executeScript(doubleClickScript, getRealElementNoSearch()); } @ReplayOnError(waitAfterAction = true) public void simulateSendKeys(CharSequence... keysToSend) { findElement(true); // click on element before sending keys through keyboard getRealElementNoSearch().click(); executeScript("arguments[0].focus();", getRealElementNoSearch()); DriverConfig driverConfig = WebUIDriver.getWebUIDriver(false).getConfig(); // handlitee org.openqa.selenium.UnsupportedCommandException: // sendKeysToActiveElement which are not available for firefox and IE if ((driverConfig.getBrowserType() == BrowserType.FIREFOX && FirefoxDriverFactory.isMarionetteMode()) || driverConfig.getBrowserType() == BrowserType.INTERNET_EXPLORER || driverConfig.getBrowserType() == BrowserType.EDGE || (driverConfig.getBrowserType() == BrowserType.CHROME && driverConfig.getMajorBrowserVersion() >= 75)) { logger.warn("using specific Marionette method"); executeScript(String.format("arguments[0].value='%s';", keysToSend[0].toString()), getRealElementNoSearch()); } else { // use keyboard to type ((CustomEventFiringWebDriver) getDriver()).getKeyboard().sendKeys(keysToSend); } } @ReplayOnError(waitAfterAction = true) public void simulateMoveToElement(int x, int y) { findElement(true); executeScript( "function simulate(f,c,d,e){var b,a=null;for(b in eventMatchers)if(eventMatchers[b].test(c)){a=b;break}if(!a)return!1;document.createEvent?(b=document.createEvent(a),a==\"HTMLEvents\"?b.initEvent(c,!0,!0):b.initMouseEvent(c,!0,!0,document.defaultView,0,d,e,d,e,!1,!1,!1,!1,0,null),f.dispatchEvent(b)):(a=document.createEventObject(),a.detail=0,a.screenX=d,a.screenY=e,a.clientX=d,a.clientY=e,a.ctrlKey=!1,a.altKey=!1,a.shiftKey=!1,a.metaKey=!1,a.button=1,f.fireEvent(\"on\"+c,a));return!0} var eventMatchers={HTMLEvents:/^(?:load|unload|abort|errorLogger|select|change|submit|reset|focus|blur|resize|scroll)$/,MouseEvents:/^(?:click|dblclick|mouse(?:down|up|over|move|out))$/}; " + "simulate(arguments[0],\"mousemove\",arguments[1],arguments[2]);", getRealElementNoSearch(), x, y); } /** * Returns the list of prefered UI libraries for the current page Should be used * when multiple UiLibraries are defined for an element (e.g: SelectList) * * @return */ protected List getPreferedUiLibraries() { if (origin != null) { return PageObject.getUiLibraries(origin); } return new ArrayList<>(); } /** * Find elements inside this element * * @param by * @return List of selenium WebElement */ @Override @ReplayOnError public List findElements(By by) { // find the root element findElement(false, false); List elements = getRealElementNoSearch().findElements(by); // throw exception so that behavior is the same as with 'findElements()' call // which retries search if (elements.isEmpty()) { throw new NoSuchElementException("No elements found for " + by.toString()); } else { return elements; } } /** * Find elements inside this element * * @param childBy * @return List of HtmlElement's based on real WebElement */ @ReplayOnError public List findHtmlElements(By childBy) { // find the root element findElement(false, false); List htmlElements = new ArrayList<>(); List elements = getRealElementNoSearch().findElements(childBy); // throw exception so that behavior is the same as with 'findElements()' call // which retries search if (elements.isEmpty()) { throw new NoSuchElementException("No elements found for " + childBy.toString()); } for (int i = 0; i < elements.size(); i++) { // frame set to null as we expect the frames are searched in the parent element htmlElements.add(new HtmlElement("", childBy, this, i)); } return htmlElements; } /** * Find an element inside an other one * * @param by * @return */ @Override public HtmlElement findElement(By by) { return new HtmlElement(label, by, this); } public ButtonElement findButtonElement(By by) { return new ButtonElement(label, by, this); } public CheckBoxElement findCheckBoxElement(By by) { return new CheckBoxElement(label, by, this); } public ImageElement findImageElement(By by) { return new ImageElement(label, by, this); } public LabelElement findLabelElement(By by) { return new LabelElement(label, by, this); } public LinkElement findLinkElement(By by) { return new LinkElement(label, by, this); } public RadioButtonElement findRadioButtonElement(By by) { return new RadioButtonElement(label, by, this); } public SelectList findSelectList(By by) { return new SelectList(label, by, this); } public Table findTable(By by) { return new Table(label, by, this); } public TextFieldElement findTextFieldElement(By by) { return new TextFieldElement(label, by, this); } /** * Find the Nth element inside an other one Equivalent to HtmlElement("", * By.id("0").findElements(By.id("1")).get(0); except that any action on the * found element will be retried if it fails * * @param by locator of the element list * @param index index in the list to get * @return */ public HtmlElement findElement(By by, Integer index) { return new HtmlElement(label, by, this, index); } public ButtonElement findButtonElement(By by, Integer index) { return new ButtonElement(label, by, this, index); } public CheckBoxElement findCheckBoxElement(By by, Integer index) { return new CheckBoxElement(label, by, this, index); } public ImageElement findImageElement(By by, Integer index) { return new ImageElement(label, by, this, index); } public LabelElement findLabelElement(By by, Integer index) { return new LabelElement(label, by, this, index); } public LinkElement findLinkElement(By by, Integer index) { return new LinkElement(label, by, this, index); } public RadioButtonElement findRadioButtonElement(By by, Integer index) { return new RadioButtonElement(label, by, this, index); } public SelectList findSelectList(By by, Integer index) { return new SelectList(label, by, this, index); } public Table findTable(By by, Integer index) { return new Table(label, by, this, index); } public TextFieldElement findTextFieldElement(By by, Integer index) { return new TextFieldElement(label, by, this, index); } protected void findElement() { findElement(false, true); } protected void findElement(boolean waitForVisibility) { findElement(waitForVisibility, true); } /** * Change CSS attribute of the element by setting if via javascript: * arguments[0].style.= * * @param cssProperty * @param cssPropertyValue */ public void changeCssAttribute(String cssProperty, String cssPropertyValue) { findElement(false, false); changeCssAttribute(getRealElementNoSearch(), cssProperty, cssPropertyValue); } /** * Execute arbitrary script on this element. Renaming of getEval * * @param script the script to execute. It MUST contain 'arguments[0]' and may * return something * @return arbitrary value. You must cast it */ @ReplayOnError public Object executeScript(String javascript, Object... args) { findElement(false, false); return executeScript(javascript, getRealElementNoSearch(), args); } /** * Execute arbitrary script on the provided element * * @param element the WebElement on which we call the script * @param script the script to execute. It MUST contain 'arguments[0]' and may * return something * @param args optional arguments to pass to the script. They should ba * accessed using 'arguments[1]' ... * @return arbitrary value. You must cast it */ protected Object executeScript(String javascript, WebElement element, Object... args) { if (element == null) { throw new ScenarioException("element should have been previously searched"); } if (element instanceof HtmlElement) { throw new ScenarioException("Only real elements should be provided, not HtmlElement"); } if (!javascript.contains("arguments[0]")) { throw new ScenarioException("JS script MUST contain 'arguments[0]' as reference"); } return ((JavascriptExecutor) getDriver()).executeScript(javascript, element, args); } /** * Finds the element using By type. Implicit Waits is built in createWebDriver() * in WebUIDriver to handle dynamic element problem. This method is invoked * before all the basic operations like click, sendKeys, getText, etc. Use * waitForPresent to use Explicit Waits to deal with special element which needs * long time to present. * * @param waitForVisibility wait for element to be visible * @param makeVisible whether we try to make the element visible. Should * be true except when trying to know if element is * displayed */ public void findElement(boolean waitForVisibility, boolean makeVisible) { // TODO: // https://discuss.appium.io/t/how-can-i-scroll-to-an-element-in-appium-im-using-android-native-app/10618/14 // String DESTINATION_ELEMENT_TEXT= "KUBO"; // ((AndroidDriver) driver).findElementByAndroidUIAutomator("new // UiScrollable(new UiSelector()) // .scrollIntoView(new UiSelector().text(DESTINATION_ELEMENT_TEXT))"); ElementInfo elementInfo = null; // search element information. Do not stop if something goes wrong here if (SeleniumTestsContextManager.getThreadContext().getAdvancedElementSearch() != ElementInfo.Mode.FALSE) { try { elementInfo = ElementInfo.getInstance(this); } catch (Exception e) { logger.info("Error getting element info"); } } // if a parent is defined, search for it before getting the sub element setDriver(updateDriver()); if (parent != null) { parent.findElement(false, false); // issue #166: add a dot in front of xpath expression if we search the element // inside a parent if (by instanceof ByXPath) { try { Field xpathExpressionField = ByXPath.class.getDeclaredField("xpathExpression"); xpathExpressionField.setAccessible(true); String xpath = (String) xpathExpressionField.get(by); if (xpath.startsWith("//")) { by = By.xpath("." + xpath); } } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { throw new CustomSeleniumTestsException(e); } } setElement(findSeleniumElement(parent.getRealElementNoSearch(), elementInfo)); } else { setElement(findSeleniumElement(getDriver(), elementInfo)); } if (makeVisible) { makeWebElementVisible(getRealElementNoSearch()); if (scrollToElementBeforeAction) { ((CustomEventFiringWebDriver) getDriver()).scrollToElement(getRealElementNoSearch(), OPTIMAL_SCROLLING); } } // wait for element to be really visible. should be done only for actions on // element if (waitForVisibility && makeVisible) { try { new WebDriverWait(getDriver(), 1).until(ExpectedConditions.visibilityOf(getRealElementNoSearch())); } catch (TimeoutException e) { logger.error(String.format("Element %s has never been made visible", toString())); } } // If we are here, element has been found, update elementInformation if (elementInfo != null) { try { elementInfo.updateInfo(this); elementInfo.exportToJsonFile(false, this); } catch (Exception e) { logger.warn("Error storing element information: " + e.getMessage()); } } } /** * Call driver to really search the element If index is specified, return the * Nth element corresponding to search * * @param context * @param elementInfo * @return */ private WebElement findSeleniumElement(SearchContext context, ElementInfo elementInfo) { enterFrame(); WebElement seleniumElement; try { if (elementIndex == null) { seleniumElement = context.findElement(by); } else { seleniumElement = getElementByIndex(context.findElements(by)); } return seleniumElement; } catch (WebDriverException e) { // element not found, raise exception // this code is here to prepare advanced element search throw e; } } /** * returns an element depending on configured index * * @param allElements */ private WebElement getElementByIndex(List allElements) { if (elementIndex != null && elementIndex.equals(FIRST_VISIBLE)) { for (WebElement el : allElements) { if (el.isDisplayed()) { return el; } } throw new NoSuchElementException("no visible element has been found for " + by.toString()); } else if (elementIndex != null && elementIndex < 0) { return allElements.get(allElements.size() + elementIndex); } else { if (elementIndex == null) { elementIndex = 0; } try { return allElements.get(elementIndex); } catch (IndexOutOfBoundsException e) { throw new NoSuchElementException( String.format("No element found for locator %s with index %d", by.toString(), elementIndex)); } } } /** * Method for going into the right frame before doing anything else this method * should be called each time we need to get an element Therefore, it's used * inside findElement() method */ private void enterFrame() { List frameTree = new ArrayList<>(); FrameElement frame = getFrameElement(); while (frame != null) { frameTree.add(0, frame); frame = frame.getFrameElement(); } for (FrameElement frameEl : frameTree) { Integer idx = frameEl.getElementIndex() == null ? 0 : frameEl.getElementIndex(); WebElement frameWebElement; SearchContext searchContext; if (frameEl.parent != null) { frameEl.parent.findElement(false, false); searchContext = frameEl.parent.getRealElementNoSearch(); } else { searchContext = getDriver(); } try { frameWebElement = searchContext.findElements(frameEl.getBy()).get(idx); } catch (IndexOutOfBoundsException e) { throw new NoSuchFrameException( String.format("Frame %s with index %d has not been found", frameEl, idx)); } ((CustomEventFiringWebDriver) getDriver()).scrollToElement(frameWebElement, -20); getDriver().switchTo().frame(frameWebElement); } } protected void changeCssAttribute(WebElement element, String cssProperty, String cssPropertyValue) { String javascript = "arguments[0].style." + cssProperty + "='" + cssPropertyValue + "';"; executeScript(javascript, element); } /** * outlines the element before acting on it Element must have been searched * before */ protected void outlineElement(WebElement localElement) { if (localElement == null || !SeleniumTestsContextManager.isWebTest() || !SeleniumTestsContextManager.getThreadContext().getDebug().contains(DebugMode.GUI)) { return; } changeCssAttribute(localElement, "outline", "2px solid red"); WaitHelper.waitForMilliSeconds(250); changeCssAttribute(localElement, "outline", ""); } /** * Make element visible. Sometimes useful when real elements are backed by an * image element */ protected void makeWebElementVisible(WebElement localElement) { if (SeleniumTestsContextManager.isWebTest()) { if (localElement.isDisplayed()) { return; } try { if (localElement.getLocation().x < 0) { Long viewportHeight = (Long) ((JavascriptExecutor) getDriver()) .executeScript("return document.documentElement.clientHeight"); Integer heightPosition = localElement.getLocation().y > viewportHeight ? localElement.getLocation().y - viewportHeight.intValue() : localElement.getLocation().y; changeCssAttribute(localElement, "left", "20px"); changeCssAttribute(localElement, "top", heightPosition + "px"); changeCssAttribute(localElement, "position", "inherit"); } if (Boolean.TRUE .equals(executeScript("return getComputedStyle(arguments[0]).display === 'none'", localElement))) { changeCssAttribute(localElement, "display", "block"); } if (Boolean.TRUE.equals( executeScript("return getComputedStyle(arguments[0]).visibility !== 'visible'", localElement))) { changeCssAttribute(localElement, "visibility", "visible"); } if (Boolean.TRUE .equals(executeScript("return getComputedStyle(arguments[0]).opacity === '0'", localElement))) { changeCssAttribute(localElement, "opacity", "1"); } changeCssAttribute(localElement, "zIndex", "100000"); } catch (Exception e) { return; } // wait for element to be displayed try { new WebDriverWait(getDriver(), 1).until(ExpectedConditions.visibilityOf(localElement)); } catch (ElementNotVisibleException e) { scenarioLogger.info(String.format("element %s not visible", localElement)); } catch (Exception e) { logger.warn("Could not make element visible", e); } } } /** * Move to element * * @param element */ public void scrollToElement(int yOffset) { findElement(); ((CustomEventFiringWebDriver) getDriver()).scrollToElement(getRealElementNoSearch(), yOffset); } /** * Get all elements in the current page with same locator. * * @return */ @ReplayOnError public List findElements() { // call findElement to enter any specified frame and search for parent elements findElement(false, false); // issue #167: if we have a parent, search elements inside it if (parent != null) { return parent.getRealElementNoSearch().findElements(by); } else { return getDriver().findElements(by); } } /** * Gets an attribute (using standard key-value pair) from the underlying * attribute. * * @param name * * @return */ @ReplayOnError public String getAttribute(String name) { findElement(false, false); return getRealElementNoSearch().getAttribute(name); } /** * Returns the BY locator stored in the HtmlElement. * * @return */ public By getBy() { return by; } /** * Returns the value for the specified CSS key. * * @param propertyName * * @return */ @Override @ReplayOnError public String getCssValue(String propertyName) { findElement(false, false); return getRealElementNoSearch().getCssValue(propertyName); } /** * Get underlying WebDriver. */ protected WebDriver updateDriver() { setDriver(WebUIDriver.getWebDriver(false)); if (getDriver() == null) { throw new ScenarioException("Driver has not already been created"); } return getDriver(); } public WebDriver getDriver() { return driver.get(); } public void setDriver(WebDriver driver) { this.driver.set(driver); } /** * Returns the underlying WebDriver WebElement. * Search is always done * * @return */ @ReplayOnError public WebElement getElement() { findElement(true); return getRealElementNoSearch(); } /** * Executes the given JavaScript against the underlying WebElement. * * @param script * @deprecated ... * * @return */ @ReplayOnError @Deprecated public String getEval(String script) { findElement(false, false); return (String) ((JavascriptExecutor) getDriver()).executeScript(script, getRealElementNoSearch()); } /** * Returns the 'height' property of the underlying WebElement's Dimension. * * @return */ @ReplayOnError public int getHeight() { findElement(false, false); return getRealElementNoSearch().getSize().getHeight(); } /** * Returns the label used during initialization. * * @return */ public String getLabel() { return label; } /** * Gets the Point location of the underlying WebElement. * * @return */ @Override @ReplayOnError public Point getLocation() { findElement(false, false); return getRealElementNoSearch().getLocation(); } @Override @ReplayOnError public Rectangle getRect() { findElement(false, false); return new Rectangle(getRealElementNoSearch().getLocation(), getRealElementNoSearch().getSize()); } /** * Returns the Dimension property of the underlying WebElement. * * @return */ @Override @ReplayOnError public Dimension getSize() { findElement(false, false); return getRealElementNoSearch().getSize(); } /** * Returns the HTML Tag for the underlying WebElement (div, a, input, etc). * * @return */ @Override @ReplayOnError public String getTagName() { findElement(false, false); return getRealElementNoSearch().getTagName(); } /** * Returns the text body of the underlying WebElement. * * @return */ @Override @ReplayOnError public String getText() { findElement(false, false); return getRealElementNoSearch().getText(); } /** * Returns the 'value' attribute of the underlying WebElement. * * @return */ @ReplayOnError public String getValue() { findElement(false, false); return getRealElementNoSearch().getAttribute("value"); } /** * Returns the 'width' property of the underlying WebElement's Dimension. * * @return */ @ReplayOnError public int getWidth() { findElement(false, false); return getRealElementNoSearch().getSize().getWidth(); } /** * Indicates whether or not the web element is currently displayed in the * browser. * * @return */ @Override public boolean isDisplayed() { try { return isDisplayedRetry(); } catch (WebDriverException e) { scenarioLogger.warn( "Element not displayed / not found. For searching if element is present and/or displayed, use isElementPresentAndDisplayed() instead"); return false; } catch (Exception e) { return false; } } @ReplayOnError public boolean isDisplayedRetry() { findElement(false, false); outlineElement(getRealElementNoSearch()); return getRealElementNoSearch().isDisplayed(); } /** * Searches for the element using the BY locator, and indicates whether or not * it exists in the page. This can be used to look for hidden objects, whereas * isDisplayed() only looks for things that are visible to the user * * Note that when requested element has "HtmlElement.FIRST_VISIBLE" index, * isElementPresent acts as isElementPresentAndDisplayed * * @param timeout timeout in seconds * @return */ public boolean isElementPresent(int timeout) { try { waitForPresent(timeout); return true; } catch (TimeoutException e) { return false; } } public boolean isElementPresent() { return isElementPresent(SeleniumTestsContextManager.getThreadContext().getExplicitWaitTimeout()); } /** * Search for an element to be present AND displayed * * @param timeout timeout in seconds * @return false if the element is not present or present but not displayed */ public boolean isElementPresentAndDisplayed(int timeout) { try { waitForPresent(timeout); return isDisplayed(); } catch (TimeoutException e) { scenarioLogger.warn(String.format("Element %s is not present", getBy())); return false; } } public boolean isElementPresentAndDisplayed() { return isElementPresentAndDisplayed(SeleniumTestsContextManager.getThreadContext().getExplicitWaitTimeout()); } /** * Indicates whether or not the element is enabled in the browser. * * @return */ @Override @ReplayOnError public boolean isEnabled() { findElement(false, false); return getRealElementNoSearch().isEnabled(); } /** * Indicates whether or not the element is selected in the browser. * * @return */ @Override @ReplayOnError public boolean isSelected() { findElement(false, false); return getRealElementNoSearch().isSelected(); } /** * Whether or not the indicated text is contained in the element's getText() * attribute. * * @param text * * @return */ public boolean isTextPresent(String pattern) { String text = getText(); return text != null && (text.contains(pattern) || text.matches(pattern)); } /** * @deprecated (due to selenium Mouse deprecation) Forces a mouseDown event on * the WebElement. */ @Deprecated public void mouseDown() { logger.error("use 'new Actions(driver).moveToElement(element).click().perform();' instead"); } /** * @deprecated (due to selenium Mouse deprecation) Forces a mouseOver event on * the WebElement. */ @Deprecated public void mouseOver() { logger.error("use 'new Actions(driver).moveToElement(element).click().perform();' instead"); } /** * Forces a mouseOver event on the WebElement using simulate by JavaScript way * for some dynamic menu. */ @ReplayOnError(waitAfterAction = true) public void simulateMouseOver() { findElement(true); // search element first because we want it to be visible String mouseOverScript = "if(document.createEvent){var evObj = document.createEvent('MouseEvents');evObj.initEvent('mouseover', true, false); arguments[0].dispatchEvent(evObj);} else if(document.createEventObject) { arguments[0].fireEvent('onmouseover');}"; executeScript(mouseOverScript, getRealElementNoSearch()); } @Override public void sendKeys(CharSequence... keysToSend) { sendKeys(true, keysToSend); } public void sendKeys(boolean blurAfter, CharSequence... keysToSend) { // Appium seems to clear field before writing boolean clearField = SeleniumTestsContextManager.getThreadContext().getTestType().family() != TestType.APP; sendKeys(clearField, blurAfter, keysToSend); } protected void blur() { if (SeleniumTestsContextManager.isWebTest() && "input".equalsIgnoreCase(getRealElementNoSearch().getTagName())) { try { executeScript("arguments[0].blur();", getRealElementNoSearch()); } catch (Exception e) { logger.error("Error doing 'blur'", e); } } } /** * Wait few time between keys typing * @param keysToSend * @throws InterruptedException */ @ReplayOnError(waitAfterAction = true) public void sendKeysAction(long duration, CharSequence... keysToSend) { findElement(true); Actions send = new Actions(getDriver()).moveToElement(getRealElementNoSearch()).click(); for (CharSequence word : keysToSend) { for (int i = 0; i < word.length(); i++) { char extractLetter = word.charAt(i); String letter = String.valueOf(extractLetter); send = send.sendKeys(letter).pause(duration); } } send.perform(); } /** * Send keys through composite actions /!\ does not clear text before and no * blur after * * @param keysToSend */ @ReplayOnError(waitAfterAction = true) public void sendKeysAction(CharSequence... keysToSend) { findElement(true); new Actions(getDriver()).sendKeys(getRealElementNoSearch(), keysToSend).build().perform(); } /** * Send keys using real keyboard * * @param keysToSend */ public void sendKeysKeyboard(CharSequence... keysToSend) { clickMouse(); for (CharSequence keys : keysToSend) { CustomEventFiringWebDriver.writeToDesktop(keys.toString(), SeleniumTestsContextManager.getThreadContext().getRunMode(), SeleniumTestsContextManager.getThreadContext().getSeleniumGridConnector()); } } /** * Sends the indicated CharSequence to the WebElement. * * @param clear if true, clear field before writing * @param blurAfter if true, do blur() after sendKeys has been done * @param keysToSend write this text */ @ReplayOnError(waitAfterAction = true) public void sendKeys(boolean clear, boolean blurAfter, CharSequence... keysToSend) { findElement(true); if (clear) { getRealElementNoSearch().clear(); } getRealElementNoSearch().sendKeys(keysToSend); if (blurAfter) { blur(); } } @Override @ReplayOnError public void clear() { findElement(true); getRealElementNoSearch().clear(); } /** * Method, which should never be used. */ protected void sleep(int waitTime) throws InterruptedException { Thread.sleep(waitTime); } /** * Returns string matching the pattern * * @param pattern pattern to find in element text or one of its attribute * @param attributeName name of the attribute to look for * @return found string */ @ReplayOnError public String findPattern(Pattern pattern, String attributeName) { findElement(false, false); String attributeValue; if ("text".equals(attributeName)) { attributeValue = getRealElementNoSearch().getText(); } else { attributeValue = getRealElementNoSearch().getAttribute(attributeName); } Matcher matcher = pattern.matcher(attributeValue); if (matcher.matches() && matcher.groupCount() > 0) { return matcher.group(1); } return ""; } /** * Returns URL present in one of the element attributes * * @param attributeName attribute name in which we should look at. Give "text" * to search in value * @return the found link */ public String findLink(String attributeName) { // link String link = findPattern(Pattern.compile(".*(http://.+?)'\"?.*"), attributeName); if (!"".equals(link)) { return link; } // link with simple quotes link = findPattern(Pattern.compile(".*(http://.+?)\"'?.*"), attributeName); if (!"".equals(link)) { return link; } // no quotes return findPattern(Pattern.compile(".*(http://.*)"), attributeName); } /** * Converts the Type, Locator and LabelElement attributes of the HtmlElement * into a readable and report-friendly string. * * @return */ public String toHTML() { return getClass().getSimpleName().toLowerCase() + " " + getLabel() + ",: " + getBy().toString() + ""; } /** * Returns a friendly string, representing the HtmlElement's Type, LabelElement * and Locator. */ @Override public String toString() { String elDescr = getClass().getSimpleName() + " " + getLabel() + ", by={" + getBy().toString() + "}"; if (parent != null) { elDescr += ", sub-element of " + parent.toString(); } return elDescr; } /** * Method created for test purpose only */ @ReplayOnError public void doNothing() { // do nothing } /* * Methods for mobile actions only */ /** * findElement returns a EventFiringWebElement which is not compatible with * MobileElement Get the unerlying element and return it */ private WebElement getUnderlyingElement(WebElement localElement) { if (localElement.getClass().getName().contains("EventFiringWebElement")) { try { Method getWrappedElementMethod = localElement.getClass().getDeclaredMethod("getWrappedElement"); getWrappedElementMethod.setAccessible(true); return (WebElement) getWrappedElementMethod.invoke(localElement); } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { throw new DriverExceptions("cannot get wrapped Element", e); } } else { return localElement; } } @ReplayOnError public Point getCenter() { try { checkForMobile(); return ((MobileElement) getUnderlyingElement(getRealElementNoSearch())).getCenter(); } catch (ScenarioException e) { Rectangle rectangle = getRect(); return new Point(rectangle.x + rectangle.width / 2, rectangle.y + rectangle.height / 2); } } @ReplayOnError(waitAfterAction = true) public void pinch() { PerformsTouchActions performTouchActions = checkForMobile(); MobileElement mobElement = (MobileElement) getUnderlyingElement(getRealElementNoSearch()); // code taken from appium MultiTouchAction multiTouch = new MultiTouchAction(performTouchActions); Point upperLeft = mobElement.getLocation(); Point center = mobElement.getCenter(); int yOffset = center.getY() - upperLeft.getY(); TouchAction action0 = createTouchAction() .press(ElementOption.element(mobElement, center.getX(), center.getY() - yOffset)) .moveTo(ElementOption.element(mobElement)).release(); TouchAction action1 = createTouchAction() .press(ElementOption.element(mobElement, center.getX(), center.getY() + yOffset)) .moveTo(ElementOption.element(mobElement)).release(); multiTouch.add(action0).add(action1).perform(); } /** * Convenience method for swiping on the given element to the given direction * * @param xOffset X offset from the top-left corner of the element * @param yOffset Y offset from the top-left corner of the element * @param xMove Movement amplitude on x axis * @param yMove Movement amplitude on y axis */ @ReplayOnError(waitAfterAction = true) public void swipe(int xOffset, int yOffset, int xMove, int yMove) { MobileElement mobElement = (MobileElement) getUnderlyingElement(getRealElementNoSearch()); createTouchAction().press(ElementOption.element(mobElement, xOffset, yOffset)).waitAction() .moveTo(ElementOption.element(mobElement, xMove, yMove)).release().perform(); } /** * Tap with X fingers on screen * * @param fingers number of fingers to tap with * @param duration duration in ms to wait before releasing */ @ReplayOnError(waitAfterAction = true) public void tap(int fingers, int duration) { PerformsTouchActions performTouchActions = checkForMobile(); MobileElement mobElement = (MobileElement) getUnderlyingElement(getRealElementNoSearch()); // code from appium MultiTouchAction multiTouch = new MultiTouchAction(performTouchActions); for (int i = 0; i < fingers; i++) { TouchAction tap = createTouchAction(); multiTouch.add(tap.press(ElementOption.element(mobElement)) .waitAction(WaitOptions.waitOptions(Duration.ofMillis(duration))).release()); } multiTouch.perform(); } @ReplayOnError(waitAfterAction = true) public void zoom() { PerformsTouchActions performTouchActions = checkForMobile(); MobileElement mobElement = (MobileElement) getUnderlyingElement(getRealElementNoSearch()); MultiTouchAction multiTouch = new MultiTouchAction(performTouchActions); Point upperLeft = mobElement.getLocation(); Point center = mobElement.getCenter(); int yOffset = center.getY() - upperLeft.getY(); TouchAction action0 = createTouchAction().press(PointOption.point(center.getX(), center.getY())) .moveTo(ElementOption.element(mobElement, center.getX(), center.getY() - yOffset)).release(); TouchAction action1 = createTouchAction().press(PointOption.point(center.getX(), center.getY())) .moveTo(ElementOption.element(mobElement, center.getX(), center.getY() + yOffset)).release(); multiTouch.add(action0).add(action1).perform(); } /** * Wait element to present using Explicit Waits with default * EXPLICIT_WAIT_TIME_OUT = 15 seconds. */ public void waitForPresent() { waitForPresent(SeleniumTestsContextManager.getThreadContext().getExplicitWaitTimeout()); } /** * Wait element not to be present using Explicit Waits with default * EXPLICIT_WAIT_TIME_OUT = 15 seconds. */ public void waitForNotPresent() { waitForNotPresent(SeleniumTestsContextManager.getThreadContext().getExplicitWaitTimeout()); } /** * Wait element to be visible using Explicit Waits with default * EXPLICIT_WAIT_TIME_OUT = 15 seconds. */ public void waitForVisibility() { waitForVisibility(SeleniumTestsContextManager.getThreadContext().getExplicitWaitTimeout()); } /** * Wait element not to be visible using Explicit Waits with default * EXPLICIT_WAIT_TIME_OUT = 15 seconds. */ public void waitForInvisibility() { waitForInvisibility(SeleniumTestsContextManager.getThreadContext().getExplicitWaitTimeout()); } public void setImplicitWaitTimeout(final double timeout) { try { getDriver().manage().timeouts().implicitlyWait((int) timeout, TimeUnit.SECONDS); } catch (Exception ex) { logger.error(ex); } } public void setImplicitWaitTimeout(int timeout, TimeUnit unit) { try { getDriver().manage().timeouts().implicitlyWait(timeout, unit); } catch (Exception ex) { logger.error(ex); } } /** * Wait element to present using Explicit Waits with timeout in seconds. This * method is used for special element which needs long time to present. This * method is replayed because it may fail if frame is not present at start. The * replay is not done if TimeOutException raises (see ReplayAction class) * * @param timeout timeout in seconds. Set a minimal value of 1 sec to avoid not * searching for element */ @ReplayOnError public void waitForPresent(int timeout) { // refresh driver setDriver(updateDriver()); try { setImplicitWaitTimeout(510, TimeUnit.MILLISECONDS); Clock clock = Clock.systemUTC(); Instant end = clock.instant().plusSeconds(Math.max(1, timeout)); while (end.isAfter(clock.instant())) { try { WebElement elt = new WebDriverWait(getDriver(), 0) .ignoring(ConfigurationException.class, ScenarioException.class) .until(ExpectedConditionsC.presenceOfElementLocated(this)); outlineElement(elt); return; } catch (TimeoutException e) { // nothing to do } } throw new TimeoutException("Element is not present", new NoSuchElementException(toString())); } finally { setImplicitWaitTimeout(SeleniumTestsContextManager.getThreadContext().getImplicitWaitTimeout()); } } public void waitFor(int timeout, ExpectedCondition condition) { try { setImplicitWaitTimeout(510, TimeUnit.MILLISECONDS); Clock clock = Clock.systemUTC(); Instant end = clock.instant().plusSeconds(Math.max(1, timeout)); while (end.isAfter(clock.instant())) { try { new WebDriverWait(getDriver(), timeout).ignoring(ConfigurationException.class, ScenarioException.class) .until(condition); return; } catch (TimeoutException e) { // nothing to do } } throw new TimeoutException("Element is not present", new NoSuchElementException(toString())); } finally { setImplicitWaitTimeout(SeleniumTestsContextManager.getThreadContext().getImplicitWaitTimeout()); } } public void waitForNotPresent(int timeout) { waitFor(timeout, ExpectedConditionsC.absenceOfElementLocated(this)); } public void waitForVisibility(int timeout) { waitFor(timeout, ExpectedConditions.visibilityOf(this)); } public void waitForInvisibility(int timeout) { waitFor(timeout, ExpectedConditions.invisibilityOf(this)); } public FrameElement getFrameElement() { return frameElement; } public void setFrameElement(FrameElement frameElement) { this.frameElement = frameElement; } /** * Sometimes, the frame defined for the element may change * * @param frameElement * @return */ @SuppressWarnings("unchecked") public T changeFrame(FrameElement frameElement, Class type) { setFrameElement(frameElement); return (T) this; } @Override public X getScreenshotAs(OutputType target) { findElement(); if (((HasCapabilities) getDriver()).getCapabilities().getCapability(CapabilityType.TAKES_SCREENSHOT) != null) { return getRealElementNoSearch().getScreenshotAs(target); } else { return null; } } @Override @ReplayOnError(waitAfterAction = true) public void submit() { findElement(true); getRealElementNoSearch().submit(); } @Override @ReplayOnError public Coordinates getCoordinates() { findElement(false, false); return ((Locatable) getRealElementNoSearch()).getCoordinates(); } public Map toJson() { findElement(); return ((RemoteWebElement) getUnderlyingElement(getRealElementNoSearch())).toJson(); } public HtmlElement getParent() { return parent; } public void setParent(HtmlElement parent) { this.parent = parent; } public void setBy(By by) { this.by = by; } /** * USE ONLY for testing * * @param element */ public void setElement(WebElement element) { this.element.set(element); } public Integer getElementIndex() { return elementIndex; } /** * Directly returns the real element even if it has not been searched * @return */ protected WebElement getRealElementNoSearch() { return element.get(); } /** * Returns the real web element. issue #313: Search the element if it has not * been searched before * * @return */ public WebElement getRealElement() { if (getRealElementNoSearch() == null) { findElement(); } return getRealElementNoSearch(); } /** * Change the search index of the element (its order in element list) * * @param elementIndex */ public void setElementIndex(Integer elementIndex) { this.elementIndex = elementIndex; } public String getOrigin() { return origin; } public boolean isScrollToElementBeforeAction() { return scrollToElementBeforeAction; } public void setScrollToElementBeforeAction(boolean scrollToElementBeforeAction) { this.scrollToElementBeforeAction = scrollToElementBeforeAction; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy