se.claremont.taf.websupport.elementidentification.WebElementIdentifier Maven / Gradle / Ivy
The newest version!
package se.claremont.taf.websupport.elementidentification;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import se.claremont.taf.core.logging.LogLevel;
import se.claremont.taf.core.logging.LogPost;
import se.claremont.taf.core.testcase.TestCase;
import se.claremont.taf.websupport.DomElement;
import java.util.ArrayList;
import java.util.List;
@SuppressWarnings("WeakerAccess")
public class WebElementIdentifier {
private final DomElement domElement;
private final WebDriver driver;
private final TestCase testCase;
private final boolean performLogging;
public static WebElement getWebElement(TestCase testCase, WebDriver driver, DomElement domElement, boolean performLogging) {
WebElementIdentifier webElementIdentifier = new WebElementIdentifier(testCase, driver, domElement, performLogging);
return webElementIdentifier.getRuntimeElement();
}
public WebElementIdentifier(TestCase testCase, WebDriver driver, DomElement domElement, boolean performLogging) {
this.domElement = domElement;
this.driver = driver;
this.testCase = testCase;
this.performLogging = performLogging;
}
///
/// Identifies the runtime IWebElement object for the given DomElement describing it.
///
/// Returns the IWebElement object corresponding to the DomElement if found, othervice null.
@SuppressWarnings("unused")
public WebElement getWebElement() {
return getRuntimeElement();
}
private WebElement getRuntimeElement() {
String xpath = createXPathFromBy();
if (xpath == null) return getElementByCssSelector();
return getElementByXpath(xpath);
}
private WebElement getElementByXpath(String xpath) {
WebElement returnElement;
try {
List elements = driver.findElements(org.openqa.selenium.By.xpath(xpath));
if (elements.size() == 0) {
log(new LogPost(LogLevel.DEBUG, "Could not identify any matches for '" + domElement.name
+ "' by using xpath:" + System.lineSeparator() + "'" + xpath + "'"
+ System.lineSeparator() + "Built from By statement:"
+ System.lineSeparator() + domElement.by.toString(), null, testCase.testName, testCase.getCurrentTestStepName(), this.getClass().getSimpleName()));
return null;
}
int ordinalNumber = 1;
for (SearchCondition sc : domElement.by.conditions) {
if (sc.getType() == SearchConditionType.OrdinalNumber) {
ordinalNumber = (int) sc.value();
}
}
if (elements.size() < ordinalNumber) {
List elementDescriptions = new ArrayList<>();
for (WebElement webElement : elements) {
elementDescriptions.add(webElement.toString());
}
log(new LogPost(LogLevel.DEBUG, "Element '" + domElement.name + "' was supposed to be the "
+ ordinalNumber + " match for its search criteria. However, only "
+ elements.size() + " metching elements were found when it is identified by " +
"its xPath:" + System.lineSeparator() +
"'" + xpath + "'" + System.lineSeparator() +
", based on its By statement: + " + System.lineSeparator() +
domElement.by.toString() + System.lineSeparator() +
"Elements found:" + System.lineSeparator() +
String.join(System.lineSeparator(), elementDescriptions), null, testCase.testName, testCase.getCurrentTestStepName(), this.getClass().getSimpleName()));
return elements.get(0);
}
if (ordinalNumber < 1) {
log(new LogPost(LogLevel.DEBUG, "Ordinal number to identify element '" + domElement.name + "' is less than one. Must be a positive integer.", null, testCase.testName, testCase.getCurrentTestStepName(), this.getClass().getSimpleName()));
return null;
}
returnElement = elements.get(ordinalNumber - 1);
} catch (Exception poff) {
log(new LogPost(LogLevel.DEBUG, "Something went wrong trying to identify element '" + domElement.name + "'. Error: " + poff.toString(), null, testCase.testName, testCase.getCurrentTestStepName(), this.getClass().getSimpleName()));
return null;
}
if (returnElement != null) log(new LogPost(LogLevel.DEBUG, "Found exactly one IWebElement match for element '" +
domElement.name + "' using xpath:" + System.lineSeparator() +
"'" + xpath + "'" + System.lineSeparator() +
", created from the By statement:" + System.lineSeparator() +
domElement.by.toString(), null, testCase.testName, testCase.getCurrentTestStepName(), this.getClass().getSimpleName()));
return returnElement;
}
private WebElement getElementByCssSelector() {
try {
@SuppressWarnings("ConstantConditions") List potentialMatches = driver.findElements(org.openqa.selenium.By.cssSelector(cssLocatorDescription()));
if (potentialMatches == null || potentialMatches.size() == 0) {
log(new LogPost(LogLevel.DEBUG, "Could not identify any match for element '" + domElement.name + "'. Used CSS identification to try to find it.", null, testCase.testName, testCase.getCurrentTestStepName(), this.getClass().getSimpleName()));
return null;
}
int ordinalNumber = 1;
for (SearchCondition sc : domElement.by.conditions) {
if (sc.getType() == SearchConditionType.OrdinalNumber) {
ordinalNumber = (int) sc.value();
}
}
if (ordinalNumber > potentialMatches.size()) {
log(new LogPost(LogLevel.DEBUG, "Was expected to return element number " + ordinalNumber + " among the elements matching search criteria for '" + domElement.name + "' but only " + potentialMatches.size() + " element(s) were found. Continuing using the first element, even if this could be the wrong one.", null, testCase.testName, testCase.getCurrentTestStepName(), this.getClass().getSimpleName()));
}
if (potentialMatches.size() == 1) {
log(new LogPost(LogLevel.DEBUG, "Found exactly one match for element '" + domElement.name + "' identified by CSS identification.", null, testCase.testName, testCase.getCurrentTestStepName(), this.getClass().getSimpleName()));
return potentialMatches.get(0);
} else {
log(new LogPost(LogLevel.DEBUG, "Found " + potentialMatches.size() + " elements given the search conditions when trying to identify the '" + domElement.name + "' element. Continuing using match number " + ordinalNumber + ", even if this could be the wrong element.", null, testCase.testName, testCase.getCurrentTestStepName(), this.getClass().getSimpleName()));
if (ordinalNumber > 0) {
return potentialMatches.get(ordinalNumber - 1);
}
return potentialMatches.get(0);
}
} catch (Exception e) {
log(new LogPost(LogLevel.DEBUG, "Could not identify element '" + domElement.name + "'. Error: " + e.toString(), null, testCase.testName, testCase.getCurrentTestStepName(), this.getClass().getSimpleName()));
return null;
}
}
public String createXPathFromBy() {
if (cssLocatorDescription() != null) return null;
String xpathString = getXPathIfCriteria();
if (xpathString != null) return addXPathForAcestorIfApplicable() + xpathString;
StringBuilder xpath = new StringBuilder();
xpath.append("//").append(identifyExpectedTagNameFromSearchCriterias());
List parts = new ArrayList<>();
List attributes = getPropertiesFromBy();
if (attributes.size() > 0) parts.addAll(attributes);
List textIdentification = textRecognitionPartsOfElementBy();
if (textIdentification.size() > 0) parts.addAll(textIdentification);
if (parts.size() > 0) xpath.append("[").append(String.join(" and ", parts)).append("]");
return addXPathForAcestorIfApplicable() + xpath.toString();
}
private String addXPathForAcestorIfApplicable() {
String ancestorXPath = "";
for (SearchCondition sc : domElement.by.conditions) {
if (sc.getType() == SearchConditionType.ByAncestor) {
WebElement ancestor = (WebElement) sc.value();
ancestorXPath += getWebElementXPath(ancestor);
}
}
return ancestorXPath;
}
private void log(LogPost logPost) {
if (!performLogging) return;
if (testCase == null) {
System.out.println(logPost.toString());
} else {
testCase.log(logPost.logLevel, logPost.message);
}
}
private String cssLocatorDescription() {
for (SearchCondition sc : domElement.by.conditions) {
if (sc.getType() == SearchConditionType.CssLocator) return sc.value().toString();
}
return null;
}
private List textRecognitionPartsOfElementBy() {
List parts = new ArrayList<>();
List textPattern = new ArrayList<>();
String xpathString;
for (SearchCondition sc : domElement.by.conditions) {
switch (sc.getType()) {
case ExactText:
for (Object text : sc.Values()) {
textPattern.add((String) text);
}
xpathString = "text()='" + String.join("' or text()='", textPattern) + "'";
if (textPattern.size() > 1) xpathString = "(" + xpathString + ")";
parts.add(xpathString);
break;
case TextContains:
for (Object text : sc.Values()) {
textPattern.add((String) text);
}
xpathString = "contains(text(),'" + String.join("') or contains(text(),'", textPattern) + "')";
if (textPattern.size() > 1) xpathString = "(" + xpathString + ")";
parts.add(xpathString);
break;
case TextRegex:
parts.add("matches(text(), '" + sc.value() + "')");
break;
default:
break;
}
}
return parts;
}
private List getPropertiesFromBy() {
List attributes = new ArrayList<>();
for (SearchCondition sc : domElement.by.conditions) {
if (sc.getType() == SearchConditionType.AttributeValue) {
if (((String) sc.Values()[0]).toLowerCase().equals("classcontains")) {
String[] classes = ((String) sc.Values()[1]).split(" ");
for (String klass : classes) {
if (klass.trim().length() == 0) continue;
attributes.add("contains(@class, '" + klass.trim() + "')");
}
} else {
attributes.add("@" + sc.Values()[0] + "='" + sc.Values()[1] + "'");
}
}
}
return attributes;
}
private String getXPathIfCriteria() {
String xpath = null;
for (SearchCondition sc : domElement.by.conditions) {
if (sc.getType() == SearchConditionType.XPath) {
xpath = (String) sc.value();
break;
}
}
if (xpath == null) return null;
for (SearchCondition sc : domElement.by.conditions) {
if (sc.getType() == SearchConditionType.OrdinalNumber) {
xpath = xpath + "[" + sc.value() + "]";
break;
}
}
return xpath;
}
private String identifyExpectedTagNameFromSearchCriterias() {
for (SearchCondition sc : domElement.by.conditions) {
if (sc.getType() == SearchConditionType.ControlType) {
return (String) sc.value();
}
}
return "*";
}
private WebDriver getDriver(WebElement webElement) {
WebDriver driver = null;
try {
driver = ((org.openqa.selenium.WrapsDriver) webElement).getWrappedDriver();
} catch (Exception ignored) {
}
return driver;
}
public String getWebElementXPath(WebElement element) {
if (element == null) return null;
WebDriver driver = getDriver(element);
if (driver == null) return null;
return (String) ((JavascriptExecutor) driver).executeScript("" +
"gPt=function(c){" +
// " if(c.id!==''){" +
// " return'//*[@id=\"'+c.id+'\"]'" +
// " }" +
" if(c===document.body){" +
" return c.tagName" +
" }" +
" var a=0;" +
" var e=c.parentNode.childNodes;" +
" for(var b=0;b
© 2015 - 2025 Weber Informatics LLC | Privacy Policy