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

Commit 77cdbc5f authored by Dounia Berrada's avatar Dounia Berrada
Browse files

Adding capability to lookup many elements.

Change-Id: I544497f010fdb723ef877e64caa15a0ed06c0fec
parent 11878229
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);