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

org.paxml.selenium.rc.SeleniumUtils Maven / Gradle / Ivy

The newest version!
/**
 * This file is part of PaxmlSelenium.
 *
 * PaxmlSelenium is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * PaxmlSelenium is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with PaxmlSelenium.  If not, see .
 */
package org.paxml.selenium.rc;

import java.util.UUID;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.paxml.annotation.Util;
import org.paxml.core.Context;
import org.paxml.core.PaxmlRuntimeException;
import org.paxml.el.IUtilFunctionsFactory;

import com.thoughtworks.selenium.DefaultSelenium;

/**
 * Selenium utils.
 * 
 * @author Xuetao Niu
 * 
 */
@Util("selenium")
public class SeleniumUtils implements IUtilFunctionsFactory {
	private static final Log log = LogFactory.getLog(SeleniumUtils.class);
	private static final FileServer fileServer = new FileServer();

	private static final String WAIT_FOR_AJAX_START_JS = "typeof(window.jQuery)!='function' || window.jQuery.active!=0";
	private static final String WAIT_FOR_AJAX_STOP_JS = "typeof(window.jQuery)!='function' || window.jQuery.active==0";

	private DefaultSelenium selenium;
	private XSelenium as;

	public DefaultSelenium getSelenium(){
		return selenium;
	}
	
	/**
	 * {@inheritDoc}
	 */
	public SeleniumUtils getUtilFunctions(Context context) {
		as = SeleniumTag.getSelenium(context);
		selenium = as.getSelenium();
		return this;
	}
	
	/**
	 * {@inheritDoc}
	 */
	public Class getXpathUtilFunctions(Context context) {
		return null;
	}

	/**
	 * Set the selenium working speed.
	 * 
	 * @param speed
	 *            pause in ms between each operation
	 */
	public void setSpeed(long speed) {
		log.trace("Setting selenium speed to " + speed + " ms");
		selenium.setSpeed(speed + "");
	}

	/**
	 * Create a cookie.
	 * 
	 * @param nameValuePair
	 *            the cookie pair
	 * @param optionsString
	 *            the option string
	 */
	public void createCookie(String nameValuePair, String optionsString) {
		selenium.createCookie(nameValuePair, optionsString);
	}

	/**
	 * Get cookie by name.
	 * 
	 * @param name
	 *            the name
	 * @return the cookie value
	 */
	public String getCookieByName(String name) {
		return selenium.getCookieByName(name);
	}

	/**
	 * Wait till a condition is met.
	 * 
	 * @param script
	 *            the javascript as condition. Returning true means met,
	 *            otherwise not.
	 * @param timeout
	 *            the timeout in ms
	 * 
	 */
	public void waitForCondition(String script, long timeout) {
		waitForCondition(script, timeout, true);
	}

	/**
	 * Wait till a condition is met.
	 * 
	 * @param script
	 *            the javascript as condition. Returning true means met,
	 *            otherwise not.
	 * @param timeout
	 *            the timeout in ms
	 * @param hard
	 *            true to fail if condition not met upon timeout, false to
	 *            continue anyway
	 * @return true confition met, false not
	 */
	public boolean waitForCondition(String script, long timeout, boolean hard) {
		if (log.isDebugEnabled()) {
			log.debug("Wait max " + timeout + " ms for condition: " + script);
		}
		try {
			selenium.waitForCondition(script, timeout + "");
		} catch (Exception e) {
			if (hard) {
				throw new PaxmlRuntimeException("Wait for javascript condition failed, because: " + e.getMessage(), e);
			} else {
				return false;
			}
		}
		return true;
	}

	/**
	 * Wait for an element to be present.
	 * 
	 * @param locator
	 *            the locator to the element
	 * @param timeout
	 *            the timeout in ms
	 * @param checkInterval
	 *            the check interval in ms
	 * @param hard
	 *            true to fail if condition not met upon timeout, false to
	 *            continue anyway
	 * 
	 */
	public void waitTillPresent(String locator, long timeout, long checkInterval) {
		waitTillPresent(locator, timeout, checkInterval, true);
	}

