# Codelab: Finding UI elements using chrome.automation API

A common task in autotests is to make hardware changes and verify that UI gets
updated or interact with UI elements and verify that hardware is updated. We can
use the [chrome.automation] API to help with both of these tasks.

[TOC]

## Getting familiar with chrome.automation API

Detailed information about chrome.automation API can be found at
https://developer.chrome.com/extensions/automation.

In short, the API is a wrapper around Chrome's hierarchy of accessibility nodes
that describe Chrome UI elements. The most important attributes of accessibility
nodes are **role** and **name**. See the section on [Accessibility Attributes]
of the accessiblity overview.

## Setup

Follow the steps in [Loading autotest extension on
device](loading-autotest-extension-on-device.md). Loading the AutotestPrivate
extension will give you access to chrome.automation API as well.

## To find a specific UI element

Load a js console connected to the autotest extension's background page. See the
previous section for steps on how to connect to the extension's background page.

**NOTE**: The following steps are meant to be run interactively in the console
and will not work if used in a real test. Section [Using chrome.automation in
autotests](#Using-chrome_automation-in-autotests) shows how to use the API
in a real test.

Let's start by grabbing a reference to the root node of the accessibility tree.

``` js
var root;
chrome.automation.getDesktop(r => root = r);
```

### Finding a button in the hierarchy

Let's demonstrate how to simulate a click on the launcher button in the system
shelf.

We'll start by listing all buttons visible in the tree.

``` js
root.findAll({attributes: {role: "button"}}).map(node => node.name);
```

After typing that into the console you should get a response such as this:

``` js
> (7) ["Back", "Launcher", "Chromium", "Stylus tools", "Status tray, time 4:21
PM, Battery is 22% full.", "Connected to Ethernet", "Battery is 22% full. Time
 left until battery is empty, 1 hour and 39 minutes"]
```

**NOTE**: Names will change depending on the locale of the device. We currently
don't have a locale independent way of identifying UI nodes.

Just by looking at button names we can easily guess that the button named
"Launcher" is the one we're looking for.

Finally, to simulate a click on our button:

``` js
var launcher = root.find({attributes: {role: "button", name: "Launcher"}});
launcher.doDefault();
```

The `doDefault` method performs an action based on the node's *role*, which for
buttons is a button click.

The `find` method supports multiple attributes filters. It returns UI elements
that satisfy all conditions.

## Important roles

The API supports interactions with many types of UI elements.

The following table contains chrome.automation roles for common UI elements:

| views class      | chorme.automation role |
|-----------------:|------------------------|
| views::Button    | button                 |
| views::Label     | staticText             |
| views::ImageView | image                  |
| views::TextField | textField              |

## Finding name and role of a view subclass

View subclasses override the `GetAccessibleNodeData` method to provide role and
name information.

For example, look at [views::Button::GetAccessibleNodeData].

## Using chrome.automation in autotests

chrome.automation extension can be accessed through the autotest extension.

``` python
with Chrome.chrome(autotest_ext=True) as cr:
    ext = cr.autotest_ext
    ext.ExecuteJavaScript("""
        chrome.automation.getDesktop(root => {
            var launcher = root.find({attributes: {role: 'button', name: 'Launcher'}});
            launcher.doDefault();
        });
    """)
```

[chrome.automation]: https://developer.chrome.com/extensions/automation
[Accessibility Attributes]: https://chromium.googlesource.com/chromium/src/+/HEAD/docs/accessibility/overview.md#the-accessibility-tree-and-accessibility-attributes
[views::Button::GetAccessibleNodeData]: https://cs.chromium.org/search/?q=views::Button::GetAccessibleNodeData
[Getting to a command prompt]: https://www.chromium.org/chromium-os/poking-around-your-chrome-os-device#TOC-Getting-to-a-command-prompt
[Run Chromium with flags]: https://www.chromium.org/developers/how-tos/run-chromium-with-flags