org.xwiki.test.ui.framework.elements.BaseElement.java Source code

Java tutorial

Introduction

Here is the source code for org.xwiki.test.ui.framework.elements.BaseElement.java

Source

/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.xwiki.test.ui.framework.elements;

import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.NotFoundException;
import org.openqa.selenium.RenderedWebElement;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.pagefactory.AjaxElementLocatorFactory;
import org.openqa.selenium.support.pagefactory.ElementLocatorFactory;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.TimeoutException;
import org.openqa.selenium.support.ui.Wait;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.xwiki.test.ui.framework.PersistentTestContext;
import org.xwiki.test.ui.framework.TestUtils;

/**
 * Represents all elements which include web pages as well as parts of web pages.
 * 
 * @version $Id: 2e79c4fc91c9af5d0f64c4b6b48b2812bb5f9e85 $
 * @since 2.4M1
 */
public class BaseElement {
    private static PersistentTestContext context;

    /** Used so that AllTests can set the persistent test context. */
    public static void setContext(PersistentTestContext context) {
        BaseElement.context = context;
    }

    public BaseElement() {
        ElementLocatorFactory finder = new AjaxElementLocatorFactory(this.getDriver(), getUtil().getTimeout());
        PageFactory.initElements(finder, this);
    }

    protected WebDriver getDriver() {
        return context.getDriver();
    }

    /**
     * @return Utility class with functions not specific to any test or element.
     */
    protected TestUtils getUtil() {
        return context.getUtil();
    }

    /**
     * Wait until the element given by the locator is displayed. Give up after timeout seconds.
     * 
     * @param locator the locator for the element to look for.
     */
    public void waitUntilElementIsVisible(final By locator) {
        this.waitUntilElementIsVisible(locator, getUtil().getTimeout());
    }

    /**
     * Wait until the element given by the locator is displayed.
     * 
     * @param locator the locator for the element to look for.
     * @param timeout how long to wait in seconds before giving up.
     */
    public void waitUntilElementIsVisible(final By locator, int timeout) {
        waitUntilElementsAreVisible(new By[] { locator }, timeout, true);
    }

    /**
     * Wait until one or all of a array of element locators are displayed.
     * 
     * @param locators the array of element locators to look for.
     * @param all if true then don't return until all elements are found. Otherwise return after finding one.
     */
    public void waitUntilElementsAreVisible(final By[] locators, final boolean all) {
        waitUntilElementsAreVisible(locators, getUtil().getTimeout(), all);
    }

    /**
     * Wait until one or all of a array of element locators are displayed.
     * 
     * @param locators the array of element locators to look for.
     * @param timeout how long to wait in seconds before giving up.
     * @param all if true then don't return until all elements are found. Otherwise return after finding one.
     */
    public void waitUntilElementsAreVisible(final By[] locators, int timeout, final boolean all) {
        Wait<WebDriver> wait = new WebDriverWait(this.getDriver(), timeout);
        try {
            wait.until(new ExpectedCondition<WebElement>() {
                public WebElement apply(WebDriver driver) {
                    RenderedWebElement element = null;
                    for (int i = 0; i < locators.length; i++) {
                        try {
                            element = (RenderedWebElement) driver.findElement(locators[i]);
                        } catch (NotFoundException e) {
                            // This exception is caught by WebDriverWait
                            // but it returns null which is not necessarily what we want.
                            if (all) {
                                return null;
                            }
                            continue;
                        }
                        // At this stage it's possible the element is no longer valid (for example if the DOM has
                        // changed). If it's no longer attached to the DOM then consider we haven't found the element
                        // yet.
                        try {
                            if (element.isDisplayed()) {
                                if (!all) {
                                    return element;
                                }
                            } else if (all) {
                                return null;
                            }
                        } catch (StaleElementReferenceException e) {
                            // Consider we haven't found the element yet
                            return null;
                        }
                    }
                    return element;
                }
            });
        } catch (TimeoutException e) {
            StringBuffer sb = new StringBuffer("Failed to find the following locators: [\n");
            for (By by : locators) {
                sb.append(by).append("\n");
            }
            sb.append("] in the source [\n");
            sb.append(getDriver().getPageSource());
            sb.append("\n]");
            throw new TimeoutException(sb.toString(), e);
        }
    }

    public void waitUntilElementDisappears(final By locator) {
        waitUntilElementDisappears(locator, getUtil().getTimeout());
    }

    /**
     * Waits until the given element is either hidden or deleted.
     * 
     * @param locator
     * @param timeout
     */
    public void waitUntilElementDisappears(final By locator, int timeout) {
        Wait<WebDriver> wait = new WebDriverWait(this.getDriver(), timeout);
        wait.until(new ExpectedCondition<Boolean>() {
            public Boolean apply(WebDriver driver) {
                try {
                    RenderedWebElement element = (RenderedWebElement) driver.findElement(locator);
                    return Boolean.valueOf(!element.isDisplayed());
                } catch (NotFoundException e) {
                    return Boolean.TRUE;
                } catch (StaleElementReferenceException e) {
                    // The element was removed from DOM in the meantime
                    return Boolean.TRUE;
                }
            }
        });
    }

    /**
     * Shows hidden elements, as if they would be shown on hover. Currently implemented using JavaScript. Will throw a
     * {@link RuntimeException} if the web driver does not support JavaScript or JavaScript is disabled.
     * 
     * @param locator locator used to find the element, in case multiple elements are found, the first is used
     */
    public void makeElementVisible(By locator) {
        makeElementVisible(this.getDriver().findElement(locator));
    }

    public void makeElementVisible(WebElement element) {
        // RenderedWebElement.hover() don't seem to work, workarounded using JavaScript call
        executeJavascript("arguments[0].style.visibility='visible'", element);
    }

    /**
     * Waits until the given element has a certain value for an attribute.
     * 
     * @param locator the element to wait on
     * @param attributeName the name of the attribute to check
     * @param expectedValue the attribute value to wait for
     */
    public void waitUntilElementHasAttributeValue(final By locator, final String attributeName,
            final String expectedValue) {
        waitUntilElementHasAttributeValue(locator, attributeName, expectedValue, getUtil().getTimeout());
    }

    /**
     * Waits until the given element ends with a certain value for an attribute.
     *
     * @param locator the element to wait on
     * @param attributeName the name of the attribute to check
     * @param expectedValue the attribute value to wait for
     */
    public void waitUntilElementEndsWithAttributeValue(final By locator, final String attributeName,
            final String expectedValue) {
        waitUntilElementEndsWithAttributeValue(locator, attributeName, expectedValue, getUtil().getTimeout());
    }

    /**
     * Waits until the given element has a certain value for an attribute.
     * 
     * @param locator the element to wait on
     * @param attributeName the name of the attribute to check
     * @param expectedValue the attribute value to wait for
     * @param timeout the maximum number of seconds to wait
     */
    public void waitUntilElementHasAttributeValue(final By locator, final String attributeName,
            final String expectedValue, int timeout) {
        Wait<WebDriver> wait = new WebDriverWait(getDriver(), timeout);
        wait.until(new ExpectedCondition<Boolean>() {
            public Boolean apply(WebDriver driver) {
                try {
                    RenderedWebElement element = (RenderedWebElement) driver.findElement(locator);
                    return expectedValue.equals(element.getAttribute(attributeName));
                } catch (NotFoundException e) {
                    return false;
                } catch (StaleElementReferenceException e) {
                    // The element was removed from DOM in the meantime
                    return false;
                }
            }
        });
    }

    /**
     * Waits until the given element ends with a certain value for an attribute.
     *
     * @param locator the element to wait on
     * @param attributeName the name of the attribute to check
     * @param expectedValue the attribute value to wait for
     * @param timeout the maximum number of seconds to wait
     */
    public void waitUntilElementEndsWithAttributeValue(final By locator, final String attributeName,
            final String expectedValue, int timeout) {
        Wait<WebDriver> wait = new WebDriverWait(getDriver(), timeout);
        wait.until(new ExpectedCondition<Boolean>() {
            public Boolean apply(WebDriver driver) {
                try {
                    RenderedWebElement element = (RenderedWebElement) driver.findElement(locator);
                    return element.getAttribute(attributeName).endsWith(expectedValue);
                } catch (NotFoundException e) {
                    return false;
                } catch (StaleElementReferenceException e) {
                    // The element was removed from DOM in the meantime
                    return false;
                }
            }
        });
    }

    /**
     * Waits until the given element has a certain value as its inner text.
     * 
     * @param locator the element to wait on
     * @param expectedValue the content value to wait for
     * @since 2.4
     */
    public void waitUntilElementHasTextContent(final By locator, final String expectedValue) {
        this.waitUntilElementHasTextContent(locator, expectedValue, getUtil().getTimeout());
    }

    /**
     * Waits until the given element has a certain value as its inner text.
     * 
     * @param locator the element to wait on
     * @param expectedValue the content value to wait for
     * @param timeout the maximum number of seconds to wait
     * @since 2.4
     */
    public void waitUntilElementHasTextContent(final By locator, final String expectedValue, int timeout) {
        Wait<WebDriver> wait = new WebDriverWait(getDriver(), timeout);
        wait.until(new ExpectedCondition<Boolean>() {
            public Boolean apply(WebDriver driver) {
                RenderedWebElement element = (RenderedWebElement) driver.findElement(locator);
                return Boolean.valueOf(expectedValue.equals(element.getText()));
            }
        });
    }

    public Object executeJavascript(String javascript, Object... arguments) {
        if (!(this.getDriver() instanceof JavascriptExecutor)) {
            throw new RuntimeException("Currently used web driver (" + this.getDriver().getClass()
                    + ") does not support JavaScript execution");
        }
        JavascriptExecutor js = (JavascriptExecutor) this.getDriver();
        if (!js.isJavascriptEnabled()) {
            throw new RuntimeException("JavaScript is disabled");
        }
        return js.executeScript(javascript, arguments);
    }

    /**
     * There is no easy support for alert/confirm window methods yet, see -
     * http://code.google.com/p/selenium/issues/detail?id=27 -
     * http://www.google.com/codesearch/p?hl=en#2tHw6m3DZzo/branches
     * /merge/common/test/java/org/openqa/selenium/AlertsTest.java The aim is : <code>
     * Alert alert = this.getDriver().switchTo().alert();
     * alert.accept();
     * </code> Until then, the following hack does override the confirm method in Javascript to return the given value.
     * 
     * @param {@code true} to accept the confirmation dialog, {@code false} to cancel it
     */
    public void makeConfirmDialogSilent(boolean accept) {
        String script = String.format("window.confirm = function() { return %s; }", accept);
        ((JavascriptExecutor) this.getDriver()).executeScript(script);
    }
}