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

org.unitils.selenium.WebDriverModule Maven / Gradle / Ivy

There is a newer version: 1.0.8
Show newest version
package org.unitils.selenium;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.SystemUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.logging.LogEntry;
import org.openqa.selenium.support.PageFactory;
import org.unitils.core.Module;
import org.unitils.core.TestListener;
import org.unitils.dbmaintainer.locator.ClassPathDataLocator;
import org.unitils.selenium.annotation.BaseUrl;
import org.unitils.selenium.annotation.TestWebDriver;
import org.unitils.selenium.annotation.WebPage;
import org.unitils.util.AnnotationUtils;
import org.unitils.util.PropertyUtils;
import org.unitils.util.ReflectionUtils;

/**
 *
 * @author Jeroen Horemans
 * @author Thomas De Rycke
 * @author Willemijn Wouters
 *
 * @since 1.0.0
 *
 */
public class WebDriverModule implements Module {

    protected static final String PACKAGENAME = "org.unitils.selenium";

    protected static final String BROWSER_NAME_KEY = PACKAGENAME + ".browser.name";

    protected static final String BASE_URL_KEY = PACKAGENAME + ".baseUrl";

    protected static final String PROXY_HOST_KEY = PACKAGENAME + ".browser.proxy";

    protected static final String DOWNLOADPATH = PACKAGENAME + ".downloadpath";

    protected static final String FILETYPE = PACKAGENAME + ".filetype";

    protected static final String LIST_AUTOMATICALLY_DOWNLOAD = "application/pdf, application/vnd.fdf, application/x-msdos-program, application/x-unknown-application-octet-stream, application/vnd.ms-powerpoint, application/excel, application/vnd.ms-publisher, application/x-unknown-message-rfc822, application/vnd.ms-excel, application/msword, application/x-mspublisher, application/x-tar, application/zip, application/x-gzip,application/x-stuffit,application/vnd.ms-works, application/powerpoint, application/rtf, application/postscript, application/x-gtar, video/quicktime, video/x-msvideo, video/mpeg, audio/x-wav, audio/x-midi, audio/x-aiff, application/octet-stream";

    protected static final String FIREFOX_BINARY_KEY = PACKAGENAME + ".firefoxbinary";

    protected static final String IE_BINARY_KEY = PACKAGENAME + ".iebinary";

    protected static final String CHROME_DRIVER_KEY = PACKAGENAME + ".chromedriver";

    protected static final String CHROME_BINARY_KEY = PACKAGENAME + ".chromebinary";

    protected static final String LOGGINGPROP_CONSOLE_ENABLED = PACKAGENAME + ".logging.console.enabled";

    protected static final String LOGGINGPROP_PERFORMANCE = PACKAGENAME + ".logging.performance";

    protected static final String LOGGINGPROP_BROWSER = PACKAGENAME + ".logging.browser";

    protected static final String LOGGINGPROP_CLIENT = PACKAGENAME + ".logging.client";

    protected static final String LOGGINGPROP_DRIVER = PACKAGENAME + ".logging.driver";

    protected static final String LOGGINGPROP_PROFILER = PACKAGENAME + ".logging.profiler";

    protected static final String LOGGINGPROP_SERVER = PACKAGENAME + ".logging.server";

    protected static final String LOGGING_FILE_PROP = PACKAGENAME + ".logging.file";

    protected static final String LOGGINGPROP_IE = PACKAGENAME + ".logging.IE";

    private BrowserChoice browserChoice;

    private String baseUrl;

    private String proxyUrl;

    private String downloadPath;

    private String fileType;

    private Properties configuration;

    private static final Log LOGGER = LogFactory.getLog(WebDriverModule.class);

    private ClassPathDataLocator dataLocator;

    @Override
    public void init(Properties configuration) {
        dataLocator = new ClassPathDataLocator();
        browserChoice = resolveBrowserChoice(configuration);
        baseUrl = resolveBaseUrl(configuration);
        proxyUrl = resolveProxyHost(configuration);
        LOGGER.debug("Driver Module loaded");
        downloadPath = PropertyUtils.getString(DOWNLOADPATH, "", configuration);
        fileType = PropertyUtils.getString(FILETYPE, LIST_AUTOMATICALLY_DOWNLOAD, configuration);

        this.configuration = configuration;

        String bit = System.getProperty("sun.arch.data.model");
        ClassLoader classLoader = getClass().getClassLoader();

        checkFirefoxDriver();
        checkChromeDriver(bit, classLoader);
        checkIEDriver(bit, classLoader);
    }

    @Override
    public void afterInit() {
        // nothing for now.
    }

    /**
     * *
     * Get the base URL out of unitils.properties
     *
     * @param configuration
     * @return {@link String}
     */
    private String resolveBaseUrl(Properties configuration) {
        String result = configuration.getProperty(BASE_URL_KEY);
        if (StringUtils.isEmpty(result)) {
            throw new IllegalArgumentException("plz fill in a value in the unitils.properties for " + BASE_URL_KEY);
        }
        return result;
    }

    /**
     * Gets the name of the browser out of unitils.properties
     *
     * @param configuration
     * @return {@link BrowserChoice}
     */
    private BrowserChoice resolveBrowserChoice(Properties configuration) {
        String browserName = configuration.getProperty(BROWSER_NAME_KEY);
        if (StringUtils.isEmpty(browserName)) {
            LOGGER.info(BROWSER_NAME_KEY + " not set. Will choose browser FIREFOX");
            return BrowserChoice.FIREFOX;
        }
        return BrowserChoice.valueOf(browserName);

    }

    /**
     * Get the proxy host out of unitils.properties
     *
     * @param configuration
     * @return {@link String}
     */
    private String resolveProxyHost(Properties configuration) {
        String result = configuration.getProperty(PROXY_HOST_KEY);
        if (StringUtils.isEmpty(result)) {
            LOGGER.info(PROXY_HOST_KEY + " not set. No proxy used");
            return "";
        }
        LOGGER.info("proxy: [" + result + "] set. Proxy used");
        return result;
    }

    /**
     * Initialises the webdriver. The method searches if there are fields with
     * the {@link TestWebDriver} and uses the browser choice (in
     * unitils.properties) to create the driver.
     *
     * @param testObject
     */
    public void initWebDriver(Object testObject) {

        Set fields = AnnotationUtils.getFieldsAnnotatedWith(testObject.getClass(), TestWebDriver.class);

        if (fields.size() > 1) {
            //warn if there are more than one fields with the @TestWebDriver
            StringBuilder builder = new StringBuilder();
            builder.append("There are more than one webdrivers.\n");
            for (Field field : fields) {
                builder.append("class: ");
                builder.append(field.getDeclaringClass().getName());
                builder.append(", field: ");
                builder.append(field.getName());
                builder.append("\n");
            }
            LOGGER.warn(builder.toString());
        }

        for (Field field : fields) {
            WebDriver driver;
            if (proxyUrl.isEmpty()) {
                driver = WebDriverFactory.createDriver(browserChoice, getAbsoluteDownloadPath(downloadPath), fileType);
            } else {
                driver = WebDriverFactory.createDriver(browserChoice, proxyUrl, getAbsoluteDownloadPath(downloadPath), fileType);
            }
            driver.manage().deleteAllCookies();
            ReflectionUtils.setFieldValue(testObject, field, driver);
        }
    }

    protected static String getAbsoluteDownloadPath(String path) {
        if (!StringUtils.isEmpty(path)) {
            File file = new File(path);
            if (!file.exists()) {
                file.mkdirs();
            }
            return file.getAbsolutePath();
        }
        return "";
    }

    /**
     * All the webdrivers (all the fields with the {@link TestWebDriver} of the
     * testObject will be killed.
     *
     * @param testObject
     */
    protected void killWebDriver(Object testObject) {
        Set fields = AnnotationUtils.getFieldsAnnotatedWith(testObject.getClass(), TestWebDriver.class);
        for (Field field : fields) {
            WebDriver driver = ReflectionUtils.getFieldValue(testObject, field);
            LOGGER.debug("closing a driver that is on page : " + driver.getCurrentUrl());
            driver.close();
            driver.quit();
            nastyDoubleCheck(driver);
            nastyDoubleCheck(driver);
        }
    }

    private void nastyDoubleCheck(WebDriver driver) {
        try {

            Thread.sleep(500);
            driver.getTitle();
            driver.close();
            driver.quit();
        } catch (WebDriverException e) {
            // continue
        } catch (InterruptedException e) {
            // continue
        }

    }

    /**
     * All the elements with the @BaseUrlString will be initialised with the
     * base url value of the unitils.properties.
     *
     * @param testObject
     */
    public void initBaseUrl(Object testObject) {
        Set fields = AnnotationUtils.getFieldsAnnotatedWith(testObject.getClass(), BaseUrl.class);
        for (Field field : fields) {
            ReflectionUtils.setFieldValue(testObject, field, baseUrl);
        }

    }

    /**
     * *
     * Searches all the fields with the {@link WebPage} annotation and sets the
     * correct elements.
     *
     * @param testObject
     */
    public void initElements(Object testObject) {
        //find fields that has the @WebPage annotation
        Set fields = AnnotationUtils.getFieldsAnnotatedWith(testObject.getClass(), WebPage.class);
        //find the webdriver
        Set webdrivers = AnnotationUtils.getFieldsAnnotatedWith(testObject.getClass(), TestWebDriver.class);
        if (webdrivers.size() > 0) {
            //initialise the page and set the object in the correct field.
            WebDriver webdriver = ReflectionUtils.getFieldValue(testObject, webdrivers.iterator().next());
            for (Field field : fields) {
                if (webdriver != null) {
                    ReflectionUtils.setFieldValue(testObject, field, getElement(webdriver, field.getType()));
                }
            }

        } else {
            LOGGER.error("The TestWebDriver cannot be found.");

        }

    }

    protected void checkChromeDriver(String bit, ClassLoader classLoader) {
        String driver = "chrome driver";
        String pathChrome = "webdriver.chrome.driver";

        String absPath = "";
        if (!(checkIfDriverIsAlreadyInSystem(System.getProperty(pathChrome), driver, pathChrome) || checkIfDriverPropertyExistsInUnitilsProperties(CHROME_DRIVER_KEY, driver, pathChrome))) {
            if (SystemUtils.IS_OS_WINDOWS) {
                absPath = copyDriverIntoNewTempFile(dataLocator.loadResources("chromedriver_win.exe", true).get(0), "chromedriver_win.exe");
                System.setProperty(pathChrome, absPath);

            } else if (SystemUtils.IS_OS_MAC) {
                //set drivers mac
                absPath = copyDriverIntoNewTempFile(dataLocator.loadResources("chromedriver_mac32", true).get(0), "chromedriver_mac32");
                System.setProperty(pathChrome, absPath);

            } else if (SystemUtils.IS_OS_LINUX) {
                absPath = copyDriverIntoNewTempFile(dataLocator.loadResources("chromedriver_linux32", true).get(0), "chromedriver_linux32");
                System.setProperty(pathChrome, absPath);
                
            }
            LOGGER.info(createLogNewDriver(pathChrome, absPath));
        }

    }

    /**
     * This method checks if their is a system property 'webdriver.firefox.bin'
     * and checks if it exists. Otherwise it will check the unitils.properties
     * if their is a property {@link WebDriverModule#FIREFOX_BINARY_KEY} in the
     * unitils.properties.
     */
    protected void checkFirefoxDriver() {
        String driver = "firefox driver";
        String pathFirefox = "webdriver.firefox.bin";
        if (!(checkIfDriverIsAlreadyInSystem(System.getProperty(pathFirefox), driver, pathFirefox) || checkIfDriverPropertyExistsInUnitilsProperties(FIREFOX_BINARY_KEY, driver, pathFirefox))) {
            LOGGER.error("There is no firefox driver found.");
        }

    }

    /**
     * This method checks if there is a system property 'webdriver.ie.driver'
     * and checks if the location exists. If this doesn't exist than he looks if
     * you've defined another IE driver ( {@link WebDriverModule#IE_BINARY_KEY}
     * in your unitils.properties. The last option is that it uses the driver
     * that is given by unitils-selenium.
     *
     * @param bit
     * @param classLoader
     */
    protected void checkIEDriver(String bit, ClassLoader classLoader) {
        String pathIE = "webdriver.ie.driver";
        String driver = "IE driver";
        String absPath = "";

        //this is only possible on WINDOWS
        if (SystemUtils.IS_OS_WINDOWS) {
            if (!(checkIfDriverIsAlreadyInSystem(System.getProperty(pathIE), driver, pathIE) || checkIfDriverPropertyExistsInUnitilsProperties(IE_BINARY_KEY, driver, pathIE))) {
                if (bit.equals("32")) {
                    absPath = copyDriverIntoNewTempFile(dataLocator.loadResources("IEDriverServer.exe", true).get(0), "IEDriverServer.exe");
                    System.setProperty(pathIE, absPath);
                } else if (bit.equals("64")) {
                    absPath = copyDriverIntoNewTempFile(dataLocator.loadResources("IEDriverServer_x64.exe", true).get(0), "IEDriverServer_x64.exe");
                    System.setProperty(pathIE, absPath);
                }
                LOGGER.info(createLogNewDriver(pathIE, absPath));
            }

        }

    }

    public boolean checkIfDriverIsAlreadyInSystem(String systemProp, String driver, String systemVarDriver) {
        if (!StringUtils.isEmpty(systemProp) && new File(systemProp).exists()) {
            StringBuilder builder = new StringBuilder()
                    .append("The ")
                    .append(driver)
                    .append(" already defined in the system (")
                    .append(systemVarDriver)
                    .append(") exists and will be used by Unitils. location:")
                    .append(systemProp);
            LOGGER.info(builder);
            return true;
        }
        return false;
    }
    
    public boolean checkIfDriverPropertyExistsInUnitilsProperties(String key, String driver, String systemKey) {
        String unitilsDriver = PropertyUtils.getString(key, "", configuration);
        if (configuration.containsKey(key) && !StringUtils.isEmpty(unitilsDriver)) {
                File driverFile = new File(unitilsDriver);
                if (driverFile.exists()) {
                    StringBuilder builder = new StringBuilder()
                            .append("The WebdriverModule uses the ")
                            .append(driver)
                            .append(" from the unitils.properties. location: ")
                            .append(driverFile.toString());
                    LOGGER.info(builder.toString());
                    System.setProperty(systemKey, driverFile.getAbsolutePath());
                    return true;
                } else {
                    StringBuilder builder = new StringBuilder()
                            .append("The location of the ")
                            .append(driver)
                            .append(" defined in the unitils.properties does not exists. location: ")
                            .append(driverFile.getAbsolutePath());
                    LOGGER.error(builder.toString());
                }
        }
        return false;
    }

    public String copyDriverIntoNewTempFile(URL url, String name) {
        StringBuilder result = new StringBuilder(TARGETSUREFIREREPORTS).append(name);
        File destination = new File(result.toString());
        try {
            FileUtils.copyInputStreamToFile(url.openStream(), destination);
            destination.setExecutable(true);
        } catch (IOException e) {
            LOGGER.error(e.getMessage(), e);
            return url.getPath();
        }

        return destination.getAbsolutePath();

    }
    public static final String TARGETSUREFIREREPORTS = "target/surefire-reports/";

    /**
     * This is the actual method that creates an object of the correct type and
     * initialises all the elements.
     *
     * @param webdriver
     * @param type
     * @return {@link Object}
     *
     */
    protected Object getElement(WebDriver webdriver, Class type) {
        return PageFactory.initElements(webdriver, type);
    }

    @Override
    public TestListener getTestListener() {
        return new TestListener() {

            @Override
            public void beforeTestSetUp(Object testObject, Method testMethod) {
                super.beforeTestSetUp(testObject, testMethod);
                initWebDriver(testObject);
                initBaseUrl(testObject);
                initElements(testObject);
            }

            /**
             * @see
             * org.unitils.core.TestListener#afterTestMethod(java.lang.Object,
             * java.lang.reflect.Method, java.lang.Throwable)
             */
            @Override
            public void afterTestMethod(Object testObject, Method testMethod, Throwable testThrowable) {
                //write the console logging
                //TODO: This doesn't work yet with IE.

                if (PropertyUtils.getBoolean(WebDriverModule.LOGGINGPROP_CONSOLE_ENABLED, false, configuration)) {
                    LOGGER.info("BEGIN CONSOLE TEST: " + testMethod.getName());

                    if (!resolveBrowserChoice(configuration).equals(BrowserChoice.IE)) {
                        for (Field webdriverField : AnnotationUtils.getFieldsAnnotatedWith(testObject.getClass(), TestWebDriver.class)) {
                            WebDriver webdriver = ReflectionUtils.getFieldValue(testObject, webdriverField);
                            for (String type : webdriver.manage().logs().getAvailableLogTypes()) {
                                try {

                                    List entries = webdriver.manage().logs().get(type).getAll();
                                    System.out.println(entries.size() + " " + type + " log entries found");
                                    for (LogEntry entry : entries) {
                                        if (!entry.getLevel().equals(Level.OFF)) {
                                            SimpleDateFormat format = new SimpleDateFormat("YYMMddHHmmss");
                                            System.out.println(
                                                    format.format(new Date(entry.getTimestamp())) + " " + entry.getLevel() + " " + entry.getMessage());
                                        }

                                    }

                                } catch (Exception e) {
                                    LOGGER.debug("Log " + type + " is not available.");
                                }
                            }
                        };
                    }

                    LOGGER.info("END CONSOLE TEST: " + testMethod.getName());
                }

                if (testThrowable != null) { 
                    int i = 0; 
                    try { 
                        Set fields = AnnotationUtils.getFieldsAnnotatedWith(testObject.getClass(), TestWebDriver.class); 
                        for (Field field : fields) { 
                            WebDriver driver = ReflectionUtils.getFieldValue(testObject, field); 
                            File surefire = new File(TARGETSUREFIREREPORTS); 
                            if (!surefire.exists()) { 
                                surefire.mkdir(); 
                            } 
                            StringBuilder builder = new StringBuilder() 
                                .append(testObject.getClass().getSimpleName()) 
                                .append("-") 
                                .append(testMethod.getName()) 
                                .append("-") 
                                .append(field.getName()) 
                                .append("-") 
                                .append(++i); 
                            new ScreenshotTakingWebDriver(driver, baseUrl).saveScreenshot(surefire, builder.toString());
                        } 
                    } catch (Exception e) { 
                        LOGGER.error("The taking of the screenshot has made a terrible mistake! but we'll continue!", e); 
                    } 
                } 

            }

            /**
             * @see
             * org.unitils.core.TestListener#afterTestTearDown(java.lang.Object,
             * java.lang.reflect.Method)
             */
            @Override
            public void afterTestTearDown(Object testObject, Method testMethod) {
                killWebDriver(testObject);
                super.afterTestTearDown(testObject, testMethod);
            }

        };
    }

    protected static String createLogNewDriver(String systemVarDriver, String absPath) {
        return new StringBuilder().append("The location of the variable defined in the ' ")
                .append(systemVarDriver)
                .append("' didn't exist, so we have changed the location of the variable to the driver added in unitils.selenium. location: ")
                .append(absPath)
                .toString();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy