skip to content

Your Appium mountain-hut suite posts mobile: swipeGesture to Android and iOS sessions alike — what breaks?

level: seniorimportance: nice to knowfreq 36%

answer

  1. the driver, not the platform, decides
  2. execute methods are declared per driver
  3. XCUITest never registered that name
  4. an Espresso session defeats a platformName branch

basics

~20 s

The iOS session runs the XCUITest driver, which declares no mobile: swipeGesture, so that call fails on every run. Gesture commands are per driver: branch the helper on the driver in play and post mobile: swipe on the Apple side.

solid answer

~40 s

Nothing here is flaky. `mobile: swipeGesture` is declared by Appium's UiAutomator2 driver; the XCUITest driver's execute-method map has no such name, so the `execute/sync` call comes back as a failure and the step dies at the same place every run. Diagnose it from the server log for the iOS session — it prints the script name that was rejected — and confirm which driver that session started with. The fix is a per-driver branch, not a retry: post `mobile: swipeGesture` with `direction` and `percent` on UiAutomator2, and `mobile: swipe` with `direction` and optionally `velocity` on XCUITest. Branch on the **driver**, because Appium's Espresso driver is an Android driver that also wants `mobile: swipe`, so a `platformName` branch reintroduces the same bug on a different session.

go deeper

for a junior

Be able to name the cause without the diagnosis: the Apple session runs a driver that has no command by that name. Knowing gesture names are per driver is enough to avoid writing the bug.

for a middle

Explain the mechanism end to end. The name is absent from that driver's execute-method map, so execute/sync fails deterministically, and the fix is a per-driver branch with translated arguments rather than a retry.

for a senior

Show the triage path and the judgment. Read the rejected script name in the server log, confirm the driver, centralise the mapping, and refuse to make a deterministic failure green by approximating a gesture.

for a principal

Set the standard that a one-platform failure is investigated as a capability question before a timing one, and that gestures with no counterpart fail loudly instead of being silently substituted across the suite.

## What the failure actually is Nothing about this is intermittent. `mobile: swipeGesture` is declared by Appium's UiAutomator2 driver, and it is a real, working command there. The XCUITest driver's execute-method map does not contain that name, so when the shared helper posts it to the iOS session the driver has nothing registered to run: the `execute/sync` call comes back as a failure and the step stops on the spot. Every run, same step, same message. The Android half of the suite passes for the simple reason that it is talking to the driver that owns the command. The first diagnostic move is therefore not to look at the device, the app or the network. It is to read the server log for the iOS session, find the rejected script name, and ask two questions: which driver did this session start with, and what gesture names does that driver declare? ## Why the shared helper looked reasonable Appium's whole value proposition is one client, one protocol, two platforms, and the standard W3C commands really do behave that way. A `findElement`, a `click`, a `GET /session/:sessionId/source` all work the same shape on both. The gesture surface is the place where that promise stops, because gestures are not in the standard protocol at all — they are per-driver execute methods, and no part of the server maps one driver's name onto another's. So the helper is not a careless mistake. It is the natural extrapolation of everything else in the suite being portable, and it is the single most common way a cross-platform Appium suite breaks the first time it grows an iOS target. ## The fix, and the branch key that survives | Intent | Post on a UiAutomator2 session | Post on an XCUITest session | |---|---|---| | Swipe the hut list | `mobile: swipeGesture` with `direction` + `percent` | `mobile: swipe` with `direction`, optional `velocity` | | Long-press a hut row | `mobile: longClickGesture` with `duration` | `mobile: touchAndHold` with `duration` | | Zoom the trail map | `mobile: pinchOpenGesture` with `percent` | `mobile: pinch` with `scale` | The mapping is easy. The branch key is where teams get it wrong: - Branching on `platformName` looks right and is wrong. Appium's Espresso driver is an Android driver that names its swipe `mobile: swipe`, so an Espresso session takes the UiAutomator2 branch and fails identically. - Branch on the driver the session was actually started with, which is what `appium:automationName` selected. - Keep the mapping in exactly one place. A per-page-object copy guarantees that the next gesture added to the suite is added on one side only. - Assert the effect of the gesture, not the fact that the command returned, so a mapping mistake cannot be papered over later. ## Gestures with no twin at all A mapping table is only half the job, because some gestures have no counterpart under any name: 1. `mobile: flingGesture` is UiAutomator2's momentum throw and XCUITest has nothing called a fling. 2. `mobile: forcePress`, `mobile: rotateDigitalCrown` and `mobile: selectPickerWheelValue` are XCUITest's, and no UiAutomator2 gesture corresponds to them. 3. `mobile: pinchOpenGesture` and `mobile: pinchCloseGesture` are two Android commands where XCUITest has one, so the mapping is not even one-to-one where a counterpart does exist. For those, the helper must fail with an explicit "not supported on this driver" rather than substituting the nearest-looking gesture. Approximating a force press with a long press does not reproduce the input the app reacts to, and it turns a red run into a green one that proves nothing. ## What senior judgment looks like here The interviewer is watching for how you respond to a failure that only happens on one platform, because that shape usually triggers the wrong reflexes: - Do not add a retry. A deterministic failure retried three times is the same failure, three times slower, with the cause buried further down the log. - Do not add a wait. The command never ran; there is nothing for a wait to settle. - Do not swap in a similar gesture to get the pipeline green. That is how a suite ends up asserting on a screen the gesture never touched. - Do read what the driver actually posted. The server log naming the rejected script is the shortest path from symptom to cause on this whole surface. The underlying lesson generalises past gestures: whenever an Appium call works on one platform and fails on the other, ask first whether the command is even declared by the driver you sent it to, before you start reasoning about devices and timing.

  • How would you confirm which gesture names the driver in play actually declares?
    Read that driver's own execute-method map, which is where the gesture names are declared, and read the server log, which prints the script name it was asked to run. Do not infer the set from the platform: UiAutomator2 and Espresso are both Android drivers with different gesture vocabularies.
  • Why is adding a retry the wrong response to this failure?
    Because nothing is intermittent. The XCUITest driver has no execute method under that name, so every attempt fails identically. A retry turns a fast, clearly-messaged failure into a slow one and pushes the real cause further down the log, which is a command sent to a driver that never declared it.

saying these in an interview costs you the question

  • Blames a flaky device and wraps the step in a retry.
  • Assumes Appium translates one driver's gesture name into another's.
  • Branches the helper on platformName, which an Espresso session defeats.
  • Substitutes a visually similar gesture where no counterpart exists.
  • Thinks the iOS step silently did nothing rather than failed outright.
  • Adds a wait for a command the driver never executed.