the Chromium logo

The Chromium Projects

UI selection in Tast tests

Many of our end-to-end (E2E) tests rely on finding and selecting UI to navigate through the system. UIs are prone to change, and those changes can result in test failures unrelated to the functionality being tested. For this reason, when designing tests, there are general practices you should follow to reduce fragility and reliance on UI structure and labels. And, where you must rely on UI, there are methods to make tests easier to debug.

This guide provides a high-level overview of the basic structure of UIAuto Finders as well as the UITree, and how to minimize brittle design patterns when using them.

UITree & Finders

Chrome uses the UIAuto framework to achieve UI automation. UIAuto relies on the accessibility tree -- a representation of the UI that displays on screen -- to navigate through the UI. The accessibility tree includes:

The accessibility tree is made up of 'nodes'. UIAuto refers to these as AutomationNode. They each have a number of attributes. If you've worked with HTML DOMs, this should look somewhat familiar. An example AutomationNode may look like:

node id=917 role=switch state={"focusable":true} parentID=922 childIds=[921] name=Mobile data className=TrayToggleButton

Every node has a parent -- excluding the root node - and can possess child nodes.

The UIAuto library uses "Finders" to find these nodes based on their attributes. For finding nodes, the most relevant attributes are:

Other attributes include:

Tip: Read more about using Finders and how to write Tast tests here.

Decreasing Fragility in Tast Tests

There is no way to add additional metadata to nodes -- like an assignable ID -- to assist in finding them. Since the UITree is an accessibility tool, any additional metadata would cause bloat when it is used for its primary purpose, like in screen readers.

Thus, the only way to find uniquely find a UI element is by its name and className. Unfortunately, these attributes are the most prone to change, and will cause unexpected failures unrelated to the functionality being tested if they do change. There are general tips to help reduce fragility of your tests that rely on UI selection:

Regex Matching

When Regex matching a desired string against the name of a node, use case insensitivity where possible. Often, a name is still uniquely identifiable without capitalization (in regex, (?i)), and this greatly reduces the chance of minor formatting changes breaking your test.

When matching against a label that reads "Connect to [Device Name]", a regex string may look like:

detailsBtn := nodewith.Role("button").NameRegex(regexp.MustCompile("(?i)open settings for .*" + deviceName))

Rather than the case sensitive

... regexp.MustCompile("Connect to" + deviceName) ...

Reference Existing Tast Packages

Many components have their own UIAuto library. It's safe to assume that if the UI itself changes, that these libraries will also be updated. Packages like uiauto/quicksettings provide Finders as well as methods for using the QuickSettings UI.

Opening the QuickSettings UI can be achieved in one method that is guaranteed to continue working, even if the UI changes:

quicksettings.NavigateToNetworkDetailedView(...)

Specifying an Ancestor node in a Finder can help improve test stability by adding another assurance that your Finder is finding the correct node. Typically, this can add additional brittleness to your test, as it's another node that is subject to change. However, because UIAuto packages are guaranteed to be updated with the UI, referencing ancestor nodes from these packages is safe, and can lead to more resistant tests.

For example, specifying a node must be a child of the QuickSettings Network UI can be achieved by:

nodewith.Role("button").NameRegex("My Button").Ancestor(quicksettings.NetworkDetailedViewRevamp)

To help EngProd diagnose test failures, always make sure you're checking for errors when using Finders. When a node cannot be found, make sure to print the error. Golang provides easy syntax to conditionally wrap errors.

if err := ui.LeftClick(mobileNetworkView)(ctx); err != nil {
    s.Fatal("Failed to click on the instant tether device in Quick Settings menu: ", err)
}

Ongoing Work to Decrease Fragility

There are proposals and work to decrease fragility of UI selection in automated tests. In line with go/tast-restriction, mainline tests are currently restricted from using UIAuto without a special exemption, since it is a major source of flakiness and failures unrelated to functionality.

There are ongoing proposals for a UI Map specifically for testing purposes, since additional data in the existing UITree could lead to bloat when using accessibility tools. It is yet to be approved or implemented, however. In future, this could introduce a more robust way of selecting UI without relying on attributes that are prone to change.

Further Reading

Highly recommended reading to get started with writing UIAuto tests include: