com.gfk.senbot.framework.services.selenium.ElementService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of SenBotRunner Show documentation
Show all versions of SenBotRunner Show documentation
The SenBot runner which will actually run all your acceptance tests and report the outcome
package com.gfk.senbot.framework.services.selenium;
import static org.junit.Assert.*;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import com.gfk.senbot.framework.BaseServiceHub;
import com.gfk.senbot.framework.cucumber.stepdefinitions.ExpectedGlobalCondition;
import com.gfk.senbot.framework.data.SenBotReferenceService;
/**
* A util class for locating elements on a HTML page using seleniums
* {@link WebDriver}
*
* @author joostschouten
*
*/
public class ElementService extends BaseServiceHub {
private static Logger log = LoggerFactory.getLogger(ElementService.class);
public static final String XPATH_LOCATOR_PREFIX = "xpath:";
public static final String ID_LOCATOR_PREFIX = "id:";
public static final String NAME_ATTRIBUTE_LOCATOR_PREFIX = "name:";
public static final String CSS_LOCATOR_PREFIX = "css:";
/**
* A helper method to return an element based on the locator passed in. The
* locator can:
*
* - start with {@link #XPATH_LOCATOR_PREFIX} followed by the xpath
* leading to the element to locate
* - start with {@link #ID_LOCATOR_PREFIX} followed by the id used on the
* element to locate
* - start with {@link #NAME_ATTRIBUTE_LOCATOR_PREFIX} followed by name
* attribute value used on the element to locate
* - Be a logical name matching a {@link By} as specified in the
* {@link SenBotReferenceService#getElementLocatorForElementReference(String)}
*
*
*
* @param locatorString
* @return The found web element
*/
public WebElement translateLocatorToWebElement(String locatorString) {
return findExpectedElement(translateLocator(locatorString));
}
public By translateLocator(String locatorString) {
By locator = null;
String lowerCaseLocatorString = locatorString.toLowerCase();
if (lowerCaseLocatorString.startsWith(XPATH_LOCATOR_PREFIX)) {
locator = By.xpath(locatorString.replace(XPATH_LOCATOR_PREFIX, ""));
} else if (lowerCaseLocatorString.startsWith(ID_LOCATOR_PREFIX)) {
locator = By.id(locatorString.replace(ID_LOCATOR_PREFIX, ""));
} else if (lowerCaseLocatorString.startsWith(NAME_ATTRIBUTE_LOCATOR_PREFIX)) {
locator = By.xpath("//*[@name='" + locatorString.replace(NAME_ATTRIBUTE_LOCATOR_PREFIX, "") + "']");
} else if (lowerCaseLocatorString.startsWith(CSS_LOCATOR_PREFIX)) {
locator = By.cssSelector(locatorString.replace(CSS_LOCATOR_PREFIX, ""));
} else {
locator = getReferenceService().getElementLocatorForElementReference(locatorString);
}
return locator;
}
/**
* Find an element that is expected to be on the page. Elements that are on
* the page but are hidden will not be returned
*
* @param by
* - the {@link By} to find
* @return the matched {@link WebElement}
* @throws AssertionError
* if no {@link WebElement} is found or the search times out
*/
public WebElement findExpectedElement(By by) {
return findExpectedElement(by, false);
}
/**
* Find an element that is expected to be on the page
*
* @param by
* - the {@link By} to find
* @param includeHiddenElements
* - should hidden elements on the page be included or not
* @return the matched {@link WebElement}
* @throws AssertionError
* if no {@link WebElement} is found or the search times out
*/
public WebElement findExpectedElement(By by, boolean includeHiddenElements) {
log.debug("findExpectedElement() called with: " + by);
waitForLoaders();
try {
WebElement foundElement = new WebDriverWait(getWebDriver(), getSeleniumManager().getTimeout())
.until(ExpectedConditions.presenceOfElementLocated(by));
if (includeHiddenElements || foundElement.isDisplayed()) {
return foundElement;
} else {
// the element is found but not visible. Wait to see if it
// becomes visible
try {
new WebDriverWait(getWebDriver(), getSeleniumManager().getTimeout()).until(ExpectedConditions
.visibilityOfElementLocated(by));
return foundElement;
} catch (WebDriverException toe) {
fail("Element: " + by.toString() + " is found but not visible");
}
}
} catch (WebDriverException wde) {
log.error("Expected element not found: ", wde);
fail("Element: " + by.toString() + " not found after waiting for " + getSeleniumManager().getTimeout() + " seconds. Webdriver though exception: " + wde.getClass().getCanonicalName() + " with error message: " + wde.getMessage());
}
return null;
}
/**
* Find all elements expected on the page
*
* @param by
* - the {@link By} to find
* @return A list of the matched elements {List<@link WebElement>}
* @throws AssertionError
* if no {@link WebElement} is found or the search times out
*/
public List findExpectedElements(By by) {
waitForLoaders();
try {
return new WebDriverWait(getWebDriver(), getSeleniumManager().getTimeout())
.until(ExpectedConditions.presenceOfAllElementsLocatedBy(by));
} catch (WebDriverException wde) {
log.error("Expected elements not found: ", wde);
fail("Element: " + by.toString() + " not found after waiting for " + getSeleniumManager().getTimeout() + " seconds. Webdriver though exception: " + wde.getClass().getCanonicalName() + " with error message: " + wde.getMessage());
}
return null;
}
public WebElement findExpectedFirstMatchedElement(By... bys) {
return findExpectedFirstMatchedElement(0, bys);
}
/**
* From the passed array of {@link By}'s return the first {@link WebElement}
* found. The {@link By}'s will be processed in the order that they are
* passed in. If no element matches any of the {@link By}'s an
* {@link AssertionError} is thrown causing a test method calling this
* method to fail.
*
* @param timeoutInSeconds
* timeout to wait for elements to be found
* @param bys
* - array of {@link By}
* @return The first {@link WebElement} found
* @throws AssertionError
* if no {@link WebElement} is found or the search times out
*/
public WebElement findExpectedFirstMatchedElement(int timeoutInSeconds, By... bys) {
waitForLoaders();
StringBuilder potentialMatches = new StringBuilder();
for (By by : bys) {
try {
if (potentialMatches.length() > 0) {
potentialMatches.append(", ");
}
potentialMatches.append(by.toString());
WebElement found = new WebDriverWait(getWebDriver(), timeoutInSeconds).until(ExpectedConditions
.presenceOfElementLocated(by));
if (found != null) {
return found;
}
} catch (WebDriverException nsee) {
// keep checking
}
}
fail("No matches found for: " + potentialMatches.toString());
return null;
}
/**
* As most browsers do not yet support XPath 2.0 which offers a matches
* function, we'll use this hacky Case insensitive check
*
* @return XPath that wity match the passed value argument in a case insensitive manner
*/
public String constructCaseInsensitiveContains(String identifier, String value) {
return "contains(translate(" + identifier + ",'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz'), '"
+ value.toLowerCase() + "')";
}
/**
* Check if the passed element is visible/invisible
*
* @param by {@link By} to be matched
* @param visible
* should the element be visible (true) or invisible (false)
*/
public void isElementVisible(By locator, boolean visible) {
waitForLoaders();
if (visible) {
try {
WebElement found = new WebDriverWait(getWebDriver(), getSeleniumManager().getTimeout())
.until(ExpectedConditions.visibilityOfElementLocated(locator));
} catch (WebDriverException e) {
fail("The element " + locator.toString()
+ " is not found or invisible where it is expected as present and visible");
}
} else {
try {
boolean invisible = new WebDriverWait(getWebDriver(), getSeleniumManager().getTimeout())
.until(ExpectedConditions.invisibilityOfElementLocated(locator));
} catch (WebDriverException e) {
fail("The element " + locator.toString() + " is visible where it is expected as invisible");
}
}
}
public void isElementVisible(WebElement element, boolean visible) throws InterruptedException {
assertExpectedGlobalConditions();
if (visible) {
new WebDriverWait(getWebDriver(), getSeleniumManager().getTimeout()).until(
ExpectedConditions.visibilityOf(element));
} else {
long currentTimeMillis = System.currentTimeMillis();
while(element.isDisplayed()) {
Thread.sleep(100);
if(System.currentTimeMillis() - currentTimeMillis > (getSeleniumManager().getTimeout() * 1000)) {
assertFalse("We expect the following element to be invisible: " + element.toString() , element.isDisplayed());
}
}
}
}
/**
* Tells whether the passed element exists
*
* @param locator {@link By} to be matched
* @return true if the element exists
*/
public boolean getElementExists(By locator) {
waitForLoaders();
List foundElements = getWebDriver().findElements(locator);
return (foundElements.size() > 0);
}
/**
* An application might show an icon while loading. Calling this method
* waits for the loading icon to disappear. Use this method sparsely as it
* consumes lots of waiting time
*
* @deprecated use {@link ElementService#assertExpectedGlobalConditions} in stead
*/
public void waitForLoaders() {
assertExpectedGlobalConditions();
}
public void assertExpectedGlobalConditions() {
if (getScenarioGlobals() != null && !getScenarioGlobals().getExpectedGlobalConditions().isEmpty()) {
log.debug("assertExpectedGlobalConditions() called, will check for " + getScenarioGlobals().getExpectedGlobalConditions().size() + " conditions");
for (ExpectedGlobalCondition condition : getScenarioGlobals().getExpectedGlobalConditions()) {
log.debug("Check condition: " + condition);
condition.checkExpected(getWebDriver());
}
}
}
/**
* Drags an element some place else
*
* @param draggable
* The element to drag
* @param droppable
* The drop aim
* @throws InterruptedException
*/
public void dragElementTo(String draggable, String droppable) throws InterruptedException {
dragElementTo(draggable, droppable, 0);
}
/**
* Drags an element some place else
*
* @param draggable
* The element to drag
* @param droppable
* The drop aim
* @param waitForMillies
* ???
* @throws InterruptedException
*/
public void dragElementTo(String draggable, String droppable, int waitForMillies) throws InterruptedException {
WebElement draggableEl = translateLocatorToWebElement(draggable);
WebElement dragReceiver = translateLocatorToWebElement(droppable);
Actions clickAndDrag = new Actions(getWebDriver());
clickAndDrag.dragAndDrop(draggableEl, dragReceiver);
clickAndDrag.perform();
// ToDO: clarify what to do with the parameter waitForMillies
}
/**
* Drags an element some place else
*
* @param draggable
* The element to drag
* @param droppable
* The drop aim
* @throws InterruptedException
*/
public void dragElementTo(By draggable, By droppable) throws InterruptedException {
WebDriver driver = getWebDriver();
Actions clickAndDrag = new Actions(getWebDriver());
clickAndDrag.dragAndDrop(driver.findElement(draggable), driver.findElement(droppable));
clickAndDrag.perform();
}
/**
* Drags an element some place else
*
* @param draggable
* The element to drag
* @param x
* Offset
* @param y
* Offset
* @throws InterruptedException
*/
public void dragElementTo(By draggable, int x, int y) throws InterruptedException {
WebDriver driver = getWebDriver();
Actions clickAndDrag = new Actions(getWebDriver());
clickAndDrag.dragAndDropBy(driver.findElement(draggable), x, y);
clickAndDrag.perform();
}
/**
* Clicks a button. Always use this method if you plan to run the tests on
* IE9 In IE9 element.click() does not in a reliable way on buttons.
*
* @param button
* The element to click at
* @deprecated I'm sure there are better ways to click a button. Legacy code
* we need to remove at some stage.
*/
public void ieSaveButtonClick(WebElement button) {
WebDriver driver = getWebDriver();
// This shall solve the clicking problems IE9 has
if (driver instanceof InternetExplorerDriver) {
((JavascriptExecutor) driver).executeScript("arguments[0].click()", button);
} else {
button.click();
}
}
public void waitForInvisibilityOfElement(WebElement element) throws InterruptedException {
long start = System.currentTimeMillis();
try {
while (element.isDisplayed()) {
if (System.currentTimeMillis() - start > getSeleniumManager().getTimeout() * 1000) {
throw new TimeoutException("The element " + element
+ " was visible for longer than the timout period of " + getSeleniumManager().getTimeout()
+ " seconds");
}
Thread.sleep(100);
}
} catch (StaleElementReferenceException sere) {
// the element is not attached to the document which means it is
// invisible
}
}
/**
*
* @param viewName
* @param elementName
* @return {@link WebElement}
* @throws IllegalArgumentException
* @throws IllegalAccessException
*
* @return {@link WebElement} by the elementName parameter on the view defined by the parameter viewName
*/
public WebElement getElementFromReferencedView(String viewName, String elementName)
throws IllegalArgumentException, IllegalAccessException {
Class pageRepresentationReference = getReferenceService().getPageRepresentationReference(viewName);
Object instance = getSeleniumManager().getViewRepresentation(pageRepresentationReference, false);
Field field = getElementFieldFromReferencedView(pageRepresentationReference, viewName, elementName);
if(field != null) {
return (WebElement) field.get(instance);
}
return null;
}
private Field getElementFieldFromReferencedView(Class pageRepresentationReference, String viewName, String elementName) {
Field[] declaredFields = pageRepresentationReference.getDeclaredFields();
PropertyDescriptor[] propertyDescriptors = BeanUtils.getPropertyDescriptors(pageRepresentationReference);
Object instance = getSeleniumManager().getViewRepresentation(pageRepresentationReference, false);
String lowerCaseName = elementName.replaceAll(" ", "_").toLowerCase();
for (Field field : declaredFields) {
if (field.getName().toLowerCase().equals(lowerCaseName)) {
return field;
}
}
fail("The element reference \"" + elementName + "\" has not been defined in view \"" + viewName + "\" (object ref: "
+ pageRepresentationReference.getName() + "." + lowerCaseName + ")");
return null;
}
public String getElementLocatorFromReferencedView(String viewName, String elementName) {
FindBy findByAnnotatio = getFindByDescriptor(viewName, elementName);
return findByAnnotatio.how() + ":" + findByAnnotatio.using();
}
public FindBy getFindByDescriptor(String viewName, String elementName) {
Class pageRepresentationReference = getReferenceService().getPageRepresentationReference(viewName);
Field field = getElementFieldFromReferencedView(pageRepresentationReference, viewName, elementName);
FindBy findByAnnotatio = field.getAnnotation(FindBy.class);
return findByAnnotatio;
}
/**
*
* @param viewName
* @param elementName
* @return {@link WebElement}
* @throws IllegalAccessException
*
*/
public WebElement viewShouldContainElement(String viewName, String elementName) throws IllegalAccessException {
WebElement found = getElementFromReferencedView(viewName, elementName);
boolean notFound = true;
try {
notFound = found == null;
waitForLoaders();
found = new WebDriverWait(getWebDriver(), getSeleniumManager().getTimeout()).until(ExpectedConditions
.visibilityOf(found));
} catch (NoSuchElementException e) {
// leave fail = true
}
if (notFound) {
String foundLocator = getElementLocatorFromReferencedView(viewName, elementName);
fail("The element \"" + foundLocator + "\" referenced by element name \"" + elementName + "\" on view/page \"" + viewName + "\" is not found after " + getSeleniumManager().getTimeout() + " seconds");
}
return found;
}
/**
* The referenced view should not show the element identified by elementName
*
* @param viewName
* @param elementName
* @throws IllegalAccessException
* @throws InterruptedException
*/
public void viewShouldNotShowElement(String viewName, String elementName) throws IllegalAccessException,
InterruptedException {
boolean pass = false;
long startOfLookup = System.currentTimeMillis();
int timeoutInMillies = getSeleniumManager().getTimeout() * 1000;
while (!pass) {
WebElement found = getElementFromReferencedView(viewName, elementName);
try {
pass = !found.isDisplayed();
} catch (NoSuchElementException e) {
pass = true;
}
if (!pass) {
Thread.sleep(100);
}
if (System.currentTimeMillis() - startOfLookup > timeoutInMillies) {
String foundLocator = getElementLocatorFromReferencedView(viewName, elementName);
fail("The element \"" + foundLocator + "\" referenced by \"" + elementName + "\" on view/page \"" + viewName + "\" is still found where it is not expected after " + getSeleniumManager().getTimeout() + " seconds.");
break;
}
}
}
/**
*
* @param viewName
* @param elementName
* @return {@link WebElement}
* @throws IllegalAccessException
*/
public WebElement viewShouldShowElement(String viewName, String elementName) throws IllegalAccessException {
WebElement found = getElementFromReferencedView(viewName, elementName);
waitForLoaders();
try {
found = new WebDriverWait(getWebDriver(), getSeleniumManager().getTimeout()).until(ExpectedConditions.visibilityOf(found));
}
catch (Exception e) {
String notFoundLocator = getElementLocatorFromReferencedView(viewName, elementName);
fail("The element \"" + notFoundLocator + "\" referenced by element name \"" + elementName+ "\" on view/page \"" + viewName + "\" is not found after a wait of " + getSeleniumManager().getTimeout() + " seconds.");
}
return found;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy