Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ddb7ab8 authored by John Reck's avatar John Reck Committed by Android (Google) Code Review
Browse files

Merge "Adding capability to lookup many elements."

parents 7460591a 77cdbc5f
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
@@ -16,12 +16,15 @@

package android.webkit.webdriver;

import java.util.List;

/**
 * Mechanism to locate elements within the DOM of the page.
 * @hide
 */
public abstract class By {
    public abstract WebElement findElement(WebElement element);
    public abstract List<WebElement> findElements(WebElement element);

    /**
     * Locates an element by its HTML id attribute.
@@ -37,6 +40,11 @@ public abstract class By {
                return element.findElementById(id);
            }

            @Override
            public List<WebElement> findElements(WebElement element) {
                return element.findElementsById(id); // Yes, it happens a lot.
            }

            @Override
            public String toString() {
                return "By.id: " + id;
@@ -59,6 +67,11 @@ public abstract class By {
                return element.findElementByLinkText(linkText);
            }

            @Override
            public List<WebElement> findElements(WebElement element) {
                return element.findElementsByLinkText(linkText);
            }

            @Override
            public String toString() {
                return "By.linkText: " + linkText;
@@ -83,6 +96,11 @@ public abstract class By {
                return element.findElementByPartialLinkText(linkText);
            }

            @Override
            public List<WebElement> findElements(WebElement element) {
                return element.findElementsByPartialLinkText(linkText);
            }

            @Override
            public String toString() {
                return "By.partialLinkText: " + linkText;
@@ -104,6 +122,11 @@ public abstract class By {
                return element.findElementByName(name);
            }

            @Override
            public List<WebElement> findElements(WebElement element) {
                return element.findElementsByName(name);
            }

            @Override
            public String toString() {
                return "By.name: " + name;
@@ -124,6 +147,11 @@ public abstract class By {
                return element.findElementByClassName(className);
            }

            @Override
            public List<WebElement> findElements(WebElement element) {
                return element.findElementsByClassName(className);
            }

            @Override
            public String toString() {
                return "By.className: " + className;
@@ -145,6 +173,11 @@ public abstract class By {
                return element.findElementByCss(css);
            }

            @Override
            public List<WebElement> findElements(WebElement element) {
                return element.findElementsByCss(css);
            }

            @Override
            public String toString() {
                return "By.css: " + css;
@@ -167,6 +200,11 @@ public abstract class By {
                return element.findElementByTagName(tagName);
            }

            @Override
            public List<WebElement> findElements(WebElement element) {
                return element.findElementsByTagName(tagName);
            }

            @Override
            public String toString() {
                return "By.tagName: " + tagName;
@@ -193,6 +231,11 @@ public abstract class By {
                return element.findElementByXPath(xpath);
            }

            @Override
            public List<WebElement> findElements(WebElement element) {
                return element.findElementsByXPath(xpath);
            }

            @Override
            public String toString() {
                return "By.xpath: " + xpath;
+38 −13
Original line number Diff line number Diff line
@@ -16,19 +16,19 @@

package android.webkit.webdriver;

import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
import android.os.Handler;
import android.os.Message;
import android.webkit.WebView;

import com.android.internal.R;

import com.google.android.collect.Lists;
import com.google.android.collect.Maps;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.os.Handler;
import android.os.Message;
import android.webkit.WebView;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
@@ -190,7 +190,6 @@ public class WebDriver {
        WebchromeClientWrapper chromeWrapper = new WebchromeClientWrapper(
                webview.getWebChromeClient(), this);
        mWebView.setWebChromeClient(chromeWrapper);
        mDocumentElement = new WebElement(this, "");
        mWebView.addJavascriptInterface(new JavascriptResultReady(),
                "webdriver");
    }
@@ -203,6 +202,7 @@ public class WebDriver {
     */
    public void get(String url) {
        executeCommand(CMD_GET_URL, url, LOADING_TIMEOUT);
        mDocumentElement = (WebElement) executeScript("return document.body;");
    }

    /**
@@ -223,9 +223,25 @@ public class WebDriver {
     * no matching element was found.
     */
    public WebElement findElement(By by) {
        checkNotNull(mDocumentElement, "Load a page using WebDriver.get() "
                + "before looking for elements.");
        return by.findElement(mDocumentElement);
    }

    /**
     * Finds all {@link android.webkit.webdriver.WebElement} within the page
     * using the given method.
     *
     * @param by The locating mechanism to use.
     * @return A list of all {@link android.webkit.webdriver.WebElement} found,
     * or an empty list if nothing matches.
     */
    public List<WebElement> findElements(By by) {
        checkNotNull(mDocumentElement, "Load a page using WebDriver.get() "
                + "before looking for elements.");
        return by.findElements(mDocumentElement);
    }

    /**
     * Clears the WebView.
     */
@@ -300,8 +316,10 @@ public class WebDriver {
                toReturn.append(toAdd.substring(0, toAdd.length() -1) + "}");
            } else if (args[i] instanceof WebElement) {
                // WebElement are represented in JavaScript by Objects as
                // follow: {ELEMENT:"id"}
                toReturn.append("{" + ELEMENT_KEY + ":\""
                // follow: {ELEMENT:"id"} where "id" refers to the id
                // of the HTML element in the javascript cache that can
                // be accessed throught bot.inject.cache.getCache_()
                toReturn.append("{\"" + ELEMENT_KEY + "\":\""
                        + ((WebElement) args[i]).getId() + "\"}");
            } else if (args[i] instanceof Number || args[i] instanceof Boolean) {
                toReturn.append(String.valueOf(args[i]));
@@ -312,7 +330,8 @@ public class WebDriver {
                        "Javascript arguments can be "
                        + "a Number, a Boolean, a String, a WebElement, "
                        + "or a List or a Map of those. Got: "
                            + ((args[i] == null) ? "null" : args[i].toString()));
                        + ((args[i] == null) ? "null" : args[i].getClass()
                        + ", value: " + args[i].toString()));
            }
        }
        return toReturn.toString();
@@ -457,7 +476,7 @@ public class WebDriver {
            case STALE_ELEMENT_REFERENCE:
                throw new WebElementStaleException("WebElement is stale.");
            default:
                throw new RuntimeException("Error: " + errorMsg);
                throw new WebDriverException("Error: " + errorMsg);
        }
    }

@@ -523,4 +542,10 @@ public class WebDriver {
        }
        return mJsResult;
    }

    private void checkNotNull(Object obj, String errosMsg) {
        if (obj == null) {
            throw new NullPointerException(errosMsg);
        }
    }
}
+38 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * 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 android.webkit.webdriver;

/**
 * @hide
 */
public class WebDriverException extends RuntimeException {
    public WebDriverException() {
        super();
    }

    public WebDriverException(String reason) {
        super(reason);
    }

    public WebDriverException(String reason, Throwable cause) {
        super(reason, cause);
    }

    public WebDriverException(Throwable cause) {
        super(cause);
    }
}
+141 −22
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package android.webkit.webdriver;

import com.android.internal.R;

import java.util.List;

/**
 * Represents an HTML element. Typically most interactions with a web page
 * will be performed through this class.
@@ -28,6 +30,15 @@ public class WebElement {
    private final String mId;
    private final WebDriver mDriver;

    private static final String LOCATOR_ID = "id";
    private static final String LOCATOR_LINK_TEXT = "linkText";
    private static final String LOCATOR_PARTIAL_LINK_TEXT = "partialLinkText";
    private static final String LOCATOR_NAME = "name";
    private static final String LOCATOR_CLASS_NAME = "className";
    private static final String LOCATOR_CSS = "css";
    private static final String LOCATOR_TAG_NAME = "tagName";
    private static final String LOCATOR_XPATH = "xpath";

    /**
     * Package constructor to prevent clients from creating a new WebElement
     * instance.
@@ -37,11 +48,10 @@ public class WebElement {
     * that can be accessed through JavaScript using "bot.inject.cache".
     *
     * @param driver The WebDriver instance to use.
     * @param id The index of the HTML element in the JavaSctipt cache. Pass
     * an empty String to indicate that this is the
     * @param id The index of the HTML element in the JavaSctipt cache.
     * document.documentElement object.
     */
    /* Package */ WebElement(final WebDriver driver, final String id) {
    /* package */ WebElement(final WebDriver driver, final String id) {
        this.mId = id;
        this.mDriver = driver;
    }
@@ -57,6 +67,18 @@ public class WebElement {
        return by.findElement(this);
    }

     /**
     * Finds all {@link android.webkit.webdriver.WebElement} within the page
     * using the given method.
     *
     * @param by The locating mechanism to use.
     * @return A list of all {@link android.webkit.webdriver.WebElement} found,
     * or an empty list if nothing matches.
     */
    public List<WebElement> findElements(final By by) {
        return by.findElements(this);
    }

    /**
     * Gets the visisble (i.e. not hidden by CSS) innerText of this element,
     * inlcuding sub-elements.
@@ -67,47 +89,143 @@ public class WebElement {
     */
    public String getText() {
        String getText = mDriver.getResourceAsString(R.raw.get_text_android);
        if (mId.equals("")) {
            return null;
        }
        return (String) executeAtom(getText, this);
    }

    /**
     * Gets the value of an HTML attribute for this element or the value of the
     * property with the same name if the attribute is not present. If neither
     * is set, null is returned.
     *
     * @param attribute the HTML attribute.
     * @return the value of that attribute or the value of the property with the
     * same name if the attribute is not set, or null if neither are set. For
     * boolean attribute values this will return the string "true" or "false".
     */
    public String getAttribute(String attribute) {
        String getAttribute = mDriver.getResourceAsString(
                R.raw.get_attribute_value_android);
        return (String) executeAtom(getAttribute, this, attribute);
    }

    /**
     * @return the tag name of this element.
     */
    public String getTagName() {
        return (String) mDriver.executeScript("return arguments[0].tagName;",
                this);
    }

    /**
     * @return true if this element is enabled, false otherwise.
     */
    public boolean isEnabled() {
        String isEnabled = mDriver.getResourceAsString(
                R.raw.is_enabled_android);
        return (Boolean) executeAtom(isEnabled, this);
    }

    /**
     * Determines whether this element is selected or not. This applies to input
     * elements such as checkboxes, options in a select, and radio buttons.
     *
     * @return True if this element is selected, false otherwise.
     */
    public boolean isSelected() {
        String isSelected = mDriver.getResourceAsString(
                R.raw.is_selected_android);
        return (Boolean) executeAtom(isSelected, this);
    }

    /**
     * Selects an element on the page. This works for selecting checkboxes,
     * options in a select, and radio buttons.
     */
    public void setSelected() {
        String setSelected = mDriver.getResourceAsString(
                R.raw.set_selected_android);
        executeAtom(setSelected, this);
    }

    /**
     * This toggles the checkboxe state from selected to not selected, or
     * from not selected to selected.
     *
     * @return True if the toggled element is selected, false otherwise.
     */
    public boolean toggle() {
        String toggle = mDriver.getResourceAsString(R.raw.toggle_android);
        return (Boolean) executeAtom(toggle, this);
    }

    /*package*/ String getId() {
        return mId;
    }

    /* package */ WebElement findElementById(final String locator) {
        return findElement("id", locator);
        return findElement(LOCATOR_ID, locator);
    }

    /* package */ WebElement findElementByLinkText(final String linkText) {
        return findElement("linkText", linkText);
        return findElement(LOCATOR_LINK_TEXT, linkText);
    }

    /* package */ WebElement findElementByPartialLinkText(
            final String linkText) {
        return findElement("partialLinkText", linkText);
        return findElement(LOCATOR_PARTIAL_LINK_TEXT, linkText);
    }

    /* package */ WebElement findElementByName(final String name) {
        return findElement("name", name);
        return findElement(LOCATOR_NAME, name);
    }

    /* package */ WebElement findElementByClassName(final String className) {
        return findElement("className", className);
        return findElement(LOCATOR_CLASS_NAME, className);
    }

    /* package */ WebElement findElementByCss(final String css) {
        return findElement("css", css);
        return findElement(LOCATOR_CSS, css);
    }

    /* package */ WebElement findElementByTagName(final String tagName) {
        return findElement("tagName", tagName);
        return findElement(LOCATOR_TAG_NAME, tagName);
    }

    /* package */ WebElement findElementByXPath(final String xpath) {
        return findElement("xpath", xpath);
        return findElement(LOCATOR_XPATH, xpath);
    }

        /* package */ List<WebElement> findElementsById(final String locator) {
        return findElements(LOCATOR_ID, locator);
    }

    /* package */ List<WebElement> findElementsByLinkText(final String linkText) {
        return findElements(LOCATOR_LINK_TEXT, linkText);
    }

    /* package */ List<WebElement> findElementsByPartialLinkText(
            final String linkText) {
        return findElements(LOCATOR_PARTIAL_LINK_TEXT, linkText);
    }

    /* package */ List<WebElement> findElementsByName(final String name) {
        return findElements(LOCATOR_NAME, name);
    }

    /* package */ List<WebElement> findElementsByClassName(final String className) {
        return findElements(LOCATOR_CLASS_NAME, className);
    }

    /* package */ List<WebElement> findElementsByCss(final String css) {
        return findElements(LOCATOR_CSS, css);
    }

    /* package */ List<WebElement> findElementsByTagName(final String tagName) {
        return findElements(LOCATOR_TAG_NAME, tagName);
    }

    /* package */ List<WebElement> findElementsByXPath(final String xpath) {
        return findElements(LOCATOR_XPATH, xpath);
    }

    private Object executeAtom(final String atom, final Object... args) {
@@ -116,17 +234,18 @@ public class WebElement {
                atom + ")(" + scriptArgs + ")");
    }

    private List<WebElement> findElements(String strategy, String locator) {
        String findElements = mDriver.getResourceAsString(
                R.raw.find_elements_android);
        return (List<WebElement>) executeAtom(findElements,
                strategy, locator, this);
    }

    private WebElement findElement(String strategy, String locator) {
        String findElement = mDriver.getResourceAsString(
                R.raw.find_element_android);
        WebElement el;
        if (mId.equals("")) {
            // Use default as root which is the document object
            el = (WebElement) executeAtom(findElement, strategy, locator);
        } else {
            // Use this as root
            el = (WebElement) executeAtom(findElement, strategy, locator, this);
        }
        WebElement el = (WebElement) executeAtom(findElement,
                strategy, locator, this);
        if (el == null) {
            throw new WebElementNotFoundException("Could not find element "
                    + "with " + strategy + ": " + locator);