skip to content

In Appium's Android Espresso driver, what does an `-android viewmatcher` selector value contain?

level: juniorimportance: must knowfreq 52%

answer

  1. JSON, not an expression language
  2. name, args, class — nothing else
  3. args may hold nested matcher objects
  4. parsed by the on-device Espresso server
  5. same shape as -android datamatcher

basics

~20 s

A JSON object describing a matcher to build on the device: name for the matcher method, args for its arguments, and class for the class holding that static method. The on-device Espresso server builds it and passes it to onView.

solid answer

~40 s

It is not a path or an expression language — it is JSON. The object carries `name`, the matcher method to call; `args`, the arguments to pass it, which may themselves be nested matcher objects so conditions compose; and `class`, the fully-qualified class holding that static method, supplied when it is not the class the on-device server searches by default. The Appium host does not interpret any of it. It ships the string to the Espresso server running inside the Android app under test, which parses the JSON, resolves the method reflectively, builds a matcher object and passes it to Espresso's `onView` to search the rendered view hierarchy. `-android datamatcher` takes the identical shape but routes the built matcher to `onData` instead.

code

json · 5 lines
json
{
  "name": "withText",
  "args": ["Hawthorn"],
  "class": "androidx.test.espresso.matcher.ViewMatchers"
}

go deeper

for a junior

Be ready to say the selector is JSON and to name its three keys. Interviewers are checking that you have actually written one rather than read about the strategy in a list.

for a middle

Explain that the JSON is resolved reflectively by the Espresso server inside the Android app, and that nesting matchers through args is what lets one selector carry a compound condition.

for a senior

Show that you can predict the failure modes — invalid JSON, missing class, wrong arg types, wrong strategy — and that you look for the on-device exception in the driver log rather than in the client.

for a principal

Own where a selector that no compiler checks is allowed to live in the suite, and how page objects hide the JSON so a driver or matcher-library change does not scatter across tests.

## The selector is a description of a call, not a path Most Appium locator strategies take a string in some little language: an XPath expression on Android or Apple platforms, an `NSPredicate` on Apple's XCUITest driver, a chained expression on Android's UiAutomator2 driver. Appium's Android Espresso driver breaks that pattern for `-android viewmatcher`. Its selector value is **JSON**, and what the JSON describes is a method call — the matcher the driver should construct on the device before it searches for anything. That framing explains every rule that follows. You are not writing a query the driver evaluates; you are writing instructions for building an object, and the object does the querying. ## The three keys - **`name`** — the name of the matcher method to invoke. This is the key that is always required. - **`args`** — an array of arguments to pass that method. Values may be plain (a string, a number, a boolean) or they may be further matcher objects of the same `{name, args, class}` shape, which is how conditions compose. - **`class`** — the fully-qualified class that owns the static method named in `name`. Supply it when the method does not live on the class the on-device Espresso server searches by default; omit it when it does. Nothing else belongs in the object. If you find yourself wanting a fourth key, you almost certainly want a nested matcher in `args` instead. ## Where it is parsed, and why that matters The Appium host does not read this JSON. Appium's Espresso driver proxies element finds to the Espresso server it built and installed inside the Android app under test, and that server parses the string, resolves the method reflectively and builds the matcher. Three consequences follow, and they are the ones that bite first: 1. Errors are device-side. A misspelled `name` or a wrong `args` type produces an exception from inside your app's process, surfaced through the driver log — not a client-side validation message. 2. Nothing type-checks the selector. It is a string in your test code, and your compiler, linter and editor all see a string. 3. Resolution depends on what is actually in the built Espresso server. A matcher class not on that server's classpath cannot be named, however correct the JSON is. ## The same JSON, two destinations `-android viewmatcher` and `-android datamatcher` take the identical object. What differs is where the built matcher goes: - `-android viewmatcher` passes it to Espresso's `onView`, which searches the **rendered view hierarchy**. Use it for a hedgerow-survey toolbar button, a filter control, a field label — anything laid out on screen. - `-android datamatcher` passes it to `onData`, which is scoped to an `AdapterView` and searches the **data** behind it. Use it for a species row the app has not inflated yet. Because the shape is shared, the mistake is easy: a matcher describing a view property will be silently offered data objects if you sent it as a datamatcher, and it will match nothing. Choosing the strategy is choosing the destination, not the syntax. ## Nesting, and why it is the point The `args` array accepting matcher objects is what makes this dialect expressive rather than merely different. A compound condition — this kind of view, with this property, inside that container — is one nested object rather than a chain of finds and a filter written in your test code. The predicate is evaluated on the device in one pass, so there is no round trip per condition either. The cost of nesting is readability. A three-level matcher object is not something anyone reads at a glance in a test file, which is why these selectors belong in a named page-object method rather than inline in a test. ## What goes wrong first For a first `-android viewmatcher` selector the failures arrive in a predictable order: - **JSON that is not valid JSON.** The value is a string in your test source, so quoting and escaping are yours to get right. - **A missing `class`.** The method resolves for a colleague and not for you because their app build has a different matcher class available. - **`args` types that do not fit.** A number passed where a string is expected fails at reflection time, with a message about the method rather than about your selector. - **The wrong strategy.** The most common one by far: a perfectly good view matcher sent as `-android datamatcher`, which then searches adapter data and finds none. And one thing that is not a failure. The driver's own node-side code declares a very short strategy array that does not include `-android viewmatcher` at all. That array is a declaration, not the effective list — the on-device Espresso server's strategy enum is, and it accepts both matcher dialects, `-android viewtag` and more besides.

  • When must you include the `class` key in an Appium `-android viewmatcher` selector?
    Whenever the static method named in `name` does not live on the class the on-device Espresso server searches by default. Naming it explicitly is harmless and removes a class of failure that only appears on some app builds, so spelling it out in a shared page object is usually worth the extra characters.
  • What changes if you send the same JSON as `-android datamatcher` instead?
    The built matcher goes to `onData` rather than `onView`, so it is evaluated against an `AdapterView`'s data objects instead of rendered views. A matcher describing a view property will then match nothing, and the failure looks like a missing element rather than a wrong strategy choice.

saying these in an interview costs you the question

  • Expects an XPath-like expression string instead of JSON
  • Thinks the Appium host validates the matcher JSON
  • Believes args may only hold plain values
  • Assumes a bad matcher name fails at build time
  • Reads the driver's short declared array as the full list