	/**
	 * Wait for an element to be present.
	 * 
	 * @param locator
	 *            the locator to the element
	 * @param timeout
	 *            the timeout in ms
	 * @param checkInterval
	 *            the check interval in ms
	 * @param hard
	 *            true to fail if condition not met upon timeout, false to
	 *            continue anyway
	 * @return true the element is present, false not
	 */
	public boolean waitTillPresent(String locator, long timeout, long checkInterval, boolean hard) {
		if (timeout < 0) {
			timeout = as.getWaitForTimeout();
		}
		if (checkInterval < 0) {
			checkInterval = as.getWaitForCheckInterval();
		}

		final long pause = checkInterval < timeout ? checkInterval : timeout;
		final long max = System.currentTimeMillis() + timeout;
		if (log.isDebugEnabled()) {
			log.debug("Waiting max " + timeout + " ms (with check interval " + pause + " ms) for this element to appear: " + locator);
		}
		while (!isPresent(locator)) {

			try {
				Thread.sleep(pause);
			} catch (InterruptedException e) {
				throw new PaxmlRuntimeException(e);
			}
			if (isPresent(locator)) {
				return true;
			}
			if (System.currentTimeMillis() >= max) {
				if (hard) {
					throw new PaxmlRuntimeException("Timeout after " + timeout + " ms waiting for this element to be present: " + locator);
				} else {
					return false;
				}
			}
		}
		return true;
	}

	/**
	 * Wait for element to be visible.
	 * 
	 * @param locator
	 *            the locator to the element
	 * @param timeout
	 *            the timeout in ms
	 * @param checkInterval
	 *            the check interval in ms
	 * 
	 * 
	 */
	public void waitTillVisible(String locator, long timeout, long checkInterval) {
		waitTillVisible(locator, timeout, checkInterval, true);
	}

	/**
	 * Wait for element to be visible.
	 * 
	 * @param locator
	 *            the locator to the element
	 * @param timeout
	 *            the timeout in ms
	 * @param checkInterval
	 *            the check interval in ms
	 * @param hard
	 *            true to fail if condition not met upon timeout, false to
	 *            continue anyway
	 * @return true visible, false not
	 */
	public boolean waitTillVisible(String locator, long timeout, long checkInterval, boolean hard) {
		if (timeout < 0) {
			timeout = as.getWaitForTimeout();
		}
		if (checkInterval < 0) {
			checkInterval = as.getWaitForCheckInterval();
		}

		final long pause = checkInterval < timeout ? checkInterval : timeout;
		final long max = System.currentTimeMillis() + timeout;
		if (log.isDebugEnabled()) {
			log.debug("Waiting max " + timeout + " ms (with check interval " + pause + " ms) for this element to be visible: " + locator);
		}
		while (!isVisible(locator)) {

			try {
				Thread.sleep(pause);
			} catch (InterruptedException e) {
				throw new PaxmlRuntimeException(e);
			}
			if (isVisible(locator)) {
				return true;
			}
			if (System.currentTimeMillis() >= max) {
				if (hard) {
					throw new PaxmlRuntimeException("Timeout after " + timeout + " ms waiting for this element to be visible: " + locator);
				} else {
					return false;
				}
			}
		}
		return true;

	}

	/**
	 * Type into element.
	 * 
	 * @param locator
	 *            the locator
	 * @param value
	 *            the value to type
	 */
	public void type(String locator, String value) {
		if (value == null) {
			return;
		}
		String tlocator = getLocator(locator);

		selenium.type(tlocator, value);
		// This is the trick. Ajax will fire when you will leave the field and
		// not during typing
		// That was the problem!
		fireEvent(tlocator, "blur");
		// waitForAjaxRequestsStop(getAjaxTimeout());

	}

	/**
	 * Fire an event on an element.
	 * 
	 * @param locator
	 *            the element locator
	 * @param event
	 *            the event name
	 */
	public void fireEvent(String locator, String event) {
		selenium.fireEvent(getLocator(locator), event);
	}

	/**
	 * Simulate key up event in an element.
	 * 
	 * @param locator
	 *            the locator to the element
	 * @param keySequence
	 *            the key sequence
	 */
	public void keyUp(String locator, String keySequence) {
		String tlocator = getLocator(locator);

		selenium.keyUp(tlocator, keySequence);
	}

	/**
	 * Simulate key down event in an element.
	 * 
	 * @param locator
	 *            the locator to the element
	 * @param keySequence
	 *            the key sequence
	 */
	public void keyDown(String locator, String keySequence) {
		String tlocator = getLocator(locator);

		selenium.keyDown(tlocator, keySequence);
	}

	/**
	 * Simulate key press event in an element.
	 * 
	 * @param locator
	 *            the locator to the element
	 * @param keySequence
	 *            the key sequence
	 */
	public void keyPress(String locator, String keySequence) {
		String tlocator = getLocator(locator);

		selenium.keyPress(tlocator, keySequence);
	}

	/**
	 * Focus in an element.
	 * 
	 * @param locator
	 *            the locator to the element
	 * 
	 */
	public void focus(String locator) {
		String tlocator = getLocator(locator);
		selenium.focus(tlocator);
	}

	/**
	 * Wait for ajax requests to start.
	 * 
	 * @param timeout
	 *            the timeout in ms
	 * @param hard
	 *            true to fail if condition not met upon timeout, false to
	 *            continue anyway
	 * @return true started, false not
	 */
	public boolean waitForAjaxRequestsStart(long timeout, boolean hard) {

		if (as.isAjaxAware()) {

			if (timeout < 0) {
				timeout = as.getAjaxTimeout();
			}

			Object js = Context.getCurrentContext().getConst("ajaxStartedConditionJs", true);

			if (js == null) {
				js = WAIT_FOR_AJAX_START_JS;
			}

			final long beginTime = System.currentTimeMillis();

			if (!this.waitForCondition(js.toString(), timeout, hard)) {
				if (log.isDebugEnabled()) {
					log.debug("Timeout after " + timeout + " ms waiting for js: " + js);
				}
				return false;
			}

			if (log.isDebugEnabled()) {
				log.debug("Ajax call took " + (System.currentTimeMillis() - beginTime) + " ms to start");
			}

		}
		return true;

	}

