Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.github.aquality-automation</groupId>
<artifactId>aquality-selenium-core</artifactId>
<version>1.0.2</version>
<version>1.1.0</version>

<packaging>jar</packaging>
<name>Aquality Selenium Core</name>
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/aquality/selenium/core/elements/Element.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.openqa.selenium.remote.RemoteWebElement;

import java.time.Duration;
import java.util.List;
import java.util.function.Supplier;

public abstract class Element implements IElement {
Expand Down Expand Up @@ -128,6 +129,16 @@ public <T extends IElement> T findChildElement(By childLoc, String name, IElemen
return getElementFactory().findChildElement(this, childLoc, name, supplier, state);
}

@Override
public <T extends IElement> List<T> findChildElements(By childLoc, String name, Class<T> clazz, ElementState state, ElementsCount count) {
return getElementFactory().findChildElements(this, childLoc, name, clazz, count, state);
}

@Override
public <T extends IElement> List<T> findChildElements(By childLoc, String name, IElementSupplier<T> supplier, ElementState state, ElementsCount count) {
return getElementFactory().findChildElements(this, childLoc, name, supplier, count, state);
}

protected <T> T doWithRetry(Supplier<T> action) {
return getElementActionRetrier().doWithRetry(action);
}
Expand Down
77 changes: 71 additions & 6 deletions src/main/java/aquality/selenium/core/elements/ElementFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import aquality.selenium.core.waitings.IConditionalWait;
import com.google.inject.Inject;
import org.openqa.selenium.By;
import org.openqa.selenium.By.ByTagName;
import org.openqa.selenium.By.ByXPath;
import org.openqa.selenium.InvalidArgumentException;
import org.openqa.selenium.WebElement;
Expand All @@ -26,6 +27,8 @@
public class ElementFactory implements IElementFactory {

private static final int XPATH_SUBSTRING_BEGIN_INDEX = 10;
private static final int TAGNAME_SUBSTRING_BEGIN_INDEX = 12;
private static final String TAGNAME_XPATH_PREFIX = "//";
private static final Duration ZERO_TIMEOUT = Duration.ZERO;

private final IConditionalWait conditionalWait;
Expand Down Expand Up @@ -59,10 +62,23 @@ public <T extends IElement> T findChildElement(IElement parentElement, By childL
@Override
public <T extends IElement> T findChildElement(IElement parentElement, By childLoc, String name, IElementSupplier<T> supplier, ElementState state) {
String childName = name == null ? "Child element of ".concat(parentElement.getName()) : name;
By fullLocator = new ByChained(parentElement.getLocator(), childLoc);
By fullLocator = generateAbsoluteChildLocator(parentElement.getLocator(), childLoc);
return supplier.get(fullLocator, childName, state);
}

@Override
public <T extends IElement> List<T> findChildElements(IElement parentElement, By childLoc, String name, Class<T> clazz, ElementsCount count, ElementState state) {
IElementSupplier<T> elementSupplier = getDefaultElementSupplier(clazz);
return findChildElements(parentElement, childLoc, name, elementSupplier, count, state);
}

@Override
public <T extends IElement> List<T> findChildElements(IElement parentElement, By childLoc, String name, IElementSupplier<T> supplier, ElementsCount count, ElementState state) {
String childName = name == null ? "Child element of ".concat(parentElement.getName()) : name;
By fullLocator = generateAbsoluteChildLocator(parentElement.getLocator(), childLoc);
return findElements(fullLocator, childName, supplier, count, state);
}

@Override
public <T extends IElement> List<T> findElements(By locator, String name, IElementSupplier<T> supplier,
ElementsCount count, ElementState state) {
Expand Down Expand Up @@ -119,14 +135,63 @@ public <T extends IElement> List<T> findElements(By locator, String name, Class<
* @return target element's locator
*/
protected By generateXpathLocator(By multipleElementsLocator, WebElement webElement, int elementIndex) {
Class supportedLocatorType = ByXPath.class;
if (multipleElementsLocator.getClass().equals(supportedLocatorType)) {
if (isLocatorSupportedForXPathExtraction(multipleElementsLocator)) {
return By.xpath(
String.format("(%1$s)[%2$s]", multipleElementsLocator.toString().substring(XPATH_SUBSTRING_BEGIN_INDEX), elementIndex));
String.format("(%1$s)[%2$s]", extractXPathFromLocator(multipleElementsLocator), elementIndex));
}
throw new InvalidArgumentException(String.format(
"Cannot define unique baseLocator for element %1$s. Multiple elements' baseLocator %2$s is not %3$s, and is not supported yet",
webElement.toString(), multipleElementsLocator, supportedLocatorType));
"Cannot define unique baseLocator for element %1$s. Multiple elements' baseLocator type %2$s is not supported yet",
webElement.toString(), multipleElementsLocator.getClass()));
}

/**
* Extracts XPath from passed locator.
* Current implementation works only with ByXPath.class and ByTagName locator types,
* but you can implement your own for the specific WebDriver type.
*
* @param locator locator to get xpath from.
* @return extracted XPath.
*/
protected String extractXPathFromLocator(By locator) {
Class supportedLocatorType = ByXPath.class;
if (locator.getClass().equals(supportedLocatorType)) {
return locator.toString().substring(XPATH_SUBSTRING_BEGIN_INDEX);
}
if (locator.getClass().equals(ByTagName.class)){
return TAGNAME_XPATH_PREFIX + locator.toString().substring(TAGNAME_SUBSTRING_BEGIN_INDEX);
}
throw new InvalidArgumentException(String.format(
"Cannot define xpath from locator %1$s. Locator type %2$s is not %3$s, and is not supported yet",
locator.toString(), locator.getClass(), supportedLocatorType));
}

/**
* Generates absolute child locator for target element.
*
* @param parentLoc parent locator
* @param childLoc child locator relative to parent
* @return absolute locator of the child
*/
protected By generateAbsoluteChildLocator(By parentLoc, By childLoc) {
if (isLocatorSupportedForXPathExtraction(parentLoc) && isLocatorSupportedForXPathExtraction(childLoc)) {
String childLocString = extractXPathFromLocator(childLoc);
String parentLocString = extractXPathFromLocator(parentLoc);
return By.xpath(parentLocString.concat(
childLocString.startsWith(".") ? childLocString.substring(1) : childLocString));
}
return new ByChained(parentLoc, childLoc);
}

/**
* Defines is the locator can be transformed to xpath or not.
* Current implementation works only with ByXPath.class and ByTagName locator types,
* but you can implement your own for the specific WebDriver type.
*
* @param locator locator to transform
* @return true if the locator can be transformed to xpath, false otherwise.
*/
protected boolean isLocatorSupportedForXPathExtraction(By locator) {
return locator.getClass().equals(ByXPath.class) || locator.getClass().equals(ByTagName.class);
}

/**
Expand Down
Loading