Espresso's `ViewActions.click()` appears to be flaky

Open
#2,191 7 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
38/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Stale
Tech stack
android, kotlin
Domain
mobile, testing

Research direction

Start by repeatedly running the provided onView(withText("button test")).perform(click()) reproduction on Espresso 3.5.1 and API 34, comparing it with earlier API levels if available. Inspect the click behavior around the reported missed interaction; done means the reproduction reliably reaches "something new after the button click" or the limitation and cause are clearly documented.

Written by the indexing model from the issue text.

Description

Description

I recently switched a test suite from API 30 to API 34 devices and I'm witnessing occasional fails (roughly 1 in 5 times across ~300 tests) in tests where we click (via onView(withText("blah")).perform(click())) on something and then expect to see the next screen. Inspecting video recordings for these (I'm using Firebase Testlab), I routinely see that the click has never occurred. I've seen this across multiple parts of a large app, so I'm fairly confident this is a problem in the test code rather than some race condition in the application code.

I had wondered if this was click() being executed before setOnClickListener in some circumstances, but as far as I can tell (through some hacky logging and exception throwing) this isn't the case and Espresso is waiting for the Activity/Fragment lifecycle to complete before interacting (as expected).

My suspicion is that there is some flakiness in click() itself and this seems to be more present in API 34 than it was in earlier versions.

I've tried a couple of different solutions to this that all seem to remove the flakes:

  1. Using a "try again" mechanism that makes the click, waits for the result it expects, and then tries the click again if it doesn't get it. This is very common in other UI testing frameworks, but not something I've generally had to resort to in Espresso (due to the IdlingResource system).
  2. Building a custom OnClickListener that can "signal" the tests when the click has actually occurred. Combining this with a "try again" approach allows your code to be certain that the click event has propagated (rather than needing to wait on some change in the view), but is obviously very invasive (we're changing application code to accommodate tests).
  3. Using a custom ViewAction that calls performClick() on the View instead of attempting to inject a tap. This feels like a glaringly simple solution, but it doesn't work with all views. For example, a TextView might be the child of a clickable view rather than clickable itself (like in the case of a view pager title for instance). My guess is that cases like this were the reason (or at least one of the reasons) for building out ViewActions.click() to inject an event in the first place.
Steps to Reproduce

With a view that contains a button that changes screen/alters the view:

onView(withText("button test")).perform(click())
onView(withText("something new after the button click")).matches(isDisplayed())
Expected Results

Espresso will always successfully click on the button.

Actual Results

The click sometimes doesn't happen.

AndroidX Test and Android OS Versions

Espresso 3.5.1 and API 34 running mainly on MediumPhone.arm virtual device on Firebase Test Lab.

Dominant language
Java
Stars
1.2k
Forks
342
Avg merge
1d 14h
Merged PRs (30d)
5

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from android/android-test

All issues in android/android-test

Similar issues

More Java issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.