skip to content

Inspection and Flakiness

What you reach for when a mobile run fails: the Inspector, the server and device logs, an on-device agent that never started, and the flake only a real phone or emulator can produce.

on this pageshow

explore

questions

16

In Appium, which flake sources does a mobile run have that a browser run cannot?

level: juniorimportance: must knowfreq 64%

answer

  1. you are fighting the device too
  2. three moving parts, not one
  3. windows your app does not own
  4. the tree is a photograph
  5. different machinery on each platform

basics

~20 s

Mobile adds five failure sources a browser page cannot have: system animation moving the target, the soft keyboard drawn over it, an OS-owned prompt above the app, a slow emulator or simulator, and an element tree that is already stale.

solid answer

~40 s

A browser test fights the page; an Appium test also fights the device and the OS. Five sources have no browser twin. **System animation** moves the target between the find and the tap — Android turns it off with `appium:disableWindowAnimation`, Apple platforms with the XCUITest driver's `reduceMotion` setting. **The soft keyboard** covers the target, and it is a separate window on Android that UiAutomator2's default source omits until `enableMultiWindows` is set, whereas XCUITest reports it inside the app's own element tree. **An OS-owned prompt** is drawn above the app on a schedule the test never authored. **A slow emulator or simulator** stretches every step. And **the element tree is a snapshot** — Android's read from the accessibility node tree, Apple's taken by WebDriverAgent — so it can be history before your command lands.

go deeper

for a junior

Be ready to name the sources out loud: system animation, the soft keyboard, an OS-owned prompt, a slow virtual device, and an element tree that is already stale. Naming them clearly is the whole bar here.

for a middle

Explain why each source exists — the agent only sees the screen through the accessibility layer, and the app is one window among several — and give the Android and the Apple mechanism for at least animation and the keyboard.

for a senior

Show how you decide from evidence which source you are looking at, and why a fix written with Android's disableWindowAnimation capability does nothing on an XCUITest run against an iPhone.

for a principal

Own the position that mobile-only causes are fleet configuration to be removed once, not per-suite workarounds, and that because the two platforms diverge, a single cross-platform switch is a design goal rather than a safe assumption.

## Why mobile has its own flake catalogue A browser end-to-end run has one moving part between the command and the assertion: the page. An Appium run has three — the app, the operating system drawing over it, and the phone, emulator or simulator the whole thing runs on. The extra two produce intermittent failures a browser suite structurally cannot have, and each one has a different lever on Android than it has on Apple platforms. The reason is architectural. Appium reaches the app through a device-side agent: on Android the UiAutomator2 driver pushes and starts a helper server on the device, and on Apple platforms the XCUITest driver builds, installs and launches WebDriverAgent. Everything your test learns about the screen travels through that agent, and everything the agent knows travels through the platform's accessibility layer. Anything that perturbs the screen, that layer, or the device's speed becomes a source of intermittency — and the two platforms perturb differently. ## The five sources - **System animation.** A transition, a ripple or a sheet slide keeps the target moving after it exists. The find succeeds, a rectangle is captured, and the pointer lands where the element used to be. Android exposes the class as device-wide animation scales that `appium:disableWindowAnimation` switches off for the session; Apple's equivalent is the accessibility Reduce Motion preference, reachable as the XCUITest driver's `reduceMotion` setting, with `animationCoolOffTimeout` as its settle-side companion. - **The soft keyboard.** The keyboard is drawn over the bottom of the app, so a control that exists is not reachable. The divergence is what each platform's tree tells you: on Android the input method is a *separate window*, and UiAutomator2's default source carries only the active app's window until the `enableMultiWindows` setting is on, so the obstruction is invisible in the data; XCUITest reports the keyboard inside the app's own element tree, where the `visible` and `hittable` attributes describe the occlusion. - **A prompt the OS owns.** A permission request or a system alert is drawn above your app by the platform, not by your process, and it arrives on the platform's schedule — a first run after install, an OS nag, a low-storage warning. Handling one is its own subject; what belongs here is that it is a flake source precisely because it is not in your app's control flow. - **A slow virtual device.** An emulator or simulator sharing a CI host with other work stretches every step: the app draws later, the agent answers later, and every bound that was comfortable on a workstation becomes marginal. The same suite passes on a laptop and fails in the pipeline. - **A stale element tree.** Neither driver streams the UI. Android's on-device server reads the accessibility node tree at the moment you ask; WebDriverAgent takes an XCUITest snapshot. The handle you hold describes that instant, so a screen that re-lays out between the find and the command — a greenhouse climate dashboard refreshing its sensor rows, a warning banner pushing the list down — makes your command act on a screen that no longer matches. ## What is genuinely different per platform | Source | Android, UiAutomator2 driver | Apple platforms, XCUITest driver | |---|---|---| | Motion | `appium:disableWindowAnimation` drops the device's animation scales for the session | `reduceMotion` setting; `animationCoolOffTimeout` bounds the settle | | Keyboard in the tree | a separate window, absent unless `enableMultiWindows` is set | inside the app's element tree, with `visible` and `hittable` | | Where the tree comes from | the accessibility node tree, read by the on-device server | an XCUITest snapshot taken by WebDriverAgent | | App stops answering | the on-device server is a separate process and keeps replying | `accessibilityDeadline` bounds the wait on the app's accessibility layer | ## How to use the catalogue 1. **Name the source before changing anything.** "Flaky" is not a cause. "The vent-schedule sheet was still animating" and "the keyboard covered the setpoint field" have different fixes and different owners. 2. **Ask which platform failed.** A run that only fails on one platform is usually hitting a mechanism the other does not have; the keyboard window and the tree-construction difference are the two that catch people most often. 3. **Prefer removing a source to absorbing it.** Turning motion off deletes a whole class of races; anything that only makes the race less likely leaves it in the suite. 4. **Re-find rather than reuse.** Because the tree is a snapshot, a handle carried across an app state change is a guess about a screen you have not looked at since. ## The boundary of this catalogue These are *mobile-only causes*. How long to wait, how often to poll, whether to retry a failed case and when to quarantine one are general automation subjects and are not what makes a mobile run different. What makes it different is that the device animates, draws windows the app does not own, runs slowly when it is virtual, and describes itself only in snapshots — and that Android and Apple do each of those with different machinery, which is why a fix written for one platform routinely does nothing on the other.

  • Which of those five sources can you delete outright, and which can only be absorbed?
    Motion can be deleted: Android's `appium:disableWindowAnimation` and the XCUITest driver's `reduceMotion` take the class off the device for the session. A slow virtual device and an OS-owned prompt can only be absorbed or handled when they appear, since neither is under the test's control. Snapshot staleness is structural — you cut exposure by re-finding instead of holding handles across a state change.
  • Why can a browser suite not have the keyboard and OS-prompt failure classes at all?
    A browser test lives inside one window the browser owns, and the page is the whole world it can see. On a device the app is one window among several: the input method is drawn by another process on Android, and permission and system alerts are drawn by the OS above every app. Those windows sit outside the app's control flow, so they interrupt on a schedule the test never authored.

saying these in an interview costs you the question

  • Says mobile flake has the same causes as browser flake
  • Treats the page source as a live view of the screen
  • Assumes the soft keyboard appears in both platforms' element trees
  • Thinks one animation switch covers Android and Apple platforms
  • Blames the app when the OS drew the prompt above it
open as a page

In Appium, how do you take system animation out of a greenhouse climate run on Android and iOS?

level: middleimportance: must knowfreq 52%

basics

~20 s

Turn the motion off at the device. On Android the appium:disableWindowAnimation capability drops the system animation scales for the session; on Apple platforms the XCUITest driver's reduceMotion setting asks the OS to prefer non-motion transitions.

open as a page

Appium Inspector's attach-to-session list is empty though a locksmith call-out session is running — why?

level: middleimportance: must knowfreq 47%

basics

~10 s

The Inspector builds that list from GET /appium/sessions, which Appium gates behind the session_discovery insecure feature. Start the server with allow-insecure set to the scoped name *:session_discovery, or the list stays empty.

open as a page

Why can Appium Inspector show a locksmith call-out element that your test's find call cannot match?

level: middleimportance: must knowfreq 58%

basics

~20 s

The Inspector's tree is a page-source snapshot from your last refresh, not a live view, and it is depth-capped by snapshotMaxDepth. Your test's find runs against its own fresh capture, so the two can honestly disagree.

open as a page

In Appium, which request pulls a device log, and which log types exist on Android versus iOS?

level: middleimportance: must knowfreq 58%

basics

~20 s

Appium pulls device logs with POST /session/:sessionId/se/log, naming a type in the body. The Android drivers offer logcat and bugreport; the XCUITest driver offers syslog, crashlog and safariConsole. GET /session/:sessionId/se/log/types lists what a driver serves.

open as a page

In Appium, what does a failed on-device agent startup look like on Android versus Apple platforms?

level: middleimportance: must knowfreq 68%

basics

~20 s

On Android the driver installs and starts the UiAutomator2 server, then fails with a socket hangup when its port never answers within uiautomator2ServerLaunchTimeout. On Apple platforms xcodebuild builds and launches WebDriverAgent, and wdaLaunchTimeout expires instead.

open as a page

An Appium Android session for a peat-bog monitoring app dies with a socket hangup at startup. How do you triage it?

level: seniorimportance: must knowfreq 61%

basics

~20 s

A socket hangup means nothing answered on the Android agent's port, so triage runs upstream: confirm the device, read the driver log to its last good step, check the device log and the installed server packages, then ask which timeout actually expired.

open as a page

In Appium, what does the Element Inspector connect to, and what does it render for you?

level: juniorimportance: should knowfreq 66%

basics

~10 s

Appium Inspector is a graphical client for a running Appium server. It renders the session's current page source as an element tree beside a screenshot, and shows a selected element's attributes and suggested locators.

open as a page

In Appium, why can a find succeed and the very next command still act on a stale screen?

level: seniorimportance: should knowfreq 46%

basics

~20 s

Because neither driver streams the screen. Android's on-device server reads the accessibility node tree when asked and Apple's WebDriverAgent takes an XCUITest snapshot, so every handle and rectangle describes an instant that has already passed by the time the next command arrives.

open as a page

You attach Appium Inspector to a live locksmith call-out session to chase a flake — what does that attachment change about the session?

level: seniorimportance: should knowfreq 37%

basics

~10 s

Appium Inspector is an ordinary client on the same session, so every refresh sends real screenshot and page-source commands, every Inspector tap is a real tap, and browsing keeps the session's idle timer alive.

open as a page

In Appium, how do you capture a caving trip-log app's crash output on Android and on iOS?

level: seniorimportance: should knowfreq 39%

basics

~20 s

Pull it through the session. On Android the drivers serve logcat and bugreport over POST /session/:sessionId/se/log; on Apple platforms the XCUITest driver serves crashlog and syslog. The Android drivers also stream live through mobile: startLogsBroadcast.

open as a page

Which Appium server flags decide where the server's own log goes and how much it carries?

level: seniorimportance: should knowfreq 46%

basics

~20 s

The Appium server's own log is shaped by server flags: --log-level sets verbosity, --log sends the stream to a file, and --log-timestamp prefixes each line. That one stream carries every session the process handles, Android and Apple alike.

open as a page

In Appium, your Apple-platform sessions keep timing out while xcodebuild builds WebDriverAgent. What do you change?

level: seniorimportance: should knowfreq 47%

basics

~20 s

On Apple platforms xcodebuild builds WebDriverAgent inside session creation, so wdaLaunchTimeout covers a real build. Remove the build instead of raising the clock: reuse the build output, use an agent already installed, or point the driver at one already running.

open as a page

Why can one Appium log configuration not serve an Android and an iOS lane, and what do you standardise?

level: principalimportance: should knowfreq 31%

basics

~20 s

Appium's logging has two halves. Server flags such as --log-level and --log are process-wide and identical for both lanes; device log type names belong to the driver and share nothing across platforms. Standardise the first, discover the second.

open as a page

Across an Android and Apple Appium fleet, how do you upgrade without breaking agent startup?

level: principalimportance: should knowfreq 38%

basics

~20 s

Pin the server, its drivers and the on-device agents together, upgrade one axis at a time on a small device set first, and refresh what each device still carries. On Apple platforms an Xcode or device OS bump is an Appium change too.

open as a page

In Appium, why does a window the app does not own break a run differently on Android and iOS?

level: seniorimportance: nice to knowfreq 38%

basics

~20 s

Each platform loses something different. On Android a foreign window such as the keyboard is absent from UiAutomator2's default tree, so the obstruction is invisible. On Apple platforms it shows, but can make the driver read the wrong app.

open as a page