	/**
	 * Wait for ajax requests to stop.
	 * 
	 * @param timeout
	 *            the timeout in ms
	 * @param hard
	 *            true to fail if condition not met upon timeout, false to
	 *            continue anyway
	 * @return true stopped, false not
	 */
	public boolean waitForAjaxRequestsStop(long timeout, boolean hard) {
		if (as.isAjaxAware()) {
			if (timeout < 0) {
				timeout = as.getAjaxTimeout();
			}
			Object js = Context.getCurrentContext().getConst("ajaxStoppedConditionJs", true);
			if (js == null) {
				js = WAIT_FOR_AJAX_STOP_JS;
			}
			final long beginTime = System.currentTimeMillis();

			if (!this.waitForCondition(js.toString(), timeout, hard)) {
				if (log.isDebugEnabled()) {
					log.debug("Ajax did not stop after " + timeout + " ms");
				}
				return false;
			}

			if (log.isDebugEnabled()) {
				log.debug("Ajax call took " + (System.currentTimeMillis() - beginTime) + " ms to stop");

			}
			if (log.isDebugEnabled()) {
				log.debug("Waiting extra 1 second after ajax stopped for the remaining javascript to finish");
			}
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// do nothing
			}
		}
		return true;
	}

	/**
	 * Get the value of an element.
	 * 
	 * @param locator
	 *            the locator
	 * @return the value
	 */
	public String getValue(String locator) {
		String tlocator = getLocator(locator);
		log.trace("Getting value from: " + tlocator);
		String ret = selenium.getValue(tlocator);
		log.trace("Got value: " + ret);
		return ret;
	}

	/**
	 * Get the text of an element.
	 * 
	 * @param locator
	 *            the locator
	 * @return the text
	 */
	public String getText(String locator) {
		String tlocator = getLocator(locator);
		log.trace("Getting text from: " + tlocator);
		String ret = selenium.getText(tlocator);
		log.trace("Got text: " + ret);
		return ret;
	}
	
	/**
	 * Check for element being present and visible.
	 * 
	 * @param locator
	 *            locator
	 * @param arguments
	 *            inserted into locator using
	 *            {@link String#format(String, Object...)}.
	 * @return true if element is present and visible
	 */
	public boolean isVisible(String locator) {
		String tlocator = getLocator(locator);

		final boolean b = isPresent(tlocator) && selenium.isVisible(tlocator);
		if (log.isDebugEnabled()) {
			log.debug("Visibility checked, this element is " + (b ? "" : "NOT ") + "visible: " + tlocator);
		}
		return b;

	}

	/**
	 * Check if an element is in the dom tree.
	 * 
	 * @param locator
	 *            the locator to the element
	 * @return true exists, false not
	 */
	public boolean isPresent(String locator) {
		String tlocator = getLocator(locator);

		final boolean b = selenium.isElementPresent(tlocator);
		if (log.isDebugEnabled()) {
			log.debug("Presence checked, this element is " + (b ? "" : "NOT ") + "present: " + locator);
		}
		return b;
	}

	/**
	 * Navigate to a page.
	 * 
	 * @param url
	 *            the url to that page
	 * @param timeout
	 *            timeout in milliseconds to wait for the complete load
	 */
	public void open(String url, long timeout) {
		if (timeout < 0) {
			timeout = as.getWaitForReloadTimeout();
		}
		if (!url.startsWith("http://") && !url.startsWith("https://")) {
			url = "http://" + url;
		}
		if (log.isInfoEnabled()) {
			log.info("Opening url with timeout " + timeout + " ms : " + url);
		}
		selenium.open(url);
		// any selenium call will change the 'pageFreshlyLoaded' flag to false.
		waitForPageToLoad(timeout);
	}

	/**
	 * Check if an element is editable.
	 * 
	 * @param locator
	 *            the locator
	 * @return true editable, false not
	 */
	public boolean isEditable(String locator) {
		return selenium.isEditable(getLocator(locator));
	}

	/**
	 * pure convenience method introduced by Bert.
	 * 
	 */
	public static String getLocator(String locator) {
		if (locator == null) {
			return null;
		}
		if (locator.startsWith("jq=")) {
			// compose a js expression using jquery
			return "dom=var jq=window.jQuery(\"" + locator.substring(3) + "\"); return jq.size()==1?jq.get(0):(jq.size() ==0 ? null: jq.toArray());";
		} else if (locator.startsWith("text=")) {
			// compose a js expression using jquery
			return "css=*:contains(\"^" + locator.substring(5) + "$\")";
		} else {
			return locator;
		}
	}

	/**
	 * Generates a partial xpath expression that matches an element whose
	 * 'attribute' attribute contains the given value. So to match <div
	 * class='foo bar'> you would say "//div[" + containingClass("class",
	 * "foo") + "]".
	 * 
	 * @param attribute
	 *            The attribute.
	 * @param value
	 *            The value.
	 * @return XPath fragment
	 */
	public String containingAttribute(String attribute, String value) {
		return "contains(concat(' ',normalize-space(@" + attribute + "),' '),' " + value + " ')";
	}

	/**
	 * Return the content of the tool tip. If any of the xpath characters being
	 * used, the locator will be passed as is. Otherwise, short notation will be
	 * replaced with long one (xpath)
	 * 
	 * @param locator
	 *            locator
	 * @return text or null if not present
	 */
	public String getToolTip(String locator) {

		String fullLocator = locator;
		if (locator.indexOf("/") != -1 || locator.indexOf("[") != -1 || locator.indexOf("@") != -1 || locator.indexOf("[") != -1 || locator.indexOf("]") != -1
				|| locator.indexOf("'") != -1) {
			fullLocator = "//div[@id='" + locator + "']/div/div[@class='error_tooltip_right']";
		}
		if (isPresent(fullLocator)) {
			String ret = getText(fullLocator);
			return ret == null ? "" : ret.trim();
		} else {
			return null;
		}
	}

	/**
	 * Figures out the right sequence of native keycodes that are required to
	 * type in character {@code ch} and presses the required keys.
	 * 
	 * @param ch
	 *            the character that needs to be typed in
	 */
	public void keyPressNative(char ch) {
		String[] codes = XSelenium.getKeyCodes(ch);
		if (codes.length == 1) {
			selenium.keyDownNative(codes[0]);
			selenium.keyUpNative(codes[0]);
		} else {
			selenium.keyDownNative(codes[0]);
			selenium.keyDownNative(codes[1]);
			selenium.keyUpNative(codes[1]);
			selenium.keyUpNative(codes[0]);
		}
	}

	void settlePageJs(long ajaxTimeout) {
		if (log.isDebugEnabled()) {
			log.debug("Waiting 1 second after page reload for the non-ajax javascript to finish");
		}
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// do nothing
		}

		if (waitForAjaxRequestsStart(XSelenium.WAIT_FOR_AJAX_START_TIMEOUT, false)) {
			waitForAjaxRequestsStop(ajaxTimeout, false);
		}

	}

	/**
	 * Wait for the page to load.
	 * 
	 * @param timeout
	 *            the timeout in ms
	 */
	public void waitForPageToLoad(long timeout) {
		if (timeout < 0) {
			timeout = as.getWaitForReloadTimeout();
		}
		if (log.isInfoEnabled()) {
			log.info("Waiting for page to reload, timeout: " + timeout + " ms");
		}
		final long start = System.currentTimeMillis();
		selenium.waitForPageToLoad(timeout + "");
		if (log.isDebugEnabled()) {
			log.debug("Page took " + (System.currentTimeMillis() - start) + " ms to load");
		}
		settlePageJs(timeout);
	}

	/**
	 * Select an option.
	 * 
	 * @param selectLocator
	 *            the locator to the select box
	 * @param optionLocator
	 *            the locator to the option
	 */
	public void select(String selectLocator, String optionLocator) {
		String slocator = getLocator(selectLocator);
		String olocator = getLocator(optionLocator);
		log.debug("SELECT: " + slocator + " = " + olocator);
		selenium.select(slocator, olocator);
		fireEvent(slocator, "blur");
		fireEvent(slocator, "change");

	}

	/**
	 * Get the select options.
	 * 
	 * @param selectLocator
	 *            the locator
	 * @return array of options
	 */
	public String[] getSelectOptions(String selectLocator) {
		String slocator = getLocator(selectLocator);
		log.debug("getSelectOptions: " + slocator + " = " + slocator);
		return selenium.getSelectOptions(slocator);
	}

	/**
	 * Click on an element.
	 * 
	 * @param locator
	 *            the element locator
	 */
	public void click(String locator) {
		String tlocator = getLocator(locator);
		if (log.isDebugEnabled()) {
			log.debug("Clicking: " + tlocator);
		}
		selenium.click(tlocator);

	}

	/**
	 * Get the confirmation.
	 * 
	 * @return the confirmation
	 */
	public String getConfirmation() {
		return selenium.getConfirmation();
	}

	/**
	 * Attach a string as file content on web page. This will automatically host
	 * the given content a logical file.
	 * 
	 * @param locator
	 *            the locator to the file input
	 * @param content
	 *            the content of the file to attach
	 * @return the url of the hosted content
	 */
	public String attachFileContent(String locator, String content) {
		if (content == null) {
			throw new PaxmlRuntimeException("No content specified for attaching");
		}
		String url = fileServer.hostIt(content, true);
		String loc = getLocator(locator);
		if (log.isInfoEnabled()) {
			log.info("Attaching file content to element, locator=" + loc + ", url=" + url);
		}
		selenium.attachFile(loc, url);
		return url;
	}

	/**
	 * Attach a file to file input on web page.
	 * 
	 * @param locator
	 *            the locator to the file input
	 * @param file
	 *            If it starts with http://, it will attach a file downloaded
	 *            from a remote server. If it does not start with http://, it
	 *            means a file found on classpath.
	 * 
	 * @return the url of given file, or the published url of the file.
	 */
	public String attachFile(String locator, String file) {
		if (StringUtils.isBlank(file)) {
			throw new PaxmlRuntimeException("No file specified for attaching");
		}

		String url = fileServer.hostIt(file, false);
		String loc = getLocator(locator);
		if (log.isInfoEnabled()) {
			log.info("Attaching file to element, locator=" + loc + ", url=" + url);
		}
		selenium.attachFile(loc, url);

		return file;
	}

	/**
	 * Switch to a different frame.
	 * 
	 * @param locator
	 *            the locator to the target frame
	 * @param wait
	 *            true to wait for the frame to be fully loaded, false not to
	 *            wait
	 * @param timeout
	 *            the timeout in ms when wait is true
	 * 
	 */
	public void selectFrame(String locator, boolean wait, long timeout) {
		locator = getLocator(locator);
		if (wait) {
			selenium.waitForFrameToLoad(locator, timeout + "");
		}
		if (log.isDebugEnabled()) {
			log.debug("Selecting frame: " + locator);
		}
		selenium.selectFrame(locator);
		if (wait) {
			settlePageJs(timeout);
		}

	}

	/**
	 * Evaluate javascript.
	 * 
	 * @return the evaluation result
	 */
	public Object eval(String js) {
		if (log.isDebugEnabled()) {
			log.debug("Evaluating javascript: " + js);
		}
		return selenium.getEval(js);
	}

	/**
	 * Open a new browser window.
	 * 
	 * @param url
	 *            the url of the new window
	 * @param windowId
	 *            the window id to assign to the new window, empty string means
	 *            to generate a unique window id.
	 * @return the windowId given, or the generated unique windowId.
	 */
	public String newWindow(String url, String windowId) {
		if (StringUtils.isEmpty(windowId)) {
			windowId = UUID.randomUUID().toString();
		}
		if (log.isInfoEnabled()) {
			log.info("Opening new window with window id: " + windowId);
		}
		selenium.openWindow(url, windowId);
		return windowId;
	}

	/**
	 * Switch to a different window.
	 * 
	 * @param windowId
	 *            the id of the window to switch to
	 */
	public void selectWindow(String windowId) {
		if (windowId == null || "null".equals(windowId)) {
			log.info("Selecting the main window");
			selenium.selectWindow(windowId);
		} else {
			if (log.isInfoEnabled()) {
				log.info("Selecting window: " + windowId);
			}
			selenium.selectWindow("name=" + windowId);
		}
	}

	/**
	 * Refresh the current page.
	 * 
	 * @param timeout
	 *            the timeout in ms, defaults to 60000 ms.
	 */
	public void refresh(long timeout) {
		if (timeout < 0) {
			timeout = as.getWaitForReloadTimeout();
		}
		if (log.isInfoEnabled()) {
			log.info("Refreshing the current page with timeout: " + timeout + " ms");
		}
		selenium.refresh();
		waitForPageToLoad(timeout);
	}

	/**
	 * Get the url of the current window.
	 * 
	 * @return the url string
	 */
	public String getCurrentUrl() {
		String url = String.valueOf(eval("window.location.href+''"));
		if (log.isDebugEnabled()) {
			log.debug("Current browser url: " + url);
		}
		return url;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy