io.github.blindio.prospero.core.utils.BySeleneseLocator.java Source code

Java tutorial

Introduction

Here is the source code for io.github.blindio.prospero.core.utils.BySeleneseLocator.java

Source

/*******************************************************************************
 * Copyright 2014 S. Thorson Little
 * 
 * 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 io.github.blindio.prospero.core.utils;

import io.github.blindio.prospero.core.exceptions.ProsperoUnsupportedLocatorException;

import java.util.List;

import org.openqa.selenium.By;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ByIdOrName;

public class BySeleneseLocator extends By {

    /**
     * <h3><a name="locators"></a>Element Locators</h3>
     * <p>
     * Element Locators tell Selenium which HTML element a command refers to.
     * The format of a locator is:
     * </p>
     * <blockquote><em>locatorType</em><strong>=</strong><em>argument</em>
     * </blockquote>
     * <p>
     * We support the following strategies for locating elements:
     * </p>
     * <ul>
     * <li><strong>identifier</strong>=<em>id</em>: Select the element with the
     * specified @id attribute. If no match is found, select the first element
     * whose @name attribute is <em>id</em>. (This is normally the default; see
     * below.)</li>
     * <li><strong>id</strong>=<em>id</em>: Select the element with the
     * specified @id attribute.</li>
     * <li><strong>name</strong>=<em>name</em>: Select the first element with
     * the specified @name attribute.
     * <ul class="first last simple">
     * <li>username</li>
     * <li>name=username</li>
     * </ul>
     * <p>
     * The name may optionally be followed by one or more
     * <em>element-filters</em>, separated from the name by whitespace. If the
     * <em>filterType</em> is not specified, <strong>value</strong> is assumed.
     * </p>
     * <ul class="first last simple">
     * <li>name=flavour value=chocolate</li>
     * </ul>
     * </li>
     * <li><strong>dom</strong>=<em>javascriptExpression</em>: Find an element
     * by evaluating the specified string. This allows you to traverse the HTML
     * Document Object Model using JavaScript. Note that you must not return a
     * value in this string; simply make it the last expression in the block.
     * <ul class="first last simple">
     * <li>dom=document.forms['myForm'].myDropdown</li>
     * <li>dom=document.images[56]</li>
     * <li>dom=function foo() { return document.links[1]; }; foo();</li>
     * </ul>
     * </li>
     * <li><strong>xpath</strong>=<em>xpathExpression</em>: Locate an element
     * using an XPath expression.
     * <ul class="first last simple">
     * <li>xpath=//img[@alt='The image alt text']</li>
     * <li>xpath=//table[@id='table1']//tr[4]/td[2]</li>
     * <li>xpath=//a[contains(@href,'#id1')]</li>
     * <li>xpath=//a[contains(@href,'#id1')]/@class</li>
     * <li>xpath=(//table[@class='stylee'])//th[text()='theHeaderText']/../td</li>
     * <li>xpath=//input[@name='name2' and @value='yes']</li>
     * <li>xpath=//*[text()="right"]</li>
     * </ul>
     * </li>
     * <li><strong>link</strong>=<em>textPattern</em>: Select the link (anchor)
     * element which contains text matching the specified <em>pattern</em>.
     * <ul class="first last simple">
     * <li>link=The link text</li>
     * </ul>
     * </li>
     * <li><strong>css</strong>=<em>cssSelectorSyntax</em>: Select the element
     * using css selectors. Please refer to <a
     * href="http://www.w3.org/TR/REC-CSS2/selector.html">CSS2 selectors</a>, <a
     * href="http://www.w3.org/TR/2001/CR-css3-selectors-20011113/">CSS3
     * selectors</a> for more information. You can also check the
     * TestCssLocators test in the selenium test suite for an example of usage,
     * which is included in the downloaded selenium core package.
     * <ul class="first last simple">
     * <li>css=a[href="#id3"]</li>
     * <li>css=span#firstChild + span</li>
     * </ul>
     * <p>
     * Currently the css selector locator supports all css1, css2 and css3
     * selectors except namespace in css3, some pseudo classes(:nth-of-type,
     * :nth-last-of-type, :first-of-type, :last-of-type, :only-of-type,
     * :visited, :hover, :active, :focus, :indeterminate) and pseudo
     * elements(::first-line, ::first-letter, ::selection, ::before, ::after).
     * </p>
     * </li>
     * <li><strong>ui</strong>=<em>uiSpecifierString</em>: Locate an element by
     * resolving the UI specifier string to another locator, and evaluating it.
     * See the <a href=
     * "http://svn.openqa.org/fisheye/browse/~raw,r=trunk/selenium/trunk/src/main/resources/core/scripts/ui-doc.html"
     * >Selenium UI-Element Reference</a> for more details.
     * <ul class="first last simple">
     * <li>ui=loginPages::loginButton()</li>
     * <li>ui=settingsPages::toggle(label=Hide Email)</li>
     * <li>ui=forumPages::postBody(index=2)//a[2]</li>
     * </ul>
     * </li>
     * </ul>
     * <p>
     * Without an explicit locator prefix, Selenium uses the following default
     * strategies:
     * </p>
     * <ul class="simple">
     * <li><strong>dom</strong>, for locators starting with "document."</li>
     * <li><strong>xpath</strong>, for locators starting with "//"</li>
     * <li><strong>identifier</strong>, otherwise</li>
     * </ul>
     * <h3><a name="element-filters">Element Filters</a></h3><blockquote>
     * <p>
     * Element filters can be used with a locator to refine a list of candidate
     * elements. They are currently used only in the 'name' element-locator.
     * </p>
     * <p>
     * Filters look much like locators, ie.
     * </p>
     * <blockquote><em>filterType</em><strong>=</strong><em>argument</em>
     * </blockquote>
     * <p>
     * Supported element-filters are:
     * </p>
     * <p>
     * <strong>value=</strong><em>valuePattern</em>
     * </p>
     * <blockquote> Matches elements based on their values. This is particularly
     * useful for refining a list of similarly-named
     * toggle-buttons.</blockquote>
     * <p>
     * <strong>index=</strong><em>index</em>
     * </p>
     * <blockquote> Selects a single element based on its position in the list
     * (offset from zero).</blockquote></blockquote><h3><a
     * name="patterns"></a>String-match Patterns</h3>
     * <p>
     * Various Pattern syntaxes are available for matching string values:
     * </p>
     * <ul>
     * <li><strong>glob:</strong><em>pattern</em>: Match a string against a
     * "glob" (aka "wildmat") pattern. "Glob" is a kind of limited
     * regular-expression syntax typically used in command-line shells. In a
     * glob pattern, "*" represents any sequence of characters, and "?"
     * represents any single character. Glob patterns match against the entire
     * string.</li>
     * <li><strong>regexp:</strong><em>regexp</em>: Match a string using a
     * regular-expression. The full power of JavaScript regular-expressions is
     * available.</li>
     * <li><strong>regexpi:</strong><em>regexpi</em>: Match a string using a
     * case-insensitive regular-expression.</li>
     * <li><strong>exact:</strong><em>string</em>: Match a string exactly,
     * verbatim, without any of that fancy wildcard stuff.</li>
     * </ul>
     * <p>
     * If no pattern prefix is specified, Selenium assumes that it's a "glob"
     * pattern.
     * </p>
     * <p>
     * For commands that return multiple values (such as verifySelectOptions),
     * the string being matched is a comma-separated list of the return values,
     * where both commas and backslashes in the values are backslash-escaped.
     * When providing a pattern, the optional matching syntax (i.e. glob,
     * regexp, etc.) is specified once, as usual, at the beginning of the
     * pattern.
     * </p>
     */

    public static final int EQUALS_SYMBOL_CODE_POINT = 61;

    public static final String STRATEGY_IDENTIFIER = "identifier";
    public static final String STRATEGY_ID = "id";
    public static final String STRATEGY_NAME = "name";
    public static final String STRATEGY_DOM = "dom";
    public static final String STRATEGY_XPATH = "xpath";
    public static final String STRATEGY_LINK = "link";
    public static final String STRATEGY_CSS = "css";
    public static final String STRATEGY_UI = "ui";

    public static final String IMPLICIT_STRATEGY_DOM = "document";
    public static final String IMPLICIT_STRATEGY_XPATH = "//";

    private By seleneseLocatedBy;

    public BySeleneseLocator(String seleneseLocator) throws ProsperoUnsupportedLocatorException {
        this.seleneseLocatedBy = seleneseLocator(seleneseLocator);
    }

    @Override
    public WebElement findElement(SearchContext context) {
        return seleneseLocatedBy.findElement(context);
    }

    @Override
    public List<WebElement> findElements(SearchContext context) {
        return seleneseLocatedBy.findElements(context);
    }

    @Override
    public boolean equals(Object o) {
        return seleneseLocatedBy.equals(o);
    }

    public static By seleneseLocator(String seleneseLocator) throws ProsperoUnsupportedLocatorException {
        By parsedBy = null;

        int index = seleneseLocator.indexOf(EQUALS_SYMBOL_CODE_POINT);
        String strategy = null;
        String locator = null;
        if (index != -1) {
            strategy = seleneseLocator.substring(0, index);
            locator = seleneseLocator.substring(index + 1);

            if (!(strategy.equalsIgnoreCase(STRATEGY_IDENTIFIER) || strategy.equalsIgnoreCase(STRATEGY_ID)
                    || strategy.equalsIgnoreCase(STRATEGY_NAME) || strategy.equalsIgnoreCase(STRATEGY_DOM)
                    || strategy.equalsIgnoreCase(STRATEGY_XPATH) || strategy.equalsIgnoreCase(STRATEGY_LINK)
                    || strategy.equalsIgnoreCase(STRATEGY_CSS) || strategy.equalsIgnoreCase(STRATEGY_UI))) {
                strategy = null;
            }
        }

        if (strategy == null) {
            locator = seleneseLocator;
            if (seleneseLocator.substring(0, IMPLICIT_STRATEGY_DOM.length()).toLowerCase()
                    .equals(IMPLICIT_STRATEGY_DOM)) {
                strategy = STRATEGY_DOM;
            } else if (seleneseLocator.substring(0, IMPLICIT_STRATEGY_XPATH.length())
                    .equals(IMPLICIT_STRATEGY_XPATH)) {
                strategy = STRATEGY_XPATH;
            } else {
                strategy = STRATEGY_IDENTIFIER;
            }
        }

        if (strategy.equalsIgnoreCase(STRATEGY_IDENTIFIER)) {
            parsedBy = new ByIdOrName(locator);
        } else if (strategy.equalsIgnoreCase(STRATEGY_ID)) {
            parsedBy = By.id(locator);
        } else if (strategy.equalsIgnoreCase(STRATEGY_NAME)) {
            parsedBy = By.name(locator);
            // TODO: use ByChained to parse element-filters
        } else if (strategy.equalsIgnoreCase(STRATEGY_DOM)) {
            parsedBy = null;
            throw new ProsperoUnsupportedLocatorException("Selenium 1.x Locator Strategy: " + STRATEGY_DOM
                    + " is not supported in Webdriver.  Selenium recommend using the " + STRATEGY_XPATH
                    + " strategy (" + seleneseLocator + ")");
        } else if (strategy.toLowerCase().equals(STRATEGY_XPATH)) {
            if (locator.endsWith("/")) {
                parsedBy = By.xpath(locator.substring(0, locator.length() - 1));
            } else {
                parsedBy = By.xpath(locator);
            }
        } else if (strategy.equalsIgnoreCase(STRATEGY_LINK)) {
            parsedBy = By.partialLinkText(seleneseLocator);
        } else if (strategy.equalsIgnoreCase(STRATEGY_CSS)) {
            parsedBy = By.cssSelector(locator);
        } else if (strategy.equalsIgnoreCase(STRATEGY_UI)) {
            parsedBy = null;
            throw new ProsperoUnsupportedLocatorException("Selenium 1.x Locator Strategy: " + STRATEGY_UI
                    + " is not supported in Webdriver (" + seleneseLocator + ")");
        } else {
            // TODO
        }

        return parsedBy;
    }
}