05 Query Syntax

Tobias Røikjer edited this page Feb 3, 2016 · 9 revisions

Note: query requires Calabash Android version 0.4.0.pre2 or above.

The Calabash Android ruby API has a method query that selects one or more visible view objects in the current screen in your app. The query method takes a string argument that describes which objects to "query".

This document serves as a reference for the syntax of queries.

Query gives a nice "CSS-selector" like approach to finding view objects in your app screens. Here are some examples from our sample app. To try it out, we recommend starting the console:

krukow:~/tmp/android$ calabash-android console login.apk
irb(main):001:0> reinstall_apps
=> nil
irb(main):002:0> start_test_server_in_background
=> nil
irb(main):001:0> query("button")
[{"id"=>"login_button",
  "enabled"=>true,
  "contentDescription"=>nil,
  "text"=>"Login",
  "qualified_class"=>"android.widget.Button",
  "frame"=>{"y"=>322, "height"=>73, "width"=>84, "x"=>135},
  "description"=>"android.widget.Button@40584908",
  "class"=>"Button"},
 {"id"=>"login_button_slow",
  "enabled"=>true,
  "contentDescription"=>nil,
  "text"=>"Login (slow)",
  "qualified_class"=>"android.widget.Button",
  "frame"=>{"y"=>322, "height"=>73, "width"=>143, "x"=>234},
  "description"=>"android.widget.Button@40585390",
  "class"=>"Button"}]

As you can see, query returns an Array of results. Each result is a Hash representing a view object.

Query syntax

Query expressions are strings. Queries match view objects in the current activity. We've already seen one example: "button" which selects buttons in the current activity.

In general, a query expression is a sequence of sub-expressions separated by space: "e0 e1 e2 ... en". Here, each of the sub-expressions has one of the types: ClassName, Filter, DOM. These types are described below. What is important to remember for now is: a query starts with all root views in the current activity, and will evaluate each sub-expression in turn (left to right).

The second important thing is that a query has a direction. By default this direction is descendant which means from a given set of views, we will look "downwards" in the view hierarchy (this will be explained in more detail below).

ClassName

Selects view objects that have a particular class (or is a sub-class of that class). To specify a ClassName expression, you simply write the fully qualified class name of the class

android.widget.Button

This will pick out all views in the input which have class android.widget.Button or which inherit from android.widget.Button.

There is a simple form of specifying classes. For example, if you just write button this matches all views which have a class with simple name "button" (or "Button" as this is case in-sensitive). Remember that the simple name of a class is the last segment of the fully qualified class name, e.g., for android.widget.Button it is Button.

Direction

There are three directions descendant, child, and parent. These determines the direction in which search proceeds.

Often, query expressions are a sequence of ClassName expressions. For example:

 "linearLayout editText"

this means "first find all linearLayouts, then inside of those, find all the editText views". The key here is the word inside. This is determined by the query direction.

By default the direction is descendant, which intuitively means "search amongst all subviews (or sub-views of sub-views, etc)."

Filtering

Selects a sub-set of views that have certain properties (e.g., certain text or ids). The general form of a filter is:

prop:val

where prop is the name of a "property" to be filtered by, and val is a value of type string, integer or boolean. Strings are delimited by single-quotes, for example: 'Cell 2' is the string "Cell 2". You can also filter by booleans by using true and false.

The property names map to "getter"-methods of the view objects. In general prop:val will try to call:

  • prop()
  • getProp()
  • isProp()

in that order. If no method is found, the view object is not included. If one of the methods is found, it is called, and the result is compared to val. If they are equals values, the view is included.

Some names have special meaning. These are marked, index and id, and their meaning is explained below.

marked: The simplest and most common filter is marked.

"button marked:'Login'"

This filters by id, contentDescription or text. In the example, first all button views are found. Then only those which have id, contentDescription or text equal to 'Login' are selected (i.e., "filtered" out).

index: Filters by index:

"button index:0"

returns the first button found. We recommend only using index in rare cases. The reason is that using index leads to fragile tests that often break if the UI changes slightly.

id: A special construct that supports views by string id.

"button id:'login_button'"

In general, you can filter on any method which returns a simple result like a integer, string or boolean.

"button isEnabled:true"

DOM/WebView Support

Query can look into web views. This is described in a separate document:

WebView Support