br.ufmg.dcc.saotome.beholder.selenium.ui.SeleniumComponent.java Source code

Java tutorial

Introduction

Here is the source code for br.ufmg.dcc.saotome.beholder.selenium.ui.SeleniumComponent.java

Source

/*  Copyright 2014 ?caro Clever da Fonseca Braga
    
   Licensed to the Apache Software Foundation (ASF) under one
   or more contributor license agreements.  See the NOTICE file
   distributed with this work for additional information
   regarding copyright ownership.  The ASF licenses this file
   to you 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 br.ufmg.dcc.saotome.beholder.selenium.ui;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import br.ufmg.dcc.saotome.beholder.selenium.message.ErrorMessages;
import br.ufmg.dcc.saotome.beholder.ui.Component;

/**
 * This abstract class implements the interface HtmlComponent using the
 * Selenium-Webdriver to simulate the interaction between the component and a
 * system user.
 * 
 * @author ?caro Clever F. Braga (icaroclever@gmail.com)
 * @see Component
 */
public abstract class SeleniumComponent implements Component {

    private static class Locator {

        public enum LocatorType {
            ATTRIBUTE, ID, NAME, XPATH;

        }

        private LocatorType loadBy;
        private String value;
        private String tagName;
        private String attributeName;

        public Locator(LocatorType loadBy, String value) {
            this.loadBy = loadBy;
            this.value = value;
        }

        public Locator(String tagName, String attributeName, String value) {
            this(LocatorType.ATTRIBUTE, value);
            this.attributeName = attributeName;
            this.tagName = tagName;
        }
    }

    private final WebDriver selenium;
    private SeleniumComponent parent;
    private Boolean isDisplayed = true;
    private Locator locator;

    /** Maximum wait for a component */
    public static final long TIMEOUT = 30;// seconds

    private WebElement element;
    private Map<String, String> attributes = new HashMap<String, String>();

    public SeleniumComponent(final WebDriver driver) {
        this.selenium = driver;
    }

    /**
     * The Selenium-Webdriver element that represents the component HTML of the
     * simulated page.
     * 
     * @return WebElement element
     */
    public final WebElement getElement() {
        return this.element;
    }

    /**
     * The Selenium-Webdriver element that represents the component HTML of the
     * simulated page.
     * 
     * @param element WebElement object
     */
    public final void setElement(final WebElement element) {

        if (element == null) {
            throw new IllegalArgumentException(
                    String.format(ErrorMessages.ERROR_TEMPLATE_VARIABLE_NULL, "element"));
        }

        this.element = element;

        validateElementTag();
        validateAttributes();
    }

    @Override
    public String getAttribute(final String attribute) {
        if (this.getElement() == null) {
            throw new IllegalArgumentException(ErrorMessages.ERROR_ELEMENT_WAS_NOT_LOADED);
        }
        if (attribute == null || attribute.isEmpty()) {
            throw new IllegalArgumentException(ErrorMessages.ERROR_ATTRIBUTE_EMPTY);
        }

        return this.getElement().getAttribute(attribute);
    }

    @Override
    public void setAttribute(final String attribute, final String value) {
        if (attribute == null || attribute.isEmpty()) {
            throw new IllegalArgumentException(ErrorMessages.ERROR_ATTRIBUTE_EMPTY);
        }

        if (value == null) {
            throw new IllegalArgumentException(String.format(ErrorMessages.ERROR_TEMPLATE_VARIABLE_NULL, "value"));
        }

        this.attributes.put(attribute, value);
    }

    @Override
    public void loadByAttribute(final String tagName, final String attributeName, final String value) {

        this.locator = new Locator(tagName, attributeName, value);

        if (this.isDisplayed) {
            WebDriverWait wait = new WebDriverWait(getSeleniumWebDriver(), TIMEOUT);
            ExpectedCondition<Boolean> resultsAreDisplayed = new ExpectedCondition<Boolean>() {

                public Boolean apply(WebDriver arg0) {
                    List<WebElement> elements = getSeleniumWebDriver().findElements(By.tagName(tagName));
                    for (WebElement el : elements) {
                        if ((el.getAttribute(attributeName) != null)
                                && (el.getAttribute(attributeName).equalsIgnoreCase(value))) {
                            setAttribute(attributeName, value);
                            setElement(el);
                            return true;
                        }
                    }
                    return false;
                }

            };
            wait.until(resultsAreDisplayed);
        }
    }

    @Override
    public <T extends Component, Y extends T> List<T> loadByAttribute(Class<Y> type, final String IdFather,
            final String tagName, final String attributeName, final String value) {

        List<T> components = new ArrayList<T>();

        this.locator = new Locator(tagName, attributeName, value);

        if (this.isDisplayed) {
            WebDriverWait wait = new WebDriverWait(getSeleniumWebDriver(), TIMEOUT);

            wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.tagName(tagName)));
            List<WebElement> elements;

            if (IdFather == null) {
                elements = getSeleniumWebDriver().findElements(By.tagName(tagName));
            } else {
                elements = getSeleniumWebDriver().findElement(By.id(IdFather)).findElements(By.tagName(tagName));
            }

            for (WebElement el : elements) {
                if ((el.getAttribute(attributeName) != null)
                        && (el.getAttribute(attributeName).equalsIgnoreCase(value))) {
                    T sc = null;

                    try {
                        // Use of reflection for instantiate sc 
                        // this equivalent the get an instance of Builder.uiComponentBuilderInstance()
                        sc = (T) type.getDeclaredConstructor(WebDriver.class).newInstance(getSeleniumWebDriver());

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

                    ((SeleniumComponent) sc).setAttribute(attributeName, value);
                    ((SeleniumComponent) sc).setElement(el);
                    components.add(sc);
                }
            }
        }
        return components;
    }

    @Override
    public final String getId() {
        return this.getAttribute("id");
    }

    @Override
    public void setId(String value) {
        this.setAttribute("id", value);
    }

    @Override
    public void loadById(final String value) {
        this.locator = new Locator(Locator.LocatorType.ID, value);
        if (this.isDisplayed) {
            this.setId(value);
            this.setElement(selenium.findElement(By.id(value)));
        }
    }

    public void reloadElement() {
        switch (this.locator.loadBy) {
        case ID:
            loadById(this.locator.value);
            break;
        case NAME:
            loadByName(this.locator.value);
            break;
        case ATTRIBUTE:
            loadByAttribute(this.locator.tagName, locator.attributeName, this.locator.value);
            break;
        case XPATH:
            loadByXPath(this.locator.value);
            break;
        }
    }

    @Override
    public final String getName() {
        return this.getAttribute("name");
    }

    @Override
    public void setName(String value) {
        this.setAttribute("name", value);
    }

    @Override
    public void loadByName(final String value) {
        this.locator = new Locator(Locator.LocatorType.NAME, value);
        if (this.isDisplayed) {
            this.setName(value);
            this.setElement(selenium.findElement(By.name(value)));
        }
    }

    @Override
    public final String getXPath() {
        return this.getAttribute("xpath");
    }

    @Override
    public void setXPath(String value) {
        this.setAttribute("xpath", value);
    }

    @Override
    public void loadByXPath(final String value) {
        this.locator = new Locator(Locator.LocatorType.XPATH, value);
        if (this.isDisplayed) {
            WebDriverWait wait = new WebDriverWait(getSeleniumWebDriver(), TIMEOUT);
            wait.until(ExpectedConditions.visibilityOf(getSeleniumWebDriver().findElement(By.xpath(value))));
            setXPath(value);
            setElement(getSeleniumWebDriver().findElement(By.xpath(value)));
        }

    }

    /**
     * Verify if the element loaded is a valid element for the class that is
     * representing it.
     * 
     * @return Returns true if the HTML tag is valid to current class, otherwise
     *         false.
     * @throws RuntimeException
     *             if the element is invalid.
     */
    public abstract boolean isValidElementTag();

    /**
     * Verify if the element loaded is a valid element for the class that is
     * representing it.
     */
    public void validateElementTag() {

        String errorMsg = String.format(ErrorMessages.ERROR_INVALID_TAG_TO_CLASS, getElement().getTagName());

        if (!isValidElementTag()) {
            throw new IllegalArgumentException(errorMsg);
        }
    }

    public void validateAttributes() {

        for (Entry<String, String> attribute : this.attributes.entrySet()) {
            if (!attribute.getKey().equals("xpath"))
                if (!getElement().getAttribute(attribute.getKey()).equalsIgnoreCase(attribute.getValue())) {
                    throw new IllegalArgumentException(ErrorMessages.ERROR_ELEMENTS_ATTRIBUTES_NOT_MATCH);
                }

        }

    }

    /**
     * This method returns a Selenium Driver instance.
     * 
     * @return Selenium Driver
     */
    public final WebDriver getSeleniumWebDriver() {
        return selenium;
    }

    /**
     * This method returns the basic location that represents the html object in
     * the html page. For example, if a object is identified by tag <tag
     * attrib="foo">, the basic xpath must be a[ \@attrib='foo' ]
     * 
     * @return Returns a minimal xpath representation of the html object on the
     *         browser's page.
     */
    public abstract String getBasicLocator();

    /**
     * Returns the relative locator to find the html object on HTML page using
     * the index of the HTML object to recover it.
     * 
     * @param index
     *            HTML index of the object. Starts with 1.
     * @return Returns a relative xpath representation of the html object on the
     *         browser's page.
     */
    public String getLocator(Integer index) {

        String relLocator = ".//";

        if (getBasicLocator().contains("[")) {
            relLocator += getBasicLocator().replace("]", " and position()=%d ]");
        } else {
            relLocator += "%s[%d]";
        }

        return String.format(relLocator, index);
    }

    /**
     * Getter to the parent component
     * @return the parent
     */
    public SeleniumComponent getParent() {
        return parent;
    }

    /**
     * Setter to the parent compoment
     * @param parent
     *            the parent to set
     */
    public void setParent(SeleniumComponent parent) {
        this.parent = parent;
    }

    @Override
    public void show() {
        this.isDisplayed = true;
        reloadElement();
    }

    @Override
    public boolean isDisplayed() {
        return this.isDisplayed;
    }

    @Override
    public void hide() {
        this.isDisplayed = false;
    }
}