com.qmetry.qaf.automation.ui.webdriver.QAFExtendedWebDriver.java Source code

Java tutorial

Introduction

Here is the source code for com.qmetry.qaf.automation.ui.webdriver.QAFExtendedWebDriver.java

Source

/*******************************************************************************
 * QMetry Automation Framework provides a powerful and versatile platform to author 
 * Automated Test Cases in Behavior Driven, Keyword Driven or Code Driven approach
 *                
 * Copyright 2016 Infostretch Corporation
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version.
 *
 * This program 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 General Public License for more details.
 *
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
 * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
 *
 * You should have received a copy of the GNU General Public License along with this program in the name of LICENSE.txt in the root folder of the distribution. If not, see https://opensource.org/licenses/gpl-3.0.html
 *
 * See the NOTICE.TXT file in root folder of this source files distribution 
 * for additional information regarding copyright ownership and licenses
 * of other open source software / files used by QMetry Automation Framework.
 *
 * For any inquiry or need additional information, please contact support-qaf@infostretch.com
 *******************************************************************************/

package com.qmetry.qaf.automation.ui.webdriver;

import java.lang.reflect.Proxy;
import java.net.URL;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.Rotatable;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.TouchScreen;
import org.openqa.selenium.remote.Augmenter;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.CommandExecutor;
import org.openqa.selenium.remote.DriverCommand;
import org.openqa.selenium.remote.RemoteTouchScreen;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.remote.Response;
import org.openqa.selenium.remote.ScreenshotException;
import org.openqa.selenium.remote.internal.WebElementToJsonConverter;
import org.openqa.selenium.support.ui.ExpectedConditions;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.qmetry.qaf.automation.core.ConfigurationManager;
import com.qmetry.qaf.automation.core.QAFListener;
import com.qmetry.qaf.automation.keys.ApplicationProperties;
import com.qmetry.qaf.automation.ui.WebDriverCommandLogger;
import com.qmetry.qaf.automation.ui.WebDriverTestBase;
import com.qmetry.qaf.automation.ui.JsToolkit;
import com.qmetry.qaf.automation.ui.util.QAFWebDriverExpectedConditions;
import com.qmetry.qaf.automation.ui.util.QAFWebDriverWait;
import com.qmetry.qaf.automation.ui.webdriver.CommandTracker.Stage;
import com.qmetry.qaf.automation.util.LocatorUtil;

/**
 * com.qmetry.qaf.automation.ui.webdriver.QAFWebDriver.java
 * 
 * @author chirag
 */
public class QAFExtendedWebDriver extends RemoteWebDriver implements QAFWebDriver, QAFWebDriverCommandListener {
    protected Log logger = LogFactory.getLog(getClass());
    private WebDriverCommandLogger commandLogger;
    private Set<QAFWebDriverCommandListener> listners;
    private WebDriver underLayingDriver;
    private Capabilities capabilities;

    public QAFExtendedWebDriver(URL url, Capabilities capabilities) {
        this(url, capabilities, null);
    }

    public QAFExtendedWebDriver(WebDriver driver) {
        this(driver, null);
    }

    public QAFExtendedWebDriver(URL url, Capabilities capabilities, WebDriverCommandLogger reporter) {
        super(url, capabilities);
        init(reporter);
    }

    public QAFExtendedWebDriver(CommandExecutor cmdExecutor, Capabilities capabilities,
            WebDriverCommandLogger reporter) {
        super(cmdExecutor, capabilities);
        init(reporter);
    }

    public QAFExtendedWebDriver() {
        init(null);
    }

    public QAFExtendedWebDriver(WebDriver driver, WebDriverCommandLogger reporter) {
        super();
        underLayingDriver = driver;
        setCommandExecutor(((RemoteWebDriver) driver).getCommandExecutor());
        setSessionId(((RemoteWebDriver) driver).getSessionId().toString());
        capabilities = ((RemoteWebDriver) driver).getCapabilities();
        init(reporter);

    }

    @Override
    public Capabilities getCapabilities() {
        if (capabilities == null)
            capabilities = super.getCapabilities();
        return capabilities;
    }

    public WebDriver getUnderLayingDriver() {
        if (underLayingDriver == null)
            underLayingDriver = this;
        return underLayingDriver;
    }

    private void init(WebDriverCommandLogger reporter) {
        setElementConverter(new QAFExtendedWebElement.JsonConvertor(this));
        try {
            listners = new LinkedHashSet<QAFWebDriverCommandListener>();
            commandLogger = (null == reporter) ? new WebDriverCommandLogger() : reporter;
            listners.add(commandLogger);
            String[] listners = ConfigurationManager.getBundle()
                    .getStringArray(ApplicationProperties.WEBDRIVER_COMMAND_LISTENERS.key);
            for (String listenr : listners) {
                registerListeners(listenr);
            }
            listners = ConfigurationManager.getBundle().getStringArray(ApplicationProperties.QAF_LISTENERS.key);
            for (String listener : listners) {
                try {
                    QAFListener cls = (QAFListener) Class.forName(listener).newInstance();
                    if (QAFWebDriverCommandListener.class.isAssignableFrom(cls.getClass()))
                        this.listners.add((QAFWebDriverCommandListener) cls);
                } catch (Exception e) {
                    logger.error("Unable to register class as driver listener:  " + listener, e);
                }
            }

            onInitialize(this);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected WebDriverCommandLogger getReporter() {
        return commandLogger;
    }

    public void setReporter(WebDriverCommandLogger reporter) {
        commandLogger = reporter;
    }

    @Override
    public QAFExtendedWebElement findElement(By by) {
        QAFExtendedWebElement element = (QAFExtendedWebElement) super.findElement(by);
        element.setBy(by);
        element.cacheable = true;
        return element;
    }

    /**
     * @param locator
     *            - selenium 1 type locator for example "id=eleid",
     *            "name=eleName" etc...
     * @return
     */
    public QAFWebElement findElement(String locator) {
        return ElementFactory.$(locator);
    }

    @SuppressWarnings("unchecked")
    public List<QAFWebElement> findElements(String loc) {
        return (List<QAFWebElement>) (List<? extends WebElement>) findElements(LocatorUtil.getBy(loc));
    }

    public QAFExtendedWebElement createElement(By by) {
        return new QAFExtendedWebElement(this, by);
    }

    public QAFExtendedWebElement createElement(String locator) {
        return new QAFExtendedWebElement(locator);
    }

    @SuppressWarnings("unchecked")
    public List<QAFWebElement> getElements(By by) {

        List<QAFWebElement> proxy;
        proxy = (List<QAFWebElement>) Proxy.newProxyInstance(this.getClass().getClassLoader(),
                new Class[] { List.class }, new QAFExtendedWebElementListHandler(this, by));
        return proxy;
    }

    @SuppressWarnings("unchecked")
    public void load(QAFExtendedWebElement... elements) {
        if (elements != null) {
            for (QAFExtendedWebElement element : elements) {
                final By by = element.getBy();
                element.setId(
                        ((QAFExtendedWebElement) new QAFWebDriverWait(this)
                                .ignore(NoSuchElementException.class, StaleElementReferenceException.class,
                                        RuntimeException.class)
                                .until(ExpectedConditions.presenceOfElementLocated(by))).getId());
            }
        }

    }

    @Override
    protected Response execute(String command) {
        return super.execute(command);
    }

    @Override
    protected Response execute(String driverCommand, Map<String, ?> parameters) {
        CommandTracker commandTracker = new CommandTracker(driverCommand, parameters);

        try {
            beforeCommand(this, commandTracker);
            // already handled in before command?
            if (commandTracker.getResponce() == null) {
                commandTracker.setStartTime(System.currentTimeMillis());
                commandTracker
                        .setResponce(super.execute(commandTracker.getCommand(), commandTracker.getParameters()));
                commandTracker.setEndTime(System.currentTimeMillis());
            }
            afterCommand(this, commandTracker);
        } catch (RuntimeException wde) {
            commandTracker.setException(wde);
            onFailure(this, commandTracker);

        }
        if (commandTracker.hasException()) {
            if (commandTracker.retry) {
                commandTracker
                        .setResponce(super.execute(commandTracker.getCommand(), commandTracker.getParameters()));
                commandTracker.setException(null);
                commandTracker.setEndTime(System.currentTimeMillis());
            } else {
                throw commandTracker.getException();
            }
        }
        return commandTracker.getResponce();
    }

    protected Response executeWitoutLog(String driverCommand, Map<String, ?> parameters) {
        return super.execute(driverCommand, parameters);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.openqa.selenium.TakesScreenshot#getScreenshotAs(org.openqa.selenium
     * .OutputType)
     */
    @Override
    public <X> X getScreenshotAs(OutputType<X> target) throws WebDriverException {
        Object takeScreenshot = getCapabilities().getCapability(CapabilityType.TAKES_SCREENSHOT);
        if (null == takeScreenshot || (Boolean) takeScreenshot) {
            String base64Str = execute(DriverCommand.SCREENSHOT).getValue().toString();
            return target.convertFromBase64Png(base64Str);
        }
        return null;
    }

    public <T> T extractScreenShot(WebDriverException e, OutputType<T> target) {
        if (e.getCause() instanceof ScreenshotException) {
            String base64Str = ((ScreenshotException) e.getCause()).getBase64EncodedScreenshot();
            return target.convertFromBase64Png(base64Str);
        }
        return null;
    }

    public Alert getAlert() {
        return new QAFWebDriverWait(this).until(QAFWebDriverExpectedConditions.alertPresent());
    }

    @Override
    public void afterCommand(QAFExtendedWebDriver driver, CommandTracker commandTracker) {
        commandTracker.setStage(Stage.executingAfterMethod);

        if ((listners != null) && !listners.isEmpty()) {
            for (QAFWebDriverCommandListener listener : listners) {
                listener.afterCommand(driver, commandTracker);
            }
        }

    }

    public void updateSessionId() {
        String sessionId = new WebDriverTestBase().getDriver().getSessionId().toString();

        this.setSessionId(sessionId);
        System.out.println("Current session: " + getSessionId() + " updated with:" + sessionId);
    }

    @Override
    public void beforeCommand(QAFExtendedWebDriver driver, final CommandTracker commandTracker) {
        commandTracker.setStage(Stage.executingBeforeMethod);
        if ((listners != null) && !listners.isEmpty()) {
            for (QAFWebDriverCommandListener listener : listners) {
                listener.beforeCommand(driver, commandTracker);
            }
        }
    }

    @Override
    public void onFailure(QAFExtendedWebDriver driver, CommandTracker commandTracker) {
        commandTracker.setStage(Stage.executingOnFailure);
        commandTracker.setEndTime(System.currentTimeMillis());

        if (commandTracker.getException() instanceof UnsupportedOperationException) {
            logger.warn(commandTracker.getException().getMessage());
            commandTracker.setException(null);
        }
        if (null != listners) {
            for (QAFWebDriverCommandListener listener : listners) {
                listener.onFailure(driver, commandTracker);
            }
        }
    }

    @Override
    public void onInitialize(QAFExtendedWebDriver driver) {
        if ((listners != null) && !listners.isEmpty()) {
            for (QAFWebDriverCommandListener listener : listners) {
                listener.onInitialize(driver);
            }
        }
    }

    @Override
    public void onInitializationFailure(Capabilities desiredCapabilities, Throwable t) {

    }

    private void registerListeners(String className) {
        try {
            QAFWebDriverCommandListener cls = (QAFWebDriverCommandListener) Class.forName(className).newInstance();
            listners.add(cls);
        } catch (Exception e) {
            logger.error("Unable to register listener class " + className, e);
        }
    }

    public void registerListeners(QAFWebDriverCommandListener listener) {
        listners.add(listener);

    }

    @Override
    public QAFExtendedWebElement findElementByClassName(String using) {
        return (QAFExtendedWebElement) super.findElementByClassName(using);
    }

    @Override
    public QAFExtendedWebElement findElementByCssSelector(String using) {
        return (QAFExtendedWebElement) super.findElementByCssSelector(using);
    }

    @Override
    public QAFExtendedWebElement findElementById(String using) {
        return (QAFExtendedWebElement) super.findElementById(using);
    }

    @Override
    public QAFExtendedWebElement findElementByLinkText(String using) {
        return (QAFExtendedWebElement) super.findElementByLinkText(using);
    }

    @Override
    public QAFExtendedWebElement findElementByName(String using) {
        return (QAFExtendedWebElement) super.findElementByName(using);
    }

    @Override
    public QAFExtendedWebElement findElementByPartialLinkText(String using) {
        return (QAFExtendedWebElement) super.findElementByPartialLinkText(using);
    }

    @Override
    public QAFExtendedWebElement findElementByTagName(String using) {
        return (QAFExtendedWebElement) super.findElementByTagName(using);
    }

    @Override
    public QAFExtendedWebElement findElementByXPath(String using) {
        return (QAFExtendedWebElement) super.findElementByXPath(using);
    }

    /**
     * Under evaluation only
     * 
     * @param using
     * @return
     */
    public QAFExtendedWebElement findElementBySizzleCss(String using) {
        List<QAFExtendedWebElement> elements = findElementsBySizzleCss(using);
        if (elements.size() > 0) {
            return elements.get(0);
        }
        return null;
    }

    /**
     * Under evaluation only
     * 
     * @param using
     * @return
     */
    @SuppressWarnings("unchecked")
    public List<QAFExtendedWebElement> findElementsBySizzleCss(String using) {
        injectSizzleIfNeeded();
        String javascriptExpression = createSizzleSelectorExpression(using);
        return (List<QAFExtendedWebElement>) executeScript(javascriptExpression);
    }

    private String createSizzleSelectorExpression(String using) {
        return "return Sizzle(\"" + using + "\")";
    }

    private void injectSizzleIfNeeded() {
        if (!sizzleLoaded()) {
            injectSizzle();
        }
    }

    private Boolean sizzleLoaded() {
        Boolean loaded;
        try {
            loaded = (Boolean) executeScript("return Sizzle()!=null");
        } catch (WebDriverException e) {
            loaded = false;
        }
        return loaded;
    }

    private void injectSizzle() {
        executeScript(" var headID = document.getElementsByTagName(\"head\")[0];"
                + "var newScript = document.createElement('script');" + "newScript.type = 'text/javascript';"
                + "newScript.src = 'https://raw.github.com/jquery/sizzle/master/sizzle.js';"
                + "headID.appendChild(newScript);");
    }

    @Override
    public TouchScreen getTouchScreen() {
        return new RemoteTouchScreen(getExecuteMethod());
    }

    @Override
    public String takeScreenShot() {
        return getScreenshotAs(OutputType.BASE64);
    }

    public void waitForAjax(JsToolkit toolkit, long... timeout) {
        new QAFWebDriverWait(this, timeout).withMessage("AJAX load Wait time out.")
                .until(QAFWebDriverExpectedConditions.jsCondition(toolkit.waitCondition()));
    }

    public void waitForAjax(long... timeout) {
        new QAFWebDriverWait(this, timeout).withMessage("AJAX load Wait time out.")
                .until(QAFWebDriverExpectedConditions.jsCondition(JsToolkit.globalWaitCondition()));
    }

    @Override
    public void beforeInitialize(Capabilities desiredCapabilities) {
        // can't do anything over here...
    }

    /**
     * This method is useful to extract underlying driver specific interface
     * implementation from the driver object. For Example, Assuming desired
     * capability rotatable is true you can extract Rotatable interface from
     * driver as below. <br />
     * <code>
     * {@link Rotatable} rotatable = driver.getCapabilityImpl();<br />
     * rotatable.rotate(ScreenOrientation.LANDSCAPE);
     * </code>
     * 
     * @return
     */
    @SuppressWarnings("unchecked")
    public <T> T getCapabilityImpl() {
        WebDriver augmentedDriver = new Augmenter().augment(this);
        return ((T) augmentedDriver);
    }

    /*
     * public <X extends RemoteWebDriver> X toX(X x){ x.getSessionId(); return
     * x; }
     */

    public QAFExtendedWebElement findElementByCustomStretegy(String stetegy, String loc) {
        return (QAFExtendedWebElement) findElement(stetegy, loc);
    }

    public List<WebElement> findElementsByCustomStretegy(String stetegy, String loc) {
        return findElements(stetegy, loc);
    }

    @Override
    public void stop() {
        quit();
    }

    @Override
    public Object executeScript(String script, Object... args) {
        if (!getCapabilities().isJavascriptEnabled()) {
            throw new UnsupportedOperationException(
                    "You must be using an underlying instance of WebDriver that supports executing javascript");
        }

        // Escape the quote marks
        script = script.replaceAll("\"", "\\\"");

        Iterable<Object> convertedArgs = Iterables.transform(Lists.newArrayList(args),
                new WebElementToJsonConverter());

        Map<String, ?> params = ImmutableMap.of("script", script, "args", Lists.newArrayList(convertedArgs));

        return execute(DriverCommand.EXECUTE_SCRIPT, params).getValue();
    }

    @Override
    public Object executeAsyncScript(String script, Object... args) {
        if (!getCapabilities().isJavascriptEnabled()) {
            throw new UnsupportedOperationException("You must be using an underlying instance of "
                    + "WebDriver that supports executing javascript");
        }

        // Escape the quote marks
        script = script.replaceAll("\"", "\\\"");

        Iterable<Object> convertedArgs = Iterables.transform(Lists.newArrayList(args),
                new WebElementToJsonConverter());

        Map<String, ?> params = ImmutableMap.of("script", script, "args", Lists.newArrayList(convertedArgs));

        return execute(DriverCommand.EXECUTE_ASYNC_SCRIPT, params).getValue();
    }

}