Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* Orignal work: Copyright 2015 www.seleniumtests.com
* Modified work: Copyright 2016 www.infotel.com
* Copyright 2017-2019 B.Hecquet
*
* Licensed 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 com.seleniumtests.uipage;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.seleniumtests.driver.CustomEventFiringWebDriver;
import io.appium.java_client.AppiumBy;
import io.appium.java_client.android.AndroidDriver;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang.NotImplementedException;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.NoSuchShadowRootException;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WrapsDriver;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.remote.RemoteWebElement;
import com.seleniumtests.core.SeleniumTestsContextManager;
import com.seleniumtests.customexception.CustomSeleniumTestsException;
import com.seleniumtests.customexception.ScenarioException;
import com.seleniumtests.driver.WebUIDriver;
public class ByC extends By {
public String getEffectiveXPath() {
throw new NotImplementedException("XPath not implemented");
}
private static final String ERROR_CANNOT_FIND_ELEMENT_WITH_SUCH_CRITERIA = "Cannot find element with such criteria ";
/**
* All classes that inherit this class force the use of xpath to search elements.
* Helps to do salesforce tests when pseudo shadow DOM is used
* @author S047432
*
*/
public abstract static class ByForcedXPath extends By implements Serializable {
private static final long serialVersionUID = 4699295846976948351L;
}
public abstract static class ByHasCssSelector extends ByC implements Serializable {
private static final long serialVersionUID = 4699295846976949851L;
protected boolean useCssSelector;
public boolean isUseCssSelector() {
return useCssSelector;
}
public void setUseCssSelector(boolean useCssSelector) {
this.useCssSelector = useCssSelector;
}
public abstract String getEffectiveCssSelector();
}
@Override
public List findElements(SearchContext context) {
return new ArrayList<>();
}
/**
* Search first 'input' element after label referenced by name
* @param label
* @return
*/
public static ByC labelForward(final String label) {
return labelForward(label, null, false, null);
}
/**
* Search first element for tagName after label referenced by name
* @param label
* @param tagName
* @return
*/
public static ByC labelForward(final String label, final String tagName) {
return labelForward(label, tagName, false, null);
}
/**
* Search first element for {@code tagName} after label referenced by partial name
* Use case is {@code
some label
}
* @param label label to search
* @param tagName tag name after this label. The element we really search
* @param labelTagName if label is not in a {@code }
*
*
* You would write
*
{@code
* HtmlElement shadowRoot = new HtmlElement("", ByC.shadow(By.tagName("host1"), By.tagName("host2")));
* HtmlElement myElement = new HtmlElement("", By.id("el"), shadowRoot);
* }
*
* @param bies
* @return
*/
public static ByC shadow(By ... bies) {
return new Shadow(bies);
}
/**
* method for searching an element by a locator or an other.
* It also checks if the locator is relevant to the tested platform (in case of mobile), which allow to write
*
* ByC.or(android(By.tagName("input")), ios(By.xpath(""), web(By.id("myId"))
* @author S047432
*
*/
public static ByC or(By ... bies) {
return new Or(bies);
}
/**
* Says that the locator in parameter is for Web only. It doesn't do anything else and should be used with ByC.or() to have an effect
* @param by
* @return
*/
public static ByC web(By by) {
return new Web(by);
}
/**
* Says that the locator in parameter is for android only. It doesn't do anything else and should be used with ByC.or() to have an effect
* @param by
* @return
*/
public static ByC android(By by) {
return new Android(by);
}
/**
* Says that the locator in parameter is for iOS only. It doesn't do anything else and should be used with ByC.or() to have an effect
* @param by
* @return
*/
public static ByC ios(By by) {
return new Ios(by);
}
/**
* Search an element by id using xpath
* @param id
* The value of the "id" attribute to search for.
* @return A By which locates elements by the value of the "id" attribute.
*/
public static By xId(String id) {
return new ByAttribute("id", id);
}
/**
* Search an element by link text using xpath
* @param linkText
* The exact text to match against.
* @return A By which locates A elements by the exact text it displays.
*/
public static By xLinkText(String linkText) {
return new ByText(linkText, "*", false);
}
/**
* Search an element by partial link text using xpath
* @param partialLinkText
* The partial text to match against
* @return a By which locates elements that contain the given link text.
*/
public static By xPartialLinkText(String partialLinkText) {
return new ByText(partialLinkText, "*", true);
}
/**
* Search an element by name using xpath
* @param name
* The value of the "name" attribute to search for.
* @return A By which locates elements by the value of the "name" attribute.
*/
public static By xName(String name) {
return new ByAttribute("name", name);
}
/**
* Search an element by tag name using xpath
* @param tagName
* The element's tag name.
* @return A By which locates elements by their tag name.
*/
public static By xTagName(String tagName) {
return new ByXTagName(tagName);
}
/**
* Find elements based on the value of the "class" attribute. If an element has
* multiple classes, then this will match against each of them. For example, if
* the value is "one two onone", then the class names "one" and "two" will
* match.
*
* @param className
* The value of the "class" attribute to search for.
* @return A By which locates elements by the value of the "class" attribute.
*/
public static By xClassName(String className) {
return new ByXClassName(className);
}
protected static String buildSelectorForText(String text) {
String escapedText;
if (text.endsWith("*") || text.endsWith("^") || text.endsWith("$")) {
escapedText = escapeQuotes(text.substring(0, text.length() - 1));
} else {
escapedText = escapeQuotes(text);
}
if (text.endsWith("*")) {
return String.format("[contains(text(),%s)]", escapedText);
} else if (text.endsWith("^")) {
return String.format("[starts-with(text(),%s)]", escapedText);
} else if (text.endsWith("$")) {
// return String.format("[ends-with(text(),%s)]", escapedText); //not valid for xpath 1.0
return String.format("[substring(text(), string-length(text()) - string-length(%s) +1) = %s]", escapedText, escapedText);
} else {
return String.format("[text() = %s]", escapedText);
}
}
public static class ByLabelForward extends ByC implements Serializable {
private static final long serialVersionUID = 5341968046120372161L;
private String label;
private String tagName;
private String labelTagName; // tag of the label we are searching. default is label
private boolean partial;
/**
*
* @param label Content of the label to search
* @param tagName Tag name of the element following label, we want to get. Default is "input"
* @param partial do we search for partial of full label name
* @param labelTagName tag name of the label element. Default is "label"
*/
public ByLabelForward(String label, String tagName, boolean partial, String labelTagName) {
if (label == null) {
throw new IllegalArgumentException("Cannot find elements with a null label attribute.");
}
this.label = label;
this.tagName = tagName == null ? "input": tagName;
this.partial = partial;
this.labelTagName = labelTagName == null ? "label": labelTagName;
}
@Override
public String getEffectiveXPath() {
if (partial && !label.endsWith("*")) {
label += "*";
}
return String.format(".//%s%s/following::%s", labelTagName, buildSelectorForText(label), tagName);
}
@Override
public List findElements(SearchContext context) {
return context.findElements(By.xpath(getEffectiveXPath()));
}
@Override
public WebElement findElement(SearchContext context) {
return context.findElement(By.xpath(getEffectiveXPath()));
}
@Override
public String toString() {
return String.format("By.label %s:'%s' forward on element %s", labelTagName, label, tagName);
}
}
public static class ByLabelBackward extends ByC implements Serializable {
private static final long serialVersionUID = 5341968046120372162L;
private String label;
private final String tagName;
private final boolean partial;
private final String labelTagName; // tag of the label we are searching. default is label
/**
*
* @param label Content of the label to search
* @param tagName Tag name of the element following label, we want to get. Default is "input"
* @param partial do we search for partial of full label name
* @param labelTagName tag name of the label element. Default is "label"
*/
public ByLabelBackward(String label, String tagName, boolean partial, String labelTagName) {
if (label == null) {
throw new IllegalArgumentException("Cannot find elements with a null label attribute.");
}
this.label = label;
this.tagName = tagName == null ? "input": tagName;
this.partial = partial;
this.labelTagName = labelTagName == null ? "label": labelTagName;
}
@Override
public String getEffectiveXPath() {
if (partial && !label.endsWith("*")) {
label += "*";
}
return String.format(".//%s%s/preceding::%s", labelTagName, buildSelectorForText(label), tagName);
}
@Override
public List findElements(SearchContext context) {
return context.findElements(By.xpath(getEffectiveXPath()));
}
@Override
public WebElement findElement(SearchContext context) {
List elements;
elements = context.findElements(By.xpath(getEffectiveXPath()));
List elementsReverse = elements.subList(0, elements.size());
Collections.reverse(elementsReverse);
return elementsReverse.get(0);
}
@Override
public String toString() {
return String.format("By.label %s:'%s' backward on element %s", labelTagName, label, tagName);
}
}
public static class ByAttribute extends ByHasCssSelector implements Serializable {
private static final long serialVersionUID = 5341968046120372161L;
private String attributeName;
private String attributeValue;
public ByAttribute(String attributeName, String attributeValue) {
if (attributeName == null) {
throw new IllegalArgumentException("Cannot find elements with a null attribute.");
}
if (attributeValue == null) {
throw new IllegalArgumentException("Cannot find elements with a null attribute value.");
}
this.attributeName = attributeName;
this.attributeValue = attributeValue;
}
@Override
public String getEffectiveXPath() {
return String.format(".//*%s", buildSelector());
}
/**
*Build a xpath selector so that we understand the CSS syntax: https://www.w3schools.com/cssref/css_selectors.asp
* '*' => contains
* '^' => starts with
* '$' => ends with
* @return
*/
private String buildSelector() {
String escapedAttributeValue = escapeQuotes(attributeValue);
if (attributeName.endsWith("*")) {
String tmpAttributeName = attributeName.substring(0, attributeName.length() - 1);
return String.format("[contains(@%s,%s)]", tmpAttributeName, escapedAttributeValue);
} else if (attributeName.endsWith("^")) {
String tmpAttributeName = attributeName.substring(0, attributeName.length() - 1);
return String.format("[starts-with(@%s,%s)]", tmpAttributeName, escapedAttributeValue);
} else if (attributeName.endsWith("$")) {
String tmpAttributeName = attributeName.substring(0, attributeName.length() - 1);
//return String.format("[ends-with(@%s,%s)]", attributeName, escapedAttributeValue); // would by valid with xpath 2.0
return String.format("[substring(@%s, string-length(@%s) - string-length(%s) +1) = %s]", tmpAttributeName, tmpAttributeName, escapedAttributeValue, escapedAttributeValue);
} else {
return String.format("[@%s=%s]", attributeName, escapedAttributeValue);
}
}
private String buildAndroidUiSelector() {
String selector = null;
if (attributeName.equals("text*")) {
selector = String.format("textContains(\"%s\")", attributeValue);
} else if (attributeName.equals("text^")) {
selector = String.format("textStartsWith(\"%s\")", attributeValue);
} else if (attributeName.equals("text$")) {
selector = String.format("textMatches(\"%s\")", attributeValue);
} else if (attributeName.equals("text")) {
selector = String.format("text(\"%s\")", attributeValue);
} else if (attributeName.equals("content-desc*")) {
selector = String.format("descriptionContains(\"%s\")", attributeValue);
} else if (attributeName.equals("content-desc^")) {
selector = String.format("descriptionStartsWith(\"%s\")", attributeValue);
} else if (attributeName.equals("content-desc$")) {
selector = String.format("descriptionMatches(\"%s\")", attributeValue);
} else if (attributeName.equals("content-desc")) {
selector = String.format("description(\"%s\")", attributeValue);
} else if (attributeName.equals("resource-id$")) {
selector = String.format("resourceIdMatches(\"%s\")", attributeValue);
} else if (attributeName.equals("resource-id")) {
selector = String.format("resourceId(\"%s\")", attributeValue);
} else {
return null;
}
return String.format("new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().%s.instance(0))", selector);
}
@Override
public String getEffectiveCssSelector() {
return String.format("[%s=%s]", attributeName, attributeValue);
}
@Override
public List findElements(SearchContext context) {
CustomEventFiringWebDriver currentDriver = (CustomEventFiringWebDriver) WebUIDriver.getWebDriver(false);
String androidSelector = null;
if (!currentDriver.isWebTest()
&& currentDriver.getOriginalDriver() instanceof AndroidDriver) {
androidSelector = buildAndroidUiSelector();
}
if (androidSelector != null) {
return context.findElements(AppiumBy.androidUIAutomator(androidSelector));
} else {
if (useCssSelector) {
return context.findElements(By.cssSelector(getEffectiveCssSelector()));
} else {
return context.findElements(By.xpath(getEffectiveXPath()));
}
}
}
@Override
public WebElement findElement(SearchContext context) {
CustomEventFiringWebDriver currentDriver = (CustomEventFiringWebDriver) WebUIDriver.getWebDriver(false);
String androidSelector = null;
if (!currentDriver.isWebTest()
&& currentDriver.getOriginalDriver() instanceof AndroidDriver) {
androidSelector = buildAndroidUiSelector();
}
if (androidSelector != null) {
return context.findElement(AppiumBy.androidUIAutomator(androidSelector));
} else {
if (useCssSelector) {
return context.findElement(By.cssSelector(getEffectiveCssSelector()));
} else {
return context.findElement(By.xpath(getEffectiveXPath()));
}
}
}
@Override
public String toString() {
return String.format("By.attribute: %s='%s'", attributeName, attributeValue);
}
}
/**
* Find element with the text content given
* @author s047432
*
*/
public static class ByText extends ByC implements Serializable {
private static final long serialVersionUID = 5341968046120372161L;
private String text;
private String tagName;
private boolean partial;
public ByText(String text, String tagName, boolean partial) {
if (text == null) {
throw new IllegalArgumentException("Cannot find elements with a null text content.");
}
if (tagName == null) {
throw new IllegalArgumentException("Cannot find elements with a null tagName.");
}
this.text = text;
this.tagName = tagName;
this.partial = partial;
}
@Override
public String getEffectiveXPath() {
if (partial && !text.endsWith("*")) {
text += "*";
}
return String.format(".//%s%s", tagName, buildSelectorForText(text));
}
@Override
public List findElements(SearchContext context) {
return context.findElements(By.xpath(getEffectiveXPath()));
}
@Override
public WebElement findElement(SearchContext context) {
return context.findElement(By.xpath(getEffectiveXPath()));
}
@Override
public String toString() {
return String.format("%s By.text: '%s'", tagName, text);
}
}
/**
* Allow to search elements with several criteria
* It will create intersection between a search for each criteria
* @author s047432
*
*/
public static class And extends ByC implements Serializable {
/**
*
*/
private static final long serialVersionUID = 6341968046120372161L;
private transient By[] bies;
public And(By ... bies) {
if (bies.length == 0) {
throw new ScenarioException("At least on locator must be provided for And");
}
for (By by : bies) {
if (by == null) {
throw new IllegalArgumentException("Cannot find elements with a null element");
}
}
this.bies = bies;
}
@Override
public List findElements(SearchContext context) {
List elements = bies[0].findElements(context);
for (int i = 1; i < bies.length; i++) {
elements = ListUtils.retainAll(elements, bies[i].findElements(context));
}
return elements;
}
@Override
public WebElement findElement(SearchContext context) {
try {
return findElements(context).get(0);
} catch (IndexOutOfBoundsException e) {
throw new NoSuchElementException(ERROR_CANNOT_FIND_ELEMENT_WITH_SUCH_CRITERIA + toString());
}
}
@Override
public String toString() {
List biesString = new ArrayList<>();
for (By by: bies) {
biesString.add(by.toString());
}
return String.join(" and ", biesString);
}
}
public static class Shadow extends ByC implements Serializable {
private static final long serialVersionUID = 6341668046120372161L;
private transient By[] bies;
public Shadow(By ... bies) {
if (bies.length == 0) {
throw new ScenarioException("At least one locator must be provided for shadow ");
}
this.bies = bies;
}
/**
* If multiple "By" are provided
*/
@Override
public List findElements(SearchContext context) {
List elements = new ArrayList<>();
for (By by: bies) {
List hosts;
if (elements.isEmpty()) { // first iteration
hosts = by.findElements(context);
} else {
hosts = elements.get(0).findElements(by);
elements = new ArrayList<>(); // reset list because we don't care parent elements
}
for (WebElement host: hosts) {
SearchContext root;
try {
root = host.getShadowRoot();
} catch (NoSuchShadowRootException e) {
continue;
// do nothing, it may happen when one of the found elements is not a shadow root (e.g: search by tagName)
}
try {
// https://github.com/SeleniumHQ/selenium/issues/10127 => invalid locator raised when using ShadowRoot directly
// so we build a remoteWebElement which works
Method getIdMethod = root.getClass().getMethod("getId");
getIdMethod.setAccessible(true);
String id = (String) getIdMethod.invoke(root);
RemoteWebElement shadowRootElement = new RemoteWebElement();
shadowRootElement.setParent((RemoteWebDriver) ((WrapsDriver)root).getWrappedDriver());
shadowRootElement.setId(id);
elements.add(shadowRootElement);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new CustomSeleniumTestsException("A change in Selenium occured, ByC.Shadow fails");
}
}
// stop if no element is found
if (elements.isEmpty()) {
return new ArrayList<>();
}
}
return elements;
}
@Override
public WebElement findElement(SearchContext context) {
try {
return findElements(context).get(0);
} catch (IndexOutOfBoundsException e) {
throw new NoSuchElementException(ERROR_CANNOT_FIND_ELEMENT_WITH_SUCH_CRITERIA + toString());
}
}
@Override
public String toString() {
List biesString = new ArrayList<>();
for (By by: bies) {
biesString.add(by.toString());
}
return String.join("/", biesString);
}
public By[] getBies() {
return bies;
}
public void setBies(By[] bies) {
this.bies = bies;
}
}
/**
* Class for searching an element by a locator or an other.
* It also checks if the locator is relevant to the tested platform (in case of mobile), which allow to write
*
* ByC.or(android(By.tagName("input")), ios(By.xpath("")))
* @author S047432
*
*/
public static class Or extends ByC implements Serializable {
private transient By[] bies;
private static final long serialVersionUID = 6341968046167372161L;
public Or(By ... bies) {
if (bies.length == 0) {
throw new ScenarioException("At least on locator must be provided");
}
for (By by : bies) {
if (by == null) {
throw new IllegalArgumentException("Cannot find elements with a null element");
}
}
this.bies = bies;
}
@Override
public List findElements(SearchContext context) {
String platform = SeleniumTestsContextManager.getThreadContext().getPlatform();
boolean webTest = SeleniumTestsContextManager.isWebTest();
List elements = new ArrayList<>();
for (By by: bies) {
// check this 'by' applies to the platform
if ((by instanceof Android && !platform.equalsIgnoreCase("android"))
|| (by instanceof Ios && !platform.equalsIgnoreCase("ios"))
|| ((by instanceof Ios || by instanceof Android) && webTest)
|| (by instanceof Web && !webTest)
) {
continue;
} else if (by instanceof ByPlatformSpecific) {
by = ((ByPlatformSpecific) by).getBy();
}
elements = by.findElements(context);
// stop once at least an element is found
if (!elements.isEmpty()) {
break;
}
}
return elements;
}
@Override
public WebElement findElement(SearchContext context) {
try {
return findElements(context).get(0);
} catch (IndexOutOfBoundsException e) {
throw new NoSuchElementException(ERROR_CANNOT_FIND_ELEMENT_WITH_SUCH_CRITERIA + toString());
}
}
@Override
public String toString() {
List biesString = new ArrayList<>();
for (By by: bies) {
biesString.add(by.toString());
}
return String.join(" or ", biesString);
}
}
/**
*
* Selector for specifying that the underlying selector is specific to web
* This is usefull using ByC.or, when an element is the same in web and mobile but with different selector strategies
*
*/
public static class Web extends ByC implements Serializable, ByPlatformSpecific {
private static final long serialVersionUID = 6341968046120092151L;
private transient By by;
public Web(By by) {
this.by = by;
}
@Override
public List findElements(SearchContext context) {
throw new UnsupportedOperationException("You cannot use ByC.web directly");
}
@Override
public WebElement findElement(SearchContext context) {
throw new UnsupportedOperationException("You cannot use ByC.web directly");
}
@Override
public String toString() {
return String.format("web[%s]", by.toString());
}
@Override
public By getBy() {
return by;
}
}
/**
* Selector for specifying that the underlying selector is specific to android
*/
public static class Android extends ByC implements Serializable, ByPlatformSpecific {
private static final long serialVersionUID = 6341968046120092161L;
private transient By by;
public Android(By by) {
this.by = by;
}
@Override
public List findElements(SearchContext context) {
throw new UnsupportedOperationException("You cannot use ByC.android directly");
}
@Override
public WebElement findElement(SearchContext context) {
throw new UnsupportedOperationException("You cannot use ByC.android directly");
}
@Override
public String toString() {
return String.format("android[%s]", by.toString());
}
@Override
public By getBy() {
return by;
}
}
/**
* Selector for specifying that the underlying selector is specific to Ios
*/
public static class Ios extends ByC implements Serializable, ByPlatformSpecific {
private static final long serialVersionUID = 6341468046120372161L;
private transient By by;
public Ios(By by) {
this.by = by;
}
@Override
public List findElements(SearchContext context) {
throw new UnsupportedOperationException("You cannot use ByC.ios directly");
}
@Override
public WebElement findElement(SearchContext context) {
throw new UnsupportedOperationException("You cannot use ByC.ios directly");
}
@Override
public String toString() {
return String.format("ios[%s]", by.toString());
}
@Override
public By getBy() {
return by;
}
}
public static class ByXTagName extends ByForcedXPath implements Serializable {
private static final long serialVersionUID = 4699295846984948351L;
private final String tagName;
public ByXTagName(String tagName) {
if (tagName == null) {
throw new IllegalArgumentException("Cannot find elements when the tag name is null.");
}
this.tagName = tagName;
}
public String getEffectiveXPath() {
return ".//" + tagName;
}
@Override
public List findElements(SearchContext context) {
return context.findElements(By.xpath(getEffectiveXPath()));
}
@Override
public WebElement findElement(SearchContext context) {
return context.findElement(By.xpath(getEffectiveXPath()));
}
@Override
public String toString() {
return "By.tagName: " + tagName;
}
}
public static class ByXClassName extends ByForcedXPath implements Serializable {
private static final long serialVersionUID = -8737882849130394673L;
private final String className;
public ByXClassName(String className) {
if (className == null) {
throw new IllegalArgumentException(
"Cannot find elements when the class name expression is null.");
}
this.className = className;
}
public String getEffectiveXPath() {
return (".//*[" + containingWord("class", className) + "]");
}
@Override
public List findElements(SearchContext context) {
return context.findElements(By.xpath(getEffectiveXPath()));
}
@Override
public WebElement findElement(SearchContext context) {
return context.findElement(By.xpath(getEffectiveXPath()));
}
/**
* Generate a partial XPath expression that matches an element whose specified attribute
* contains the given CSS word. So to match <div class='foo bar'> you would say "//div[" +
* containingWord("class", "foo") + "]".
*
* @param attribute name
* @param word name
* @return XPath fragment
*/
private String containingWord(String attribute, String word) {
return "contains(concat(' ',normalize-space(@" + attribute + "),' '),' " + word + " ')";
}
@Override
public String toString() {
return "By.className: " + className;
}
}
protected static String escapeQuotes(String aString) {
if (!aString.contains("'")) {
return "'" + aString + "'";
} else {
StringBuilder newString = new StringBuilder("concat(");
for (String part: aString.split("'")) {
newString.append("'" + part + "',\"'\",");
}
return newString.substring(0, newString.length() - 5) + ")";
}
}
/**
* Find element with the for content given
*
*/
public static class ByLabel extends ByForcedXPath implements Serializable {
private static final long serialVersionUID = 5341968046120372161L;
private String label;
/**
* @param label Value of the "for" attribute of the label to search.
*/
public ByLabel(String label) {
if (label == null) {
throw new IllegalArgumentException("Cannot find elements with a null label attribute.");
}
this.label = label;
}
public String getEffectiveXPath() {
return String.format("//input[@id=string(//label[.='%s']/@for)]", label);
}
@Override
public WebElement findElement(SearchContext context) {
return context.findElement(By.xpath(getEffectiveXPath()));
}
@Override
public List findElements(SearchContext context) {
return context.findElements(By.xpath(getEffectiveXPath()));
}
@Override
public String toString() {
return String.format("By.label '%s' on element", label);
}
}
}