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

com.github.jjYBdx4IL.test.selenium.SeleniumTestBase Maven / Gradle / Ivy

/*
 * Copyright (C) 2016 jjYBdx4IL (https://github.com/jjYBdx4IL)
 *
 * 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.github.jjYBdx4IL.test.selenium;

import com.github.jjYBdx4IL.test.JsoupTools;
import com.github.jjYBdx4IL.test.Screenshot;

import com.google.common.base.Predicate;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.rules.TestRule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.openqa.selenium.By;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Keys;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.UnhandledAlertException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxProfile;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.ui.Select;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author jjYBdx4IL
 */
public class SeleniumTestBase {

    private static final Logger log = LoggerFactory.getLogger(SeleniumTestBase.class);
    private static WebDriver driver;
    public static final String OUTPUT_DIR = "target/screenshots/";
    public static final String SCREENSHOT_EXT = ".png";
    protected static final int CLICK_WAIT4ELEMENT_MILLIS = 120 * 1000;
    protected static final int CLICK_WAIT4ELEMENT_POLL_MILLIS = 2 * 1000;
    private static final Driver DEFAULT_DRIVER = Driver.CHROME;
    private static long screenShotId = 0L;
    private String testName = null;

    @AfterClass
    public static void tearDown() {
        stopDriver();
    }

    public static void stopDriver() {
        if (driver != null) {
            driver.quit();
            driver = null;
        }
    }

    /**
     * Local screenshots take a screenshot of the entire desktop. They are required to catch alerts.
     *
     * @param name
     */
    public void takeLocalScreenshot(String name) {
        String outputFilePath = String.format(Locale.ROOT, "%s%03d_%s%s", OUTPUT_DIR, ++screenShotId, name,
                SCREENSHOT_EXT);
        Screenshot.takeDesktopScreenshot(outputFilePath);
    }

    /**
     * Take a screenshot of the browser's current page.
     *
     * @param name
     */
    public void takeScreenshot(String name) {
        try {
            String outputFilePath = String.format(Locale.ROOT, "%s%03d_%s%s", OUTPUT_DIR, ++screenShotId, name,
                    SCREENSHOT_EXT);
            File output = new File(outputFilePath);
            log.info("writing remote screenshot: " + output.getCanonicalPath());
            File scrFile = ((TakesScreenshot) getDriver()).getScreenshotAs(OutputType.FILE);
            if (output.exists()) {
                log.warn("screenshot output file exists, overwriting it");
                if (!output.delete()) {
                    log.error("failed to remove previous screenshot file");
                }
            }
            FileUtils.moveFile(scrFile, output);
        } catch (IOException | WebDriverException ex) {
            throw new RuntimeException(ex);
        }
    }

    public void takeScreenshot() {
        if (testName == null) {
            testName = getClass().getSimpleName();
        }
        takeScreenshot(testName);
    }

    public void setTestName(String _testName) {
        testName = _testName;
    }

    /**
     * Tries to force a key up event even when the {
     *
     * @plain value} argument is empty or null.
     * @param el
     * @param value
     */
    public void setInputFieldValue(WebElement el, String value) {
        if ("select".equals(el.getTagName().toLowerCase(Locale.ROOT))) {
            new Select(el).selectByValue(value);
            return;
        }
        if (value != null && !value.isEmpty()) {
            el.clear();
            el.sendKeys(value);
        } else {
            el.sendKeys(Keys.chord(Keys.CONTROL, "a"));
            el.sendKeys(Keys.DELETE);
        }
    }

    public void setInputFieldValue(String inputElementName, String value) throws WebElementNotFoundException {
        WebElement el = getInputByName(inputElementName);
        setInputFieldValue(el, value);
    }

    public void waitUntil(Predicate predicate) {
        new WebDriverWait(getDriver(), CLICK_WAIT4ELEMENT_MILLIS / 1000).until(predicate);
    }

    public String switchToWindowOtherThan(String windowHandle) {
        Iterator it = getDriver().getWindowHandles().iterator();
        String switchToWindowHandle = it.next();
        if (switchToWindowHandle.equals(windowHandle)) {
            switchToWindowHandle = it.next();
        }

        getDriver().switchTo().window(switchToWindowHandle);

        return switchToWindowHandle;
    }

    public String switchToOtherWindow() {
        return switchToWindowOtherThan(getDriver().getWindowHandle());
    }

    /**
     * @return the driver
     */
    public static WebDriver getDriver() {
        return getDriver(DEFAULT_DRIVER);
    }

    public static WebDriver getDriver(Driver driverType) {
        if (driver == null) {
            switch (driverType) {
                case CHROME:
                    ChromeOptions chromeOptions = new ChromeOptions();
                    //chromeOptions.setBinary("/usr/bin/chromium-browser");
                    chromeOptions.addArguments("--disable-gpu");
                    chromeOptions.addArguments("--dbus-stub");
                    setDriver(new ChromeDriver(chromeOptions));
                    //((WebDriver.Window)getDriver()).setSize(new Dimension(1024, 768));
                    break;
                case FIREFOX:
                    FirefoxProfile fp = new FirefoxProfile();
                    fp.setPreference("dom.max_chrome_script_run_time", 3000);
                    fp.setPreference("dom.max_script_run_time", 3000);
                    fp.setPreference("app.update.auto", false);
                    fp.setPreference("app.update.enabled", false);
                    fp.setPreference("browser.tabs.warnOnClose", false);
                    fp.setPreference("browser.tabs.warnOnOpen", false);
                    setDriver(new FirefoxDriver(fp));
                    break;
                default:
                    throw new RuntimeException("not yet supported driver: " + driverType);
            }
            dumpVersion();
        }
        return driver;
    }

    public static void dumpVersion() {
        Capabilities caps = ((RemoteWebDriver) driver).getCapabilities();
        log.info("browser: " + caps.getBrowserName() + " "
                + caps.getVersion() + " (" + caps.getPlatform() + ")");
    }

    /**
     * @param aDriver the driver to set
     */
    public static void setDriver(WebDriver aDriver) {
        driver = aDriver;
    }

    @Rule
    public TestRule seleniumTestWatcher = new TestWatcher() {

        @Override
        protected void succeeded(Description description) {
            tearDown();
        }

        @Override
        protected void failed(Throwable e, Description description) {
            if (driver == null) {
                return;
            }
            try {
                if (e instanceof UnhandledAlertException) {
                    log.error(((UnhandledAlertException) e).getAlertText());
                    takeLocalScreenshot("UnhandledAlertException");
                } else if (e instanceof TimeoutException) {
                    log.error("timeout", e);
                    takeLocalScreenshot("TimeoutException");
                    log.error("body content: " + getPrettyPageSource());
                } else {
                    log.error("testFailure", e);
                    takeLocalScreenshot("testFailure");
                    takeScreenshot("testFailure");
                    log.error("body content: " + getPrettyPageSource());
                }
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            } finally {
                tearDown();
            }
        }
    };

    public void assertNotFound(String text) {
        try {
            assertElement(text);
            Assert.fail();
        } catch (WebElementNotFoundException ex) {
        }
    }

    public void assertNotFoundOrNotDisplayed(String text) {
        WebElement e;
        try {
            e = assertElement(text);
            if (!e.isDisplayed()) {
                return;
            }
            Assert.fail();
        } catch (WebElementNotFoundException ex) {
        }
    }

    /**
     * Assert that the element in question exists, is displayed, and is disabled.
     *
     * @param text the text value of the element to select via {@link #findElement}
     * @throws com.github.jjYBdx4IL.test.selenium.WebElementNotFoundException
     */
    public void assertElementDisabled(String text) throws WebElementNotFoundException {
        WebElement e = assertElement(text);
        if (!e.isDisplayed()) {
            throw new WebElementNotFoundException("found but not displayed: " + text);
        }
        if (e.isEnabled()) {
            throw new WebElementNotFoundException("found but not disabled: " + text);
        }
    }

    /**
     * Assert that the element in question exists, is displayed, but is enabled.
     *
     * @param text the text value of the element to select via {@link #findElement}
     * @throws com.github.jjYBdx4IL.test.selenium.WebElementNotFoundException
     */
    public void assertElementEnabled(String text) throws WebElementNotFoundException {
        WebElement e = assertElement(text);
        if (!e.isDisplayed()) {
            throw new WebElementNotFoundException("found but not displayed: " + text);
        }
        if (!e.isEnabled()) {
            throw new WebElementNotFoundException("found but not enabled: " + text);
        }
    }

    /**
     * Wait for some element using {@link #waitForElement}, then click it.
     *
     * @param text the text value of the element to select
     * @throws WebElementNotFoundException
     */
    public void click(String text) throws WebElementNotFoundException {
        log.info("click(" + text + ")");
        WebElement el = waitForElement(text);
        el.click();
    }

    public void scrollAndClick(WebElement clickable) {
        Actions actions = new Actions(getDriver());
        actions.moveToElement(clickable).click().perform();
    }

    /**
     * Wait until there is some element returned by {@link #findElement} which is displayed and enabled. The
     * timeout is given by {@link #CLICK_WAIT4ELEMENT_MILLIS}.
     *
     * @param text the text value of the element to select
     * @return
     * @throws WebElementNotFoundException
     */
    public WebElement waitForElement(String text, Boolean displayed, Boolean enabled)
            throws WebElementNotFoundException {
        log.info("waitForElement(" + text + ")");

        WebElement e = null;
        long timeout = System.currentTimeMillis() + CLICK_WAIT4ELEMENT_MILLIS;
        do {
            try {
                e = findElement(text);
                if (e != null && enabled != null && enabled.booleanValue() != e.isEnabled()) {
                    e = null;
                }
                if (e != null && displayed != null && displayed.booleanValue() != e.isDisplayed()) {
                    e = null;
                }
            } catch (StaleElementReferenceException ex) {
                e = null;
            }
            if (e == null) {
                try {
                    Thread.sleep(CLICK_WAIT4ELEMENT_POLL_MILLIS);
                } catch (InterruptedException ex) {
                }
            }
        } while ((e == null) && System.currentTimeMillis() < timeout);
        if (e == null) {
            throw new WebElementNotFoundException(text);
        }
        return e;
    }

    public WebElement waitForElement(String text) throws WebElementNotFoundException {
        return waitForElementDisplayedAndEnabled(text);
    }

    public WebElement waitForElementDisplayedAndEnabled(String text) throws WebElementNotFoundException {
        return waitForElement(text, true, true);
    }

    public WebElement waitForElementDisplayedAndDisabled(String text) throws WebElementNotFoundException {
        return waitForElement(text, true, false);
    }

    public WebElement findElement(String text) {
        List elements;
        if (text.startsWith("xpath:")) {
            elements = getDriver().findElements(By.xpath(text.substring("xpath:".length())));
            if (elements.size() > 0) {
                return elements.get(0);
            }
            return null;
        }
        elements = getDriver().findElements(By.xpath("//button[text()='" + text + "']"));
        if (elements.size() > 0) {
            return elements.get(0);
        }
        elements = getDriver().findElements(By.xpath("//label[text()='" + text + "']"));
        if (elements.size() > 0) {
            return elements.get(0);
        }
        elements = getDriver().findElements(By.xpath("//div[text()='" + text + "']"));
        if (elements.size() > 0) {
            return elements.get(0);
        }
        return null;
    }

    public WebElement getButtonByName(String name) throws WebElementNotFoundException {
        return getElementByName("button", name);
    }

    public WebElement getInputByName(String name) throws WebElementNotFoundException {
        return getElementByName("input|select|textarea", name);
    }

    public WebElement getElementByName(String elementTag, String name) throws WebElementNotFoundException {
        String xpath = "xpath://*[(name()='"+StringUtils.join(elementTag.split("\\|"), "' or name()='")+"') and @name='" + name + "']";
        return waitForElement(xpath, null, null);
    }

    public WebElement assertElement(String text) throws WebElementNotFoundException {
        WebElement e = findElement(text);
        if (e == null) {
            throw new WebElementNotFoundException("WebElement with text »" + text + "« not found; page source = "
                    + getPageSource(getDriver()));
        }
        return e;
    }

    protected String getPageSource() {
        return getPageSource(getDriver());
    }

    protected String getPageSource(WebDriver d) {
        return JsoupTools.prettyFormatHtml(d.getPageSource(), false);
    }

    /**
     * This method uses {@link JsoupTools#prettyFormatHtml(java.lang.String, boolean)}, so beware that some
     * content may get truncated for nicer display.
     *
     * @return
     */
    protected String getPrettyPageSource() {
        return JsoupTools.prettyFormatHtml(getDriver().getPageSource(), true);
    }

    public void sleep(int secs) {
        try {
            Thread.sleep(secs * 1000L);
        } catch (InterruptedException ex) {
            throw new RuntimeException(ex);
        }
    }

    public String getXPathForActiveElement() {
        return getXPath(getDriver().switchTo().activeElement());
    }

    public String getXPath(WebElement webElement) {
        String jscript = "function absoluteXPath(element) {"
                + "var comp, comps = [];"
                + "var parent = null;"
                + "var xpath = '';"
                + "var getPos = function(element) {"
                + "var position = 1, curNode;"
                + "if (element.nodeType == Node.ATTRIBUTE_NODE) {"
                + "return null;"
                + "}"
                + "for (curNode = element.previousSibling; curNode; curNode = curNode.previousSibling) {"
                + "if (curNode.nodeName == element.nodeName) {"
                + "++position;"
                + "}"
                + "}"
                + "return position;"
                + "};"
                + "if (element instanceof Document) {"
                + "return '/';"
                + "}"
                + "for (; element && !(element instanceof Document); element = element.nodeType == Node.ATTRIBUTE_NODE ? element.ownerElement : element.parentNode) {"
                + "comp = comps[comps.length] = {};"
                + "switch (element.nodeType) {"
                + "case Node.TEXT_NODE:"
                + "comp.name = 'text()';"
                + "break;"
                + "case Node.ATTRIBUTE_NODE:"
                + "comp.name = '@' + element.nodeName;"
                + "break;"
                + "case Node.PROCESSING_INSTRUCTION_NODE:"
                + "comp.name = 'processing-instruction()';"
                + "break;"
                + "case Node.COMMENT_NODE:"
                + "comp.name = 'comment()';"
                + "break;"
                + "case Node.ELEMENT_NODE:"
                + "comp.name = element.nodeName;"
                + "break;"
                + "}"
                + "comp.position = getPos(element);"
                + "}"
                + "for (var i = comps.length - 1; i >= 0; i--) {"
                + "comp = comps[i];"
                + "xpath += '/' + comp.name.toLowerCase();"
                + "if (comp.position !== null) {"
                + "xpath += '[' + comp.position + ']';"
                + "}"
                + "}"
                + "return xpath;"
                + "} return absoluteXPath(arguments[0]);";
        return (String) ((JavascriptExecutor) getDriver()).executeScript(jscript, webElement);
    }

    public String getXPathSimple(WebElement webElement) {
        String jscript = "function getPathTo(node) {"
                + "  var stack = [];"
                + "  while(node.parentNode !== null) {"
                + "    stack.unshift(node.tagName);"
                + "    node = node.parentNode;"
                + "  }"
                + "  return stack.join('/');"
                + "}"
                + "return getPathTo(arguments[0]);";
        return (String) ((JavascriptExecutor) getDriver()).executeScript(jscript, webElement);
    }

    public WebElement activeElement() {
        return getDriver().switchTo().activeElement();
    }

    public enum Driver {

        FIREFOX, CHROME
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy