All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openqa.selenium.By Maven / Gradle / Ivy

Go to download

Selenium automates browsers. That's it! What you do with that power is entirely up to you.

There is a newer version: 4.26.0
Show newest version
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The SFC 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 org.openqa.selenium;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Pattern;
import org.openqa.selenium.internal.Require;

/**
 * Mechanism used to locate elements within a document. In order to create your own locating
 * mechanisms, it is possible to subclass this class and override the protected methods as required,
 * though it is expected that all subclasses rely on the basic finding mechanisms provided through
 * static methods of this class:
 *
 * 

 * public WebElement findElement(WebDriver driver) {
 *     WebElement element = driver.findElement(By.id(getSelector()));
 *     if (element == null)
 *       element = driver.findElement(By.name(getSelector());
 *     return element;
 * }
 * 
*/ public abstract class By { /** * @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 id(String id) { return new ById(id); } /** * @param linkText The exact text to match against. * @return A By which locates A elements by the exact text it displays. */ public static By linkText(String linkText) { return new ByLinkText(linkText); } /** * @param partialLinkText The partial text to match against * @return a By which locates elements that contain the given link text. */ public static By partialLinkText(String partialLinkText) { return new ByPartialLinkText(partialLinkText); } /** * @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 name(String name) { return new ByName(name); } /** * @param tagName The element's tag name. * @return A By which locates elements by their tag name. */ public static By tagName(String tagName) { return new ByTagName(tagName); } /** * @param xpathExpression The XPath to use. * @return A By which locates elements via XPath. */ public static By xpath(String xpathExpression) { return new ByXPath(xpathExpression); } /** * Find elements based on the value of the "class" attribute. Only one class name should be used. * If an element has multiple classes, please use {@link By#cssSelector(String)}. * * @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 className(String className) { return new ByClassName(className); } /** * Find elements via the driver's underlying W3C Selector engine. If the browser does not * implement the Selector API, the best effort is made to emulate the API. In this case, we strive * for at least CSS2 support, but offer no guarantees. * * @param cssSelector CSS expression. * @return A By which locates elements by CSS. */ public static By cssSelector(String cssSelector) { return new ByCssSelector(cssSelector); } /** * Find a single element. Override this method if necessary. * * @param context A context to use to find the element. * @return The WebElement that matches the selector. */ public WebElement findElement(SearchContext context) { List allElements = findElements(context); if (allElements == null || allElements.isEmpty()) { throw new NoSuchElementException("Cannot locate an element using " + toString()); } return allElements.get(0); } /** * Find many elements. * * @param context A context to use to find the elements. * @return A list of WebElements matching the selector. */ public abstract List findElements(SearchContext context); protected WebDriver getWebDriver(SearchContext context) { if (context instanceof WebDriver) { return (WebDriver) context; } if (!(context instanceof WrapsDriver)) { throw new IllegalArgumentException("Context does not wrap a webdriver: " + context); } return ((WrapsDriver) context).getWrappedDriver(); } protected JavascriptExecutor getJavascriptExecutor(SearchContext context) { WebDriver driver = getWebDriver(context); if (!(context instanceof JavascriptExecutor)) { throw new IllegalArgumentException( "Context does not provide a mechanism to execute JS: " + context); } return (JavascriptExecutor) driver; } @Override public boolean equals(Object o) { if (!(o instanceof By)) { return false; } By that = (By) o; return this.toString().equals(that.toString()); } @Override public int hashCode() { return toString().hashCode(); } @Override public String toString() { // A stub to prevent endless recursion in hashCode() return "[unknown locator]"; } public static class ById extends PreW3CLocator { private final String id; public ById(String id) { super( "id", Require.argument("Id", id).nonNull("Cannot find elements when id is null."), "#%s"); this.id = id; } @Override public String toString() { return "By.id: " + id; } } public static class ByLinkText extends BaseW3CLocator { private final String linkText; public ByLinkText(String linkText) { super( "link text", Require.argument("Link text", linkText) .nonNull("Cannot find elements when the link text is null.")); this.linkText = linkText; } @Override public String toString() { return "By.linkText: " + linkText; } } public static class ByPartialLinkText extends BaseW3CLocator { private final String partialLinkText; public ByPartialLinkText(String partialLinkText) { super( "partial link text", Require.argument("Partial link text", partialLinkText) .nonNull("Cannot find elements when the link text is null.")); this.partialLinkText = partialLinkText; } @Override public String toString() { return "By.partialLinkText: " + partialLinkText; } } public static class ByName extends PreW3CLocator { private final String name; public ByName(String name) { super( "name", Require.argument("Name", name).nonNull("Cannot find elements when name text is null."), String.format("*[name='%s']", name.replace("'", "\\'"))); this.name = name; } @Override public String toString() { return "By.name: " + name; } } public static class ByTagName extends BaseW3CLocator { private final String tagName; public ByTagName(String tagName) { super( "tag name", Require.argument("Tag name", tagName) .nonNull("Cannot find elements when the tag name is null.")); if (tagName.isEmpty()) { throw new InvalidSelectorException("Tag name must not be blank"); } this.tagName = tagName; } @Override public String toString() { return "By.tagName: " + tagName; } } public static class ByXPath extends BaseW3CLocator { private final String xpathExpression; public ByXPath(String xpathExpression) { super( "xpath", Require.argument("XPath", xpathExpression) .nonNull("Cannot find elements when the XPath is null.")); this.xpathExpression = xpathExpression; } @Override public String toString() { return "By.xpath: " + xpathExpression; } } public static class ByClassName extends PreW3CLocator { private final String className; public ByClassName(String className) { super( "class name", Require.argument("Class name", className) .nonNull("Cannot find elements when the class name expression is null."), ".%s"); if (className.matches(".*\\s.*")) { throw new InvalidSelectorException("Compound class names not permitted"); } this.className = className; } @Override public String toString() { return "By.className: " + className; } } public static class ByCssSelector extends BaseW3CLocator { private final String cssSelector; public ByCssSelector(String cssSelector) { super( "css selector", Require.argument("CSS selector", cssSelector) .nonNull("Cannot find elements when the selector is null")); this.cssSelector = cssSelector; } @Override public String toString() { return "By.cssSelector: " + cssSelector; } } public interface Remotable { Parameters getRemoteParameters(); class Parameters { private final String using; private final Object value; public Parameters(String using, Object value) { this.using = Require.nonNull("Search mechanism", using); // There may be subclasses where the value is optional. Allow for this. this.value = value; } public String using() { return using; } public Object value() { return value; } @Override public String toString() { return "[" + using + ": " + value + "]"; } @Override public boolean equals(Object o) { if (!(o instanceof Parameters)) { return false; } Parameters that = (Parameters) o; return using.equals(that.using) && Objects.equals(value, that.value); } @Override public int hashCode() { return Objects.hash(using, value); } private Map toJson() { Map params = new HashMap<>(); params.put("using", using); params.put("value", value); return Collections.unmodifiableMap(params); } } } private abstract static class BaseW3CLocator extends By implements Remotable { private final Parameters params; protected BaseW3CLocator(String using, String value) { this.params = new Parameters(using, value); } @Override public WebElement findElement(SearchContext context) { Require.nonNull("Search Context", context); return context.findElement(this); } @Override public List findElements(SearchContext context) { Require.nonNull("Search Context", context); return context.findElements(this); } @Override public final Parameters getRemoteParameters() { return params; } protected final Map toJson() { return getRemoteParameters().toJson(); } } private abstract static class PreW3CLocator extends By implements Remotable { private static final Pattern CSS_ESCAPE = Pattern.compile("([\\s'\"\\\\#.:;,!?+<>=~*^$|%&@`{}\\-\\/\\[\\]\\(\\)])"); private final Parameters remoteParams; private final ByCssSelector fallback; private PreW3CLocator(String using, String value, String formatString) { this.remoteParams = new Remotable.Parameters(using, value); this.fallback = new ByCssSelector(String.format(formatString, cssEscape(value))); } @Override public WebElement findElement(SearchContext context) { return context.findElement(fallback); } @Override public List findElements(SearchContext context) { return context.findElements(fallback); } @Override public final Parameters getRemoteParameters() { return remoteParams; } protected final Map toJson() { return fallback.toJson(); } private String cssEscape(String using) { using = CSS_ESCAPE.matcher(using).replaceAll("\\\\$1"); if (!using.isEmpty() && Character.isDigit(using.charAt(0))) { using = "\\" + (30 + Integer.parseInt(using.substring(0, 1))) + " " + using.substring(1); } return using; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy