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

org.finra.jtaf.ewd.impl.DefaultExtWebDriver Maven / Gradle / Ivy

Go to download

ExtWebDriver is an enhancement to the WebDriver API, with features such as widget library, session management and extended functions

There is a newer version: 1.5.6
Show newest version
/*
 * (C) Copyright 2013 Java Test Automation Framework Contributors.
 *
 * 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 org.finra.jtaf.ewd.impl;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXSource;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.ccil.cowan.tagsoup.Parser;
import org.finra.jtaf.ewd.ExtWebDriver;
import org.finra.jtaf.ewd.HighlightProvider;
import org.finra.jtaf.ewd.TimeOutException;
import org.finra.jtaf.ewd.widget.IElement;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.HasCapabilities;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

import com.google.common.collect.Lists;

/**
 * DefaultExtWebDriver is the default implementation of the ExtWebDriver
 * interface to support more advanced window and frame handling on top of
 * WebDriver
 * 
 */
public class DefaultExtWebDriver implements ExtWebDriver, HighlightProvider {
	private static Logger logger = LoggerFactory.getLogger(ExtWebDriver.class
			.getPackage().getName());

	/**
	 * The default maximum time that waiting methods should wait
	 */
	private long maxRequestTimeout;

	/**
	 * The underlying WebDriver instance
	 */
	private WebDriver wd;

	/**
	 * The configuration properties for this instance
	 */
	private ClientProperties cp;

	/**
	 * State tracking whether to use JavaScript for typing actions
	 */
	private boolean useJavascriptType;

	/**
	 * State tracking whether to use JavaScript for click actions
	 */
	private boolean useJavascriptClick;

	/**
	 * State tracking whether to focus on the window when clicking
	 */
	private boolean doFocusOnClick;

	/**
	 * Whether highlighting is turned on
	 */
	private boolean isHighlight;

	/**
	 * The list of currentWindowIds when they were last stored
	 */
	private Set currentWindowIds;

	/**
	 * Tracking the frame selection hierarchy
	 */
	private FrameNode lastSelectedFrame;

	/**
	 * current session identifier
	 */
	private String sessionId;

	/**
	 * 
	 */
	private Map highlightColorMap;

	/**
	 * Constructor for ExtWebDriver
	 * 
	 */
	public DefaultExtWebDriver() {
		useJavascriptType = false;
		useJavascriptClick = false;
		doFocusOnClick = true;
		currentWindowIds = new HashSet();
	}

	@Override
	public void setWrappedDriver(WebDriver wd) {
		this.wd = wd;
	}

	/**
	 * Sets the client configuration to use
	 * 
	 * @param cp
	 *            client configuration
	 */
	public void setClientProperties(ClientProperties cp) {
		this.cp = cp;
	}

	@Override
	public void setTypeMode(boolean useJavascript) {
		useJavascriptType = useJavascript;
	}

	@Override
	public boolean isJavascriptTypeMode() {
		return useJavascriptType;
	}

	@Override
	public void setClickMode(boolean useJavascript) {
		useJavascriptClick = useJavascript;
	}

	@Override
	public boolean isJavascriptClickMode() {
		return useJavascriptClick;
	}

	@Override
	public void setFocusOnClick(boolean doFocus) {
		doFocusOnClick = doFocus;
	}

	@Override
	public boolean isFocusOnClick() {
		return doFocusOnClick;
	}

	@Override
	public void setIsHighlight(boolean isHighlight) {
		this.isHighlight = isHighlight;
	}

	@Override
	public boolean isHighlight() {
		return isHighlight;
	}

	@Override
	public void setHighlightColors(Map colorMap) {
		this.highlightColorMap = colorMap;

	}

	@Override
	public String getHighlightColor(String highlightMode) {
		return highlightColorMap.get(highlightMode.toUpperCase());
	}

	@Override
	public void open(String url) {
		wd.navigate().to(url);
	}

	@Override
	public void back() {
		wd.navigate().back();
	}

	@Override
	public void closeCurrentBrowser() {
		wd.close();
		lastSelectedFrame = null;
	}

	@Override
	public void close() {
		String browser = cp.getBrowser();
		// TODO: confirm that this is to compensate for the lack of unload
		// performed by the IEDriver and add other drivers which need this
		if (browser.equalsIgnoreCase("ie")
				|| browser.equalsIgnoreCase("iexplore")
				|| browser.equalsIgnoreCase("*iexplore")) {
			eval("window.onbeforeunload = function(e){};");
		}
		wd.quit();
		lastSelectedFrame = null;
	}

	@Override
	public void forward() {
		wd.navigate().forward();
	}

	@Override
	public void refresh() {
		wd.navigate().refresh();
	}

	@Override
	public void storeCurrentWindowIds() {
		currentWindowIds = wd.getWindowHandles();
	}

	// TODO: verify that focus is not needed on other browsers
	@Override
	public void focus() {
		if (cp.getDebugMode() == true
				&& (cp.getBrowser().equalsIgnoreCase("ie")
						|| cp.getBrowser().equalsIgnoreCase("*iexplore") || cp
						.getBrowser().equalsIgnoreCase("iexplore")))

			windowFocus();
		else if (doFocusOnClick)
			windowFocus();
	}

	/**
	 * Convenience method for {@link #focus()}
	 * 
	 */
	private void windowFocus() {
		this.eval("window.focus()");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.finra.jtaf.ewd.ExtWebDriver#selectWindow(java.lang.String) TODO:
	 * use {@link org.finra.jtaf.ewd.timer.WaitForConditionTimer}
	 */
	@Override
	public void selectWindow(String windowId) {
		long endTime = System.currentTimeMillis() + maxRequestTimeout;

		Set currentWindowHandles = wd.getWindowHandles();
		boolean found = false;
		while (!found && System.currentTimeMillis() < endTime) {
			if (currentWindowHandles.contains(windowId)) {
				found = true;
			} else {
				currentWindowHandles = wd.getWindowHandles();
			}
		}

		if (found)
			wd.switchTo().window(windowId);
		else
			throw new TimeOutException("Could not select " + windowId
					+ " within " + maxRequestTimeout + " milliseconds");
	}

	@Override
	public String selectPopupWindow() throws StaleWindowIdListException {
        if (currentWindowIds == null) {
            throw new NullPointerException(
                "WebDriver returned a null set of WindowIds to storeCurrentWindowIds()");
        }

        String windowId = null;

		Set windowIds = null;
		long endTime = System.currentTimeMillis() + maxRequestTimeout;
		boolean found = false;
		while (!found && System.currentTimeMillis() < endTime) {
			windowIds = wd.getWindowHandles();
			if (windowIds.size() == (currentWindowIds.size() + 1)) {
				windowIds.removeAll(currentWindowIds);
				if (windowIds.size() != 1) {
					throw new StaleWindowIdListException(
							"Invalid set of current window IDs",
							Lists.newArrayList(currentWindowIds),
							Lists.newArrayList(windowIds));
				}
				windowId = windowIds.iterator().next();
				selectWindow(windowId);
				found = true;
			}
		}

		if (!found) {
			throw new StaleWindowIdListException(
					"Must set current window IDs by caling storeCurrentWindowIds() before using this function",
					Lists.newArrayList(currentWindowIds), Lists
							.newArrayList(windowIds));
		}
		return windowId;
	}

	@Override
	public String[] getAllWindowIds() {
		Object[] windowIds = wd.getWindowHandles().toArray();
		String[] windowIdStringArray = new String[windowIds.length];
		int index = 0;
		for (Object o : windowIds) {
			windowIdStringArray[index] = (String) o;
			index++;
		}

		return windowIdStringArray;
	}

	/**
	 * Returns the current window handle ID
	 * 
	 * @return the window handle ID
	 */
	@Override
	public String getWindowId() {
		return wd.getWindowHandle();
	}

	/**
	 * Maximizes the browser window
	 */
	@Override
	public void currentWindowMaximize() {
		wd.manage().window().maximize();
	}

	/**
	 * Scrolls the current browser window to specific position
	 * 
	 * @param i
	 *            Horizontal position
	 * @param j
	 *            Vertical position
	 */
	@Override
	public void windowScroll(int i, int j) {
		eval("window.scroll(" + i + "," + j + ");");
	}

	/**
	 * Scrolls the current browser by specific amount
	 * 
	 * @param i
	 *            Horizontal scroll amount
	 * @param j
	 *            Vertical scroll amount
	 */
	@Override
	public void windowScrollBy(int i, int j) {
		eval("window.scrollBy(" + i + "," + j + ");");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.finra.jtaf.ewd.ExtWebDriver#eval(java.lang.String)
	 * 
	 * TODO: use {@link org.finra.jtaf.ewd.timer.WaitForConditionTimer}
	 */
	@Override
	public void eval(String javaScript) {
		try {
			// TODO: add configuration for JavaScript executor
			((JavascriptExecutor) wd).executeScript(javaScript);

			// TODO: catch specific exceptions. If wd is not a JavaScript
			// executor, don't bother waiting.
		} catch (Exception e) {
			long time = System.currentTimeMillis() + 2000;
			boolean success = false;
			while (!success && System.currentTimeMillis() < time) {
				try {
					((JavascriptExecutor) wd).executeScript(javaScript);
					success = true;
				} catch (Exception e2) {
					try {
						Thread.sleep(500);
					} catch (InterruptedException e1) {
						// TODO: log
					}
					e = e2;
				}
			}

			if (!success) {
				// TODO: use specific exception type(s) for eval issues
				throw new RuntimeException(e);
			}
		}
	}

	@Override
	public String getHtmlSource() {
		selectLastFrame();
		return wd.getPageSource();
	}

	@Override
	public Map getGeneratedHtmlSource() {
		try {

			if (lastSelectedFrame != null) {
				wd.switchTo().defaultContent();
			}

			FrameNode rootNode = new FrameNode();
			return getGeneratedHtmlSourceRecursive(rootNode, "FRAME[root]");

		} catch (Exception e) {
			// TODO: log
			return new HashMap();
		} finally {
            doSelectLastFrame();
		}
	}

	/**
	 * Gets the current html source from the dom for the every frame in the
	 * current window recursively
	 * 
	 * @param currentFrame
	 *            the current FrameNode
	 * @param currFrameId
	 *            the locator of the current frame
	 * @return a map of each frame locator to the generated source
	 * 
	 * @see #getGeneratedHtmlSource() TODO: check/enforce currFrameId format
	 */
	private Map getGeneratedHtmlSourceRecursive(
			FrameNode currentFrame, String currFrameId) throws Exception {

		Map frames = new HashMap();

		if (!currentFrame.isRoot()) {
			wd.switchTo().defaultContent();

			Stack framesToSelect = new Stack();
			FrameNode currFrame = currentFrame;
			while (currFrame.getParent() != null) {
				framesToSelect.push(currFrame);
				currFrame = currFrame.getParent();
			}

			while (!framesToSelect.isEmpty()) {
				FrameNode fn = framesToSelect.pop();
				wd.switchTo().frame(fn.getFrame());
			}
		} else {
			wd.switchTo().defaultContent();
		}

		// Add current frame

		frames.put(currFrameId, wd.getPageSource());

		int iframeCount = wd.findElements(By.xpath("//iframe")).size();
		if (iframeCount == 0) {
			return frames;
		}
		for (int i = 1; i <= iframeCount; i++) {
			if (!currentFrame.isRoot()) {
				wd.switchTo().defaultContent();

				Stack framesToSelect = new Stack();
				FrameNode currFrame = currentFrame;
				while (currFrame.getParent() != null) {
					framesToSelect.push(currFrame);
					currFrame = currFrame.getParent();
				}

				while (!framesToSelect.isEmpty()) {
					FrameNode fn = framesToSelect.pop();
					wd.switchTo().frame(fn.getFrame());
				}
			} else {
				wd.switchTo().defaultContent();
			}

            FrameNode nextFrame = new FrameNode(currentFrame, By.xpath("(//iframe)[" + i + "]"), this.getWrappedDriver().findElement(By.xpath("(//iframe)[" + i + "]")));
			String nextFrameId = currFrameId.substring(0,
					currFrameId.length() - 1) + "-" + i + "]";

			// Recursively add next frames
			frames.putAll(getGeneratedHtmlSourceRecursive(nextFrame,
					nextFrameId));
		}

		return frames;
	}

    @Override
	public void selectFrame(IElement element) throws Exception {
		try {
			WebElement frameElement = element.getWebElement();
			wd.switchTo().frame(frameElement);

			if (lastSelectedFrame != null) {
				FrameNode parentNode = lastSelectedFrame;
				lastSelectedFrame = new FrameNode(parentNode, element.getByLocator(),
						frameElement);
			} else {
				FrameNode parentNode = new FrameNode();
				lastSelectedFrame = new FrameNode(parentNode, element.getByLocator(),
						frameElement);
			}
			// TODO: look for a specific exception
		} catch (Exception e) {
			wd.switchTo().defaultContent();

			if (lastSelectedFrame == null) {
				WebElement frameElement = element.getWebElement();
				wd.switchTo().frame(frameElement);

				FrameNode parentNode = new FrameNode();
				lastSelectedFrame = new FrameNode(parentNode, element.getByLocator(),
						frameElement);
			} else {
				Stack framesToSelect = new Stack();
				FrameNode currFrame = lastSelectedFrame;
				while (currFrame.getParent() != null) {
					framesToSelect.push(currFrame);
					currFrame = currFrame.getParent();
				}

				while (!framesToSelect.isEmpty()) {
					FrameNode fn = framesToSelect.pop();
					wd.switchTo().frame(fn.getFrame());
				}
			}
		}
	}

	/**
	 * Selects the top most frame
	 */
	@Override
	public void unselectFrame() {
		wd.switchTo().defaultContent();
		lastSelectedFrame = null;
	}

	@Override
	public void selectLastFrame() {
		if (!cp.shouldSelectLastFrame())
			return;

		doSelectLastFrame();
	}

    private void doSelectLastFrame() {
        try {
            if (lastSelectedFrame != null) {
                Stack framesToSelect = new Stack();
                FrameNode currFrame = lastSelectedFrame;
                while (currFrame.getParent() != null) {
                    framesToSelect.push(currFrame.getParent());
                    currFrame = currFrame.getParent();
                }

                while (!framesToSelect.isEmpty()) {
                    FrameNode fn = framesToSelect.pop();
                    if (!fn.isRoot()) {
                        wd.switchTo().frame(fn.getFrame());
                    } else {
                        wd.switchTo().defaultContent();
                    }
                }

                try {
                    wd.switchTo().frame(lastSelectedFrame.getFrame());
                    // TODO: look for a specific exception
                } catch (Exception e) {
                    // TODO: log
                }
            }
            // TODO: look for a specific exception
        } catch (Exception e) {
            logger.info("Unable to select the frame", e);
        }
    }

	@Override
	public String evaluateXpath(String xpath) throws Exception {
		XPathFactory xpathFac = XPathFactory.newInstance();
		XPath theXpath = xpathFac.newXPath();

		String html = getHtmlSource();
		html = html.replaceAll(">\\s+<", "><");
		InputStream input = new ByteArrayInputStream(html.getBytes(Charset.forName("UTF-8")));

		XMLReader reader = new Parser();
		reader.setFeature(Parser.namespacesFeature, false);
		Transformer transformer = TransformerFactory.newInstance()
				.newTransformer();

		DOMResult result = new DOMResult();
		transformer.transform(new SAXSource(reader, new InputSource(input)),
				result);

		Node htmlNode = result.getNode(); // This code gets a Node from the
											// result.
		return (String) theXpath.evaluate(xpath, htmlNode,
				XPathConstants.STRING);
	}

	@Override
	public void confirmNativeDialog() throws Exception {
		Alert alert = wd.switchTo().alert();
		alert.accept();
	}

	@Override
	public void cancelNativeDialog() {
		Alert alert = wd.switchTo().alert();
		alert.dismiss();
	}

	@Override
	public String getNativeDialogText() {
		Alert alert = wd.switchTo().alert();
		return alert.getText();
	}

	// TODO: determine if there is a better option than returning null
	@Override
	public String getBrowserName() {
		if (wd != null) {
			Capabilities capabilities = ((HasCapabilities) wd)
					.getCapabilities();
			if (capabilities != null) {
				return capabilities.getBrowserName();
			}
			return null;
		}
		return null;
	}

	// TODO: determine if there is a better option than returning null
	@Override
	public String getBrowserVersion() {
		if (wd != null) {
			Capabilities capabilities = ((HasCapabilities) wd)
					.getCapabilities();
			if (capabilities != null) {
				return capabilities.getVersion();
			}
			return null;
		}
		return null;
	}

	/**
	 * 
	 * TreeNode with parent references only to represent the path for a specific
	 * child frame
	 * 
	 */
	private static class FrameNode {

		private boolean isRoot;
		private final FrameNode parentNode;
		private final By iframeLocator;
		private final WebElement frame;

		/**
		 * Default constructor for FrameNode
		 * 
		 */
		FrameNode() {
			this.setRoot(true);
			this.parentNode = null;
			this.iframeLocator = null;
			this.frame = null;
		}

		/**
		 * Specific constructor for FrameNode
		 * 
		 * @param parentNode
		 *            The parent FrameNode if it exists
		 * @param iframeLocator
		 *            The locator of the frame element
		 * @param frame
		 *            the WebElement frame itself
		 */
		FrameNode(FrameNode parentNode, By iframeLocator, WebElement frame) {
			this.setRoot(false);
			this.parentNode = parentNode;
			this.iframeLocator = iframeLocator;
			this.frame = frame;
		}

		/**
		 * Gets parent FrameNode
		 * 
		 * @return parent FrameNode
		 */
		FrameNode getParent() {
			return parentNode;
		}

		/**
		 * Gets the frame
		 * 
		 * @return WebElement representing the frame
		 */
		WebElement getFrame() {
			return frame;
		}

		/**
		 * Gets the locator for the frame
		 *
		 * @return String representing the locator of the frame element
		 */
		By getFrameLocator() {
			return iframeLocator;
		}

		/**
		 * Is the FrameNode representing the root of the page
		 * 
		 * @return the FrameNode the root
		 */
		boolean isRoot() {
			return isRoot;
		}

		/**
		 * Sets the FrameNode as the root
		 * 
		 * @param isRoot
		 *            is the FrameNode the root
		 */
		void setRoot(boolean isRoot) {
			this.isRoot = isRoot;
		}

		@Override
		public boolean equals(Object o) {
			if (o instanceof FrameNode
					&& ((FrameNode) o).getFrameLocator().equals(
                    this.getFrameLocator())) {
				return true;
			}
			return false;
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result
					+ ((iframeLocator == null) ? 0 : iframeLocator.hashCode());
			result = prime * result
					+ ((parentNode == null) ? 0 : parentNode.hashCode());
			return result;
		}
	}
	
	@Override
	public WebElement findElement(By arg0) {
		return wd.findElement(arg0);
	}

	@Override
	public List findElements(By arg0) {
		return wd.findElements(arg0);
	}

	@Override
	public void get(String arg0) {
		wd.get(arg0);
	}

	@Override
	public String getCurrentUrl() {
		return wd.getCurrentUrl();
	}

	@Override
	public String getPageSource() {
		return wd.getPageSource();
	}

	@Override
	public String getTitle() {
		return wd.getTitle();
	}

	@Override
	public String getWindowHandle() {
		return wd.getWindowHandle();
	}

	@Override
	public Set getWindowHandles() {
		return wd.getWindowHandles();
	}

	@Override
	public Options manage() {
		return wd.manage();
	}

	@Override
	public Navigation navigate() {
		return wd.navigate();
	}

	@Override
	public void quit() {
		wd.quit();
	}

	@Override
	public TargetLocator switchTo() {
		return wd.switchTo();
	}

	@Override
	public void setMaxRequestTimeout(String timeout) {
		this.maxRequestTimeout = Long.parseLong(timeout);
	}

	@Override
	public long getMaxRequestTimeout() {
		return maxRequestTimeout;
	}

	@Override
	public WebDriver getWrappedDriver() {
		return wd;
	}

	@Override
	public int getXpathCount(String string) {
		return wd.findElements(By.xpath(string)).size();
	}

	@Override
	public void setSessionId(String id) {
		this.sessionId = id;
	}

	@Override
	public String getSessionId() {
		return this.sessionId;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy