org.testeditor.fixture.web.AbstractWebFixture.java Source code

Java tutorial

Introduction

Here is the source code for org.testeditor.fixture.web.AbstractWebFixture.java

Source

/*******************************************************************************
 * Copyright (c) 2012 - 2015 Signal Iduna Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * Signal Iduna Corporation - initial API and implementation
 * akquinet AG
 *******************************************************************************/
package org.testeditor.fixture.web;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Keys;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Wait;
import org.testeditor.fixture.core.elementlist.ElementListService;
import org.testeditor.fixture.core.exceptions.ContinueTestException;
import org.testeditor.fixture.core.exceptions.ElementKeyNotFoundException;
import org.testeditor.fixture.core.exceptions.StopTestException;
import org.testeditor.fixture.core.interaction.Fixture;
import org.testeditor.fixture.core.interaction.StoppableFixture;

/**
 * Abstract class for all web based fixtures.
 * 
 */
public abstract class AbstractWebFixture implements StoppableFixture, Fixture {

    /** Represents a map with user defined names and application elements. */
    protected ElementListService elementListService;
    /** Maximum wait time in seconds for each test step. */
    protected int timeout = 10;
    /** The web driver. */
    protected WebDriver webDriver;

    private static final Logger logger = Logger.getLogger(AbstractWebFixture.class);

    /**
     * Creates the element list instance representing the GUI-Map for widget
     * element id's of an application and the user defined names for this
     * represented GUI element. Often used in a FitNesse ScenarioLibrary for
     * configuration purpose.
     * 
     * @param elementList
     *            relative path of the element list content.txt wiki site on a
     *            FitNesse Server where WikiPages is the directory where all the
     *            Wiki Sites of the recent project are
     */
    public void setElementlist(String elementList) {
        this.elementListService = ElementListService.instanceFor(elementList);
    }

    /**
     * Sets the maximum wait time in seconds for each test step.
     * 
     * @param timeout
     *            timeout in seconds
     * @throws StopTestException
     *             if timeout is not a correct integer value
     */
    public void setTimeout(String timeout) throws StopTestException {
        try {
            this.timeout = Integer.valueOf(timeout);
            if (this.timeout < 1) {
                this.timeout = 1;
            }
        } catch (NumberFormatException e) {
            throw new StopTestException("Timeout must be an integer greater or equal 1 second. ", e);
        }
    }

    /**
     * Opens a specific browser (e.g. Firefox, Google-Chrome or Microsoft
     * Internet Explorer), it is possible to use 'firefox', 'chrome' or 'ie' as
     * browser name.
     * <p/>
     * 
     * 
     * For <b>Firefox</b> the path to the executable is needed:
     * -Dwebdriver.firefox.bin<br/>
     * For <b>Internet Explorer</b> the path to the web driver is needed:
     * -Dwebdriver.ie.driver<br/>
     * For <b>Chrome</b> the path to the web driver is needed:
     * -Dwebdriver.chrome.driver
     * 
     * @param browserName
     *            name of browser ('ie', 'chrome' or 'firefox')
     * @return {@code true}, if browser starts successful, {@code false}
     *         otherwise
     */
    public boolean openBrowser(String browserName) {

        if ("firefox".equalsIgnoreCase(browserName)) {
            initFirefoxDriver();
        } else if ("ie".equalsIgnoreCase(browserName)) {
            initIEDriver();
        } else if ("chrome".equalsIgnoreCase(browserName)) {
            initChromeDriver();
        } else {
            throw new StopTestException("Browser '" + browserName + "' not available.");
        }

        manageTimeouts();

        return true;
    }

    /**
     * Manages the timeouts for the web driver.
     */
    protected void manageTimeouts() {
        webDriver.manage().timeouts().implicitlyWait(timeout, TimeUnit.SECONDS);
    }

    /**
     * Initialize web driver for the Internet Explorer.
     */
    protected void initIEDriver() {
        DesiredCapabilities cap = DesiredCapabilities.internetExplorer();
        cap.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, "true");
        webDriver = new InternetExplorerDriver(cap);
    }

    /**
     * Initialize web driver for Google Chrome.
     */
    protected void initChromeDriver() {
        webDriver = new ChromeDriver();
    }

    /**
     * Initialize web driver for Firefox.
     */
    protected void initFirefoxDriver() {
        String osName = System.getProperty("os.name");
        if (osName != null && osName.contains("Linux")) {
            System.setProperty("webdriver.firefox.profile", "testing");
        }

        String firefoxBin = System.getProperty("webdriver.firefox.bin");
        if (firefoxBin == null) {
            webDriver = new FirefoxDriver();
            // throw new StopTestException(
            // "Web driver initialisation error. Please specify system property
            // -Dwebdriver.firefox.bin properly.");
        } else if (!(new File(firefoxBin)).exists()) {
            throw new StopTestException(
                    "Web driver initialisation error. Browser path '" + firefoxBin + "' does not exist.");
        } else {
            webDriver = new FirefoxDriver();
        }
    }

    /**
     * Close the browser instance.
     * 
     * @return always {@code true} to show inside FitNesse a positive result
     */
    public boolean closeBrowser() {
        // checks if Browser is Chrome because Chrome-Driver does not function
        // with Close-Method
        if (webDriver instanceof ChromeDriver) {
            webDriver.quit();
        } else {
            webDriver.close();
            // necessary wait, at least for Firefox-Portable
            try {
                Thread.sleep(500);
                // CHECKSTYLE:OFF
            } catch (InterruptedException e) {
                // CHECKSTYLE:ON
                // try to quit browser anyway
            }
            // best effort
            try {
                webDriver.quit();
                // CHECKSTYLE:OFF
            } catch (Exception e) {
                // CHECKSTYLE:ON
                // At least Firefox-Portable is down after close()
            }
        }
        return true;
    }

    /**
     * Navigates to a new web page in the current browser window.
     * 
     * @param url
     *            URL of page to navigate to
     * @return always {@code true} to show inside FitNesse a positive result
     */
    public boolean navigateToUrl(String url) {
        webDriver.get(url);
        return true;
    }

    /**
     * Checks if a given string {@code second} is found within {@code first}
     * string.
     * 
     * @param first
     *            the string to analyze
     * @param second
     *            the string to be found within {@code first}
     * @return {@code true} if {@code first} contains {@code second},
     *         {@code false} otherwise
     */
    public boolean assertContains(String first, String second) {
        boolean result = false;

        if (first == null && second == null) {
            result = true;
        } else if (first != null && second != null && first.trim().contains(second.trim())) {
            result = true;
        }

        return result;
    }

    /**
     * Checks if a given string {@code second} is <b>not</b> part of
     * {@code first} string.
     * 
     * @param first
     *            the string to analyze
     * @param second
     *            the string not to be part of {@code first}
     * @return {@code true} if {@code first} <b>not</b> part of {@code second},
     *         {@code false} otherwise
     */
    public boolean assertNotContains(String first, String second) {
        return !assertContains(first, second);
    }

    /**
     * Checks if a given value is empty (i.e. a {@code null}-value or an empty
     * string.
     * 
     * @param value
     *            the value to compare
     * @return {@code true} if {@code value} is an empty string, {@code false}
     *         otherwise
     */
    public boolean assertIsEmpty(String value) {
        boolean result = false;
        if (value == null || value.trim().isEmpty()) {
            result = true;
        }
        return result;
    }

    /**
     * Checks if a given value is <b>not</b> empty (i.e. not a {@code null}
     * -value or an empty string.
     * 
     * @param value
     *            the value to compare
     * @return {@code true} if {@code value} is <b>not</b> an empty string,
     *         {@code false} otherwise
     */
    public boolean assertIsNotEmpty(String value) {
        return !assertIsEmpty(value);
    }

    /**
     * Compares a given value with another value for equality.
     * 
     * @param first
     *            the first value to compare
     * @param second
     *            the second value to compare
     * @return {@code true} if {@code first} is equal to {@code second},
     *         {@code false} otherwise
     */
    public boolean assertIsEqual(String first, String second) {
        boolean result = false;

        if (first == null && second == null) {
            result = true;
        } else if (first != null && second != null && (first.trim()).equals(second.trim())) {
            result = true;
        }

        return result;
    }

    /**
     * Compares a given value with another value for inequality.
     * 
     * @param first
     *            the first value to compare
     * @param second
     *            the second value to compare
     * @return {@code true} if {@code first} is <b>not</b> equal to
     *         {@code second}, {@code false} otherwise
     */
    public boolean assertIsNotEqual(String first, String second) {
        return !assertIsEqual(first, second);
    }

    /**
     * Waits for the given period of time before executing the next test step.
     * 
     * @param secondsToWait
     *            Time to wait in seconds
     * @return {@code true} if waiting was successful, {@code false} otherwise
     */
    public boolean waitSeconds(long secondsToWait) {
        if (secondsToWait <= 0) {
            return true;
        }

        try {
            Thread.sleep(secondsToWait * 1000);
        } catch (InterruptedException e) {
            return false;
        }
        return true;
    }

    /**
     * Checks if a web element is present in the DOM and visible on the web
     * page.
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @param replaceArgs
     *            values to replace the place holders in the element list entry
     * @return {@code true} if the web element is displayed on the page,
     *         {@code false} otherwise
     * @throws StopTestException
     *             if a timeout occurred
     */
    public boolean checkElementIsAvailable(String elementListKey, String... replaceArgs) throws StopTestException {
        List<WebElement> elements = findWebElements(elementListKey, replaceArgs);
        for (WebElement webElement : elements) {
            if (webElement != null && webElement.isDisplayed()) {
                return true;
            }
        }

        return false;
    }

    /**
     * Checks if a web element is present in the DOM and visible on the web
     * page.
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @return {@code true} if the web element is displayed on the page,
     *         {@code false} otherwise
     * @throws StopTestException
     *             if a timeout occurred
     */
    public boolean checkElementIsAvailable(String elementListKey) throws StopTestException {
        return checkElementIsAvailable(elementListKey, new String[] {});
    }

    /**
     * Checks if a web element is <b>not</b> present in the DOM or present but
     * <b>not</b> displayed on web page.
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @param replaceArgs
     *            values to replace the place holders in the element list entry
     * @return {@code true} if the web element is <b>not</b> displayed on the
     *         page, {@code false} otherwise
     * @throws StopTestException
     *             if a timeout occurred
     */
    public boolean checkElementIsNotAvailable(String elementListKey, String... replaceArgs)
            throws StopTestException {
        try {
            WebElement element = webDriver.findElement(createBy(elementListKey, replaceArgs));
            return element == null || !element.isDisplayed();
        } catch (NoSuchElementException e) {
            return true;
        } catch (TimeoutException e) {
            return true;
        } catch (StaleElementReferenceException e) {
            return true;
        }
    }

    /**
     * Checks if a web element is <b>not</b> present in the DOM or present but
     * <b>not</b> displayed on web page.
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @return {@code true} if the web element is <b>not</b> displayed on the
     *         page, {@code false} otherwise
     * @throws StopTestException
     *             if a timeout occurred
     */
    public boolean checkElementIsNotAvailable(String elementListKey) throws StopTestException {
        return checkElementIsNotAvailable(elementListKey, new String[] {});
    }

    /**
     * Checks if a web element is active (Enabled).
     * 
     * Therefore it is ensured that the element is available (present in DOM and
     * visible on web page). If element is not available a
     * {@code StopTestException} is thrown.
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @param replaceArgs
     *            values to replace the place holders in the element list entry
     * @return {@code true} if the web element is active (enabled),
     *         {@code false} otherwise
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public boolean checkElementIsActive(String elementListKey, String... replaceArgs) throws StopTestException {
        WebElement element = findAvailableWebElement(elementListKey, replaceArgs);
        return element.isEnabled();
    }

    /**
     * Checks if a web element is active (Enabled).
     * 
     * Therefore it is ensured that the element is available (present in DOM and
     * visible on web page). If element is not available a
     * {@code StopTestException} is thrown.
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @return {@code true} if the web element is active (enabled),
     *         {@code false} otherwise
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public boolean checkElementIsActive(String elementListKey) throws StopTestException {
        return checkElementIsActive(elementListKey, new String[] {});
    }

    /**
     * Checks if a web element is inactive (disabled).
     * 
     * Therefore it is ensured that the element is available (present in DOM and
     * visible on web page). If element is not available a
     * {@code StopTestException} is thrown.
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @param replaceArgs
     *            values to replace the place holders in the element list entry
     * @return {@code true} if the web element is inactive (disabled),
     *         {@code false} otherwise
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public boolean checkElementIsInactive(String elementListKey, String... replaceArgs) throws StopTestException {
        WebElement element = findAvailableWebElement(elementListKey, replaceArgs);
        return !element.isEnabled();
    }

    /**
     * Checks if a web element is inactive (disabled).
     * 
     * Therefore it is ensured that the element is available (present in DOM and
     * visible on web page). If element is not available a
     * {@code StopTestException} is thrown.
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @return {@code true} if the web element is inactive (disabled),
     *         {@code false} otherwise
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public boolean checkElementIsInactive(String elementListKey) throws StopTestException {
        return checkElementIsInactive(elementListKey, new String[] {});
    }

    /**
     * Moves the mouse cursor to the displayed web element.
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @param replaceArgs
     *            values to replace the place holders in the element list entry
     * @return always {@code true} to show inside FitNesse a positive result
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public boolean moveMouseToElement(String elementListKey, String... replaceArgs) throws StopTestException {
        WebElement element = findAvailableWebElement(elementListKey, replaceArgs);
        Actions actions = new Actions(webDriver);
        actions.moveToElement(element).build().perform();
        return true;
    }

    /**
     * Moves the mouse cursor to the displayed web element.
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @return always {@code true} to show inside FitNesse a positive result
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public boolean moveMouseToElement(String elementListKey) throws StopTestException {
        return moveMouseToElement(elementListKey, new String[] {});
    }

    /**
     * Switches to another frame (e.g. iFrame).
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @param replaceArgs
     *            values to replace the place holders in the element list entry
     * @return always {@code true} to show inside FitNesse a positive result
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public boolean switchToFrame(String elementListKey, String... replaceArgs) throws StopTestException {
        WebElement webElement = findAvailableWebElement(elementListKey, replaceArgs);
        webDriver.switchTo().frame(webElement);

        return true;
    }

    /**
     * Switches to another frame (e.g. iFrame).
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @return always {@code true} to show inside FitNesse a positive result
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public boolean switchToFrame(String elementListKey) throws StopTestException {
        return switchToFrame(elementListKey, new String[] {});
    }

    /**
     * Switches to the default content (main frame).
     * 
     * @return true if switch successed
     */
    public boolean switchToDefaultContent() {
        webDriver.switchTo().defaultContent();

        return true;
    }

    /**
     * Performs a mouse click on the displayed web element.
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @param replaceArgs
     *            values to replace the place holders in the element list entry
     * @return always {@code true} to show inside FitNesse a positive result
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public boolean clickElement(String elementListKey, String... replaceArgs) throws StopTestException {
        WebElement element = findAvailableWebElement(elementListKey, replaceArgs);
        element.click();
        return true;
    }

    /**
     * Performs a mouse click on the displayed web element.
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @return always {@code true} to show inside FitNesse a positive result
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public boolean clickElement(String elementListKey) throws StopTestException {
        return clickElement(elementListKey, new String[] {});
    }

    /**
     * Double clicks on an element.
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @param replaceArgs
     *            values to replace the place holders in the element list entry
     * @return always {@code true} to show inside FitNesse a positive result
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public boolean doubleClickElement(String elementListKey, String... replaceArgs) throws StopTestException {
        WebElement element = findAvailableWebElement(elementListKey, replaceArgs);
        Actions action = new Actions(webDriver);
        action.moveToElement(element).doubleClick().build().perform();
        return true;
    }

    /**
     * Double clicks on an element.
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @return always {@code true} to show inside FitNesse a positive result
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public boolean doubleClickElement(String elementListKey) throws StopTestException {
        return doubleClickElement(elementListKey, new String[] {});
    }

    /**
     * Inserts a value into a field (e.g. an input field or text area).
     * 
     * @param value
     *            the value to insert
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @param replaceArgs
     *            values to replace the place holders in the element list entry
     * @return {@code true} if the {@code value} was insert successful,
     *         {@code false} otherwise
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public boolean insertIntoField(String value, String elementListKey, String... replaceArgs)
            throws StopTestException {
        if (value == null) {
            return true;
        }

        WebElement element = findAvailableWebElement(elementListKey, replaceArgs);
        String oldValue = element.getAttribute("value");
        element.click();
        element.sendKeys(value);
        return oldValue.concat(value).equals(element.getAttribute("value"));
    }

    /**
     * Inserts a value into a field (e.g. an input field or text area).
     * 
     * @param value
     *            the value to insert
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @return {@code true} if the {@code value} was insert successful,
     *         {@code false} otherwise
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public boolean insertIntoField(String value, String elementListKey) throws StopTestException {
        return insertIntoField(value, elementListKey, new String[] {});
    }

    /**
     * Searches for a given text on the page.
     * 
     * @param text
     *            to be searched for
     * @return {@code true} if the {@code text} is present on the page,
     *         {@code false} otherwise
     */
    public boolean checkTextIsPresentOnPage(final String text) {

        waitForPage();
        try {
            int interval = (int) Math.floor(Math.sqrt(timeout));
            logger.info("Got interval: " + interval);
            Wait<WebDriver> wait = new FluentWait<WebDriver>(webDriver).withTimeout(timeout, TimeUnit.SECONDS)
                    .pollingEvery(interval, TimeUnit.SECONDS)
                    .ignoring(NoSuchElementException.class, StaleElementReferenceException.class);
            return wait.until(new ExpectedCondition<Boolean>() {

                @Override
                public Boolean apply(WebDriver driver) {
                    String source = webDriver.getPageSource();
                    logger.info("Got source: " + "\"" + source + "\"");
                    logger.info("text to be checked: " + "\"" + text + "\"");
                    source = source.replaceFirst("(?i:<HEAD[^>]*>[\\s\\S]*</HEAD>)", "");
                    return source.contains(text.trim());
                }
            });
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * Waits for page is complete loaded. Therefore the "document.readyState" is
     * checked.
     * 
     * @return {@code true} if complete loaded during the timeout, {@code false}
     *         otherwise
     */
    public boolean waitForPage() {
        int interval = (int) Math.floor(Math.sqrt(timeout));
        Wait<WebDriver> wait = new FluentWait<WebDriver>(webDriver).withTimeout(timeout, TimeUnit.SECONDS)
                .pollingEvery(interval, TimeUnit.SECONDS)
                .ignoring(NoSuchElementException.class, StaleElementReferenceException.class);
        try {
            return wait.until(new ExpectedCondition<Boolean>() {

                @Override
                public Boolean apply(WebDriver arg) {
                    return ((JavascriptExecutor) webDriver).executeScript("return document.readyState")
                            .equals("complete");
                }
            });
        } catch (TimeoutException e) {
            throw new ContinueTestException("Page could not be loaded within the timeout.");
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        return true;
    }

    /**
     * Checks that a text is <b>not</b> present on the page.
     * 
     * @param text
     *            not expected on the page
     * @return {@code true} if the {@code text} is <b>not</b> present on the
     *         page, {@code false} otherwise
     */
    public boolean checkTextIsNotPresentOnPage(String text) {
        return !checkTextIsPresentOnPage(text);
    }

    /**
     * Searches for a given text on the available web element.
     * 
     * <p />
     * <b>Hint:</b> for input field use
     * {@link HtmlWebFixture#checkValueOfElement(String, String, String...)}
     * 
     * @param text
     *            to be searched for
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @param replaceArgs
     *            values to replace the place holders in the element list entry
     * @return {@code true} if the {@code text} is present on the web element,
     *         {@code false} otherwise
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public boolean checkTextIsPresentOnElement(String text, String elementListKey, String... replaceArgs)
            throws StopTestException {
        WebElement element = findAvailableWebElement(elementListKey, replaceArgs);
        return element.getText().contains(text.trim());
    }

    /**
     * Searches for a given text on the available web element.
     * 
     * <p />
     * <b>Hint:</b> for input field use
     * {@link HtmlWebFixture#checkValueOfElement(String, String)}
     * 
     * @param text
     *            to be searched for
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @return {@code true} if the {@code text} is present on the web element,
     *         {@code false} otherwise
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public boolean checkTextIsPresentOnElement(String text, String elementListKey) throws StopTestException {
        return checkTextIsPresentOnElement(text, elementListKey, new String[] {});
    }

    /**
     * Checks that a text is <b>not</b> present on the web element.
     * 
     * @param text
     *            not expected on the web element
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @param replaceArgs
     *            values to replace the place holders in the element list entry
     * @return {@code true} if the {@code text} is <b>not</b> present on the web
     *         element, {@code false} otherwise
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public boolean checkTextIsNotPresentOnElement(String text, String elementListKey, String... replaceArgs)
            throws StopTestException {
        return !checkTextIsPresentOnElement(text, elementListKey, replaceArgs);
    }

    /**
     * Checks that a text is <b>not</b> present on the web element.
     * 
     * @param text
     *            not expected on the web element
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @return {@code true} if the {@code text} is <b>not</b> present on the web
     *         element, {@code false} otherwise
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public boolean checkTextIsNotPresentOnElement(String text, String elementListKey) throws StopTestException {
        return checkTextIsNotPresentOnElement(text, elementListKey, new String[] {});
    }

    /**
     * Clears a element (e.g. an input field or text area).
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @param replaceArgs
     *            values to replace the place holders in the element list entry
     * @return always {@code true} to show inside FitNesse a positive result
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public boolean clearElement(String elementListKey, String... replaceArgs) throws StopTestException {
        WebElement element = findAvailableWebElement(elementListKey, replaceArgs);
        element.clear();
        return true;
    }

    /**
     * Clears a element (e.g. an input field or text area).
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @return always {@code true} to show inside FitNesse a positive result
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public boolean clearElement(String elementListKey) throws StopTestException {
        return clearElement(elementListKey, new String[] {});
    }

    /**
     * Returns the value for the given {@code attribute} of the web element. Use
     * 'innerText' as {@code attribute} to get the complete inner text of the
     * web element.
     * 
     * @param attribute
     *            the attribute of a web element or 'innertext'
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @param replaceArgs
     *            values to replace the place holders in the element list entry
     * @return the value of the {@code attribute} or {@code null} if the
     *         {@code attribute} does not exists
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public String readAttributeFromElement(String attribute, String elementListKey, String... replaceArgs)
            throws StopTestException {
        WebElement element = findAvailableWebElement(elementListKey, replaceArgs);
        if ("innerText".equalsIgnoreCase(attribute)) {
            return element.getText();
        } else {
            return element.getAttribute(attribute);
        }
    }

    /**
     * Returns the value for the given {@code attribute} of the web element. Use
     * 'innerText' as {@code attribute} to get the complete inner text of the
     * web element.
     * 
     * @param attribute
     *            the attribute of a web element or 'innertext'
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @return the value of the {@code attribute} or {@code null} if the
     *         {@code attribute} does not exists
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    public String readAttributeFromElement(String attribute, String elementListKey) throws StopTestException {
        return readAttributeFromElement(attribute, elementListKey, new String[] {});
    }

    /**
     * Finds and returns all web element in the DOM matching the technical
     * locator. This does not necessarily mean that the elements are visible.
     * The configured {@code timeout} is used to specify the time to wait for
     * the element.
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @param replaceArgs
     *            values to replace the place holders in the element list entry
     * @return the web elements or {@code null} if no matching element is
     *         present in the DOM
     * @throws StopTestException
     *             if a timeout occurred while finding the web elements
     */
    protected List<WebElement> findWebElements(String elementListKey, String... replaceArgs)
            throws StopTestException {
        int interval = (int) Math.floor(Math.sqrt(timeout));
        Wait<WebDriver> wait = new FluentWait<WebDriver>(webDriver).withTimeout(timeout, TimeUnit.SECONDS)
                .pollingEvery(interval, TimeUnit.SECONDS)
                .ignoring(NoSuchElementException.class, StaleElementReferenceException.class);
        try {
            return wait.until(
                    ExpectedConditions.presenceOfAllElementsLocatedBy(createBy(elementListKey, replaceArgs)));
        } catch (TimeoutException e) {
            throw new StopTestException("There was a timeout while finding the element '"
                    + createBy(elementListKey, replaceArgs) + "'!");
        }
    }

    /**
     * Finds and returns a web element displayed on the page. Always returns an
     * element or an exception.
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @param replaceArgs
     *            values to replace the place holders in the element list entry
     * @return the web element
     * @throws StopTestException
     *             if element not available (hidden, not present) or a timeout
     *             occurred
     */
    protected WebElement findAvailableWebElement(String elementListKey, String... replaceArgs)
            throws StopTestException {
        List<WebElement> elements = findWebElements(elementListKey, replaceArgs);

        for (WebElement webElement : elements) {
            if (webElement != null && webElement.isDisplayed()) {
                return webElement;
            }
        }

        throw new StopTestException("The specified Gui-Element for the Key '"
                + createBy(elementListKey, replaceArgs) + "' could not be found on web page!");
    }

    /**
     * Finds and returns a list of web element displayed on the page. If non
     * matching element, an empty list is returned.
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @param replaceArgs
     *            values to replace the place holders in the element list entry
     * @return a list of available (present and not hidden) web elements
     * @throws StopTestException
     *             if a timeout occurred
     */
    protected List<WebElement> findAllAvailableWebElements(String elementListKey, String... replaceArgs)
            throws StopTestException {
        int interval = (int) Math.floor(Math.sqrt(timeout));
        Wait<WebDriver> wait = new FluentWait<WebDriver>(webDriver).withTimeout(timeout, TimeUnit.SECONDS)
                .pollingEvery(interval, TimeUnit.SECONDS)
                .ignoring(NoSuchElementException.class, StaleElementReferenceException.class);
        try {
            return wait.until(
                    ExpectedConditions.visibilityOfAllElementsLocatedBy(createBy(elementListKey, replaceArgs)));
        } catch (TimeoutException e) {
            throw new StopTestException("There was a timeout while finding the element '"
                    + createBy(elementListKey, replaceArgs) + "'!");
        }
    }

    /**
     * Returns the locator for a given key.
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @return locator as String or an ElementKeyNotFoundException if locater
     *         not found (locater is never null)
     * 
     */
    protected String retrieveLocater(String elementListKey) {
        try {
            if (elementListKey == null) {
                throw new ElementKeyNotFoundException("Null is not a valid key!");
            }
            return elementListService.getValue(elementListKey);
        } catch (ElementKeyNotFoundException e) {
            throw new StopTestException(
                    "The specified Key '" + elementListKey + "' could not be found in element list!");
        }
    }

    /**
     * A special keyboard key is pressed.
     * 
     * @param specialKey
     *            the key to press (@see Keys)
     * @return {@code true} if pressing the key was successful, {@code false}
     *         otherwise
     * @throws StopTestException
     *             if key is invalid
     */
    public boolean pressSpecialKey(String specialKey) throws StopTestException {
        if (specialKey == null || specialKey.trim().isEmpty()) {
            throw new StopTestException("Invalid or empty key!");
        }

        try {
            Keys seleniumKey = Keys.valueOf(specialKey.trim().toUpperCase());
            new Actions(webDriver).sendKeys(seleniumKey).build().perform();
            return true;
        } catch (IllegalArgumentException e) {
            throw new StopTestException("The specified key '" + specialKey.trim().toUpperCase()
                    + "' is invalid and could not be found in selenium enum Keys!");
        }
    }

    /**
     * A special keyboard key is pressed on a displayed web element identified
     * by the element list key.
     * 
     * Therefore it is ensured that the element is available (present in DOM and
     * visible on web page). If element is not available a
     * {@code StopTestException} is thrown.
     * 
     * @param specialKey
     *            the key to press (@see Keys)
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @param replaceArgs
     *            values to replace the place holders in the element list entry
     * @return {@code true} if pressing the key was successful, {@code false}
     *         otherwise
     * @throws StopTestException
     *             if key is invalid, the element is not available or a timeout
     *             occurred
     */
    public boolean pressSpecialKeyOnElement(String specialKey, String elementListKey, String... replaceArgs)
            throws StopTestException {
        if (specialKey == null || specialKey.trim().isEmpty()) {
            throw new StopTestException("Invalid or empty key!");
        }

        WebElement element = findAvailableWebElement(elementListKey, replaceArgs);
        return pressSpecialKeyOnElement(specialKey, element);
    }

    /**
     * A special keyboard key is pressed on a displayed web element identified
     * by the element list key.
     * 
     * Therefore it is ensured that the element is available (present in DOM and
     * visible on web page). If element is not available a
     * {@code StopTestException} is thrown.
     * 
     * @param specialKey
     *            the key to press (@see Keys)
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @return {@code true} if pressing the key was successful, {@code false}
     *         otherwise
     * @throws StopTestException
     *             if key is invalid, the element is not available or a timeout
     *             occurred
     */
    public boolean pressSpecialKeyOnElement(String specialKey, String elementListKey) throws StopTestException {
        return pressSpecialKeyOnElement(specialKey, elementListKey, new String[] {});
    }

    /**
     * A special keyboard key is pressed on a web element.
     * 
     * @param specialKey
     *            the key to press (@see Keys)
     * @param element
     *            available web element
     * @return {@code true} if pressing the key was successful, {@code false}
     *         otherwise
     * @throws StopTestException
     *             if key is not a selenium {@code Keys}
     */
    protected boolean pressSpecialKeyOnElement(String specialKey, WebElement element) throws StopTestException {
        try {
            Keys seleniumKey = Keys.valueOf(specialKey.trim().toUpperCase());
            element.sendKeys(seleniumKey);
            return true;
        } catch (IllegalArgumentException e) {
            throw new StopTestException("The specified key '" + specialKey.trim().toUpperCase()
                    + "' is invalid and could not be found in selenium enum Keys!");
        }
    }

    /**
     * Creates a Selenium identifier for a GUI-element by the given element list
     * key and optional values for the element list entry place holders.
     * 
     * @param elementListKey
     *            key in the element list to find the technical locator
     * @param replaceArgs
     *            values to replace the place holders in the element list entry
     * @return a Selenium identifier for a GUI-element
     */
    // CHECKSTYLE:OFF
    protected By createBy(String elementListKey, String... replaceArgs) {
        // CHECKSTYLE:ON
        String locator = retrieveLocater(elementListKey);

        // replace arguments (e.g. {0}) in locater
        if (replaceArgs.length > 0) {
            Object[] args = Arrays.copyOf(replaceArgs, replaceArgs.length, Object[].class);
            locator = MessageFormat.format(locator, args);
        }

        // Apostrophes in X-Paths must escaped
        // locator = locator.replace("'", "''");

        if (locator.startsWith(ElementPrefix.ID.getName())) {
            locator = locator.substring(ElementPrefix.ID.getName().length());
            return By.id(locator);
        } else if (locator.startsWith(ElementPrefix.XPATH.getName())) {
            locator = locator.substring(ElementPrefix.XPATH.getName().length());
            return By.xpath(locator);
        } else if (locator.startsWith(ElementPrefix.CLASSNAME.getName())) {
            locator = locator.substring(ElementPrefix.CLASSNAME.getName().length());
            return By.className(locator);
        } else if (locator.startsWith(ElementPrefix.CSSSELECTOR.getName())) {
            locator = locator.substring(ElementPrefix.CSSSELECTOR.getName().length());
            return By.cssSelector(locator);
        } else if (locator.startsWith(ElementPrefix.LINKTEXT.getName())) {
            locator = locator.substring(ElementPrefix.LINKTEXT.getName().length());
            return By.linkText(locator);
        } else if (locator.startsWith(ElementPrefix.NAME.getName())) {
            locator = locator.substring(ElementPrefix.NAME.getName().length());
            return By.name(locator);
        } else if (locator.startsWith(ElementPrefix.PARTIAL.getName())) {
            locator = locator.substring(ElementPrefix.PARTIAL.getName().length());
            return By.partialLinkText(locator);
        } else if (locator.startsWith(ElementPrefix.TAGNAME.getName())) {
            locator = locator.substring(ElementPrefix.TAGNAME.getName().length());
            return By.tagName(locator);
        } else if (locator.startsWith("//")) {
            return By.xpath(locator);
        } else {
            return By.id(locator);
        }
    }

    /**
     * Stops the current test execution.
     * 
     * @throws StopTestException
     *             always thrown to stop the test
     */
    public void stopTestExecution() throws StopTestException {
        throw new StopTestException("Test execution stopped!");
    }

    @Override
    public void tearDown(boolean failer) {
        closeBrowser();
    }

    @Override
    public String getTestName() {
        return null;
    }

    @Override
    public void postInvoke(Method arg0, Object arg1, Object... arg2)
            throws InvocationTargetException, IllegalAccessException {
    }

    @Override
    public void preInvoke(Method arg0, Object arg1, Object... arg2)
            throws InvocationTargetException, IllegalAccessException {
    }

    @Override
    public void setTestName(String arg0) {
    }

}