Why My React Native E2E Tests Passed Locally but Failed in Expo Cloud
My lessons from Maestro, WebViews, OAuth, and CI-only authentication failures
Why My React Native E2E Tests Passed Locally but Failed in Expo Cloud
My lessons from Maestro, WebViews, OAuth, and CI-only authentication failures

The tests passed locally. Again. Again. Fourteen times.
Then Expo Cloud failed instantly.
At first, it looked like a familiar problem: a flaky WebView synchronization issue. Maestro was waiting for a login field that never appeared, eventually causing the entire smoke suite to fail.
The obvious assumption was timing. Maybe the WebView was loading slowly. Maybe the emulator was under heavy load. Maybe we just needed longer waits. I kept on debugging the UI but the real problem was somewhere much deeper.
My app setup:
A React Native mobile application built with Expo SDK 55 for both Android and iOS.
Some flows , like login are handled through WebViews rather than fully native screens.
For E2E automation, I use:
- Maestro
- GitHub Actions
- Expo EAS Workflows
- dynamically generated real api data
My CI pipeline looked roughly like this:

The Failure :
The failing step looked deceptively simple. Maestro was waiting for a login input:

Expo EAS workflow failing during the Maestro smoke suite while waiting for the login field to appear.
assertVisible:
text: "Login username or membership number"
But in Expo cloud, that field never appeared. The smoke workflow eventually failed with a timeout/assertion error but locally, the exact same flow succeeded repeatedly.
At first, I leaned toward the most common explanation: the WebView was probably slow and tried the usual things:
- longer waits,
- retries,
- synchronization tweaks.
None of them solved the problem consistently.
That was the first clue that we were debugging the symptom instead of the cause so Istarted collecting artifacts aggressively.
Once implemented I started collecting: adb logcat outputs, EAS workflow artifacts, screenshots, Maestro recordings, failure annotations. This turned out to be helpful an I found, instead of a slow-loading login screen, the WebView was actually returning:

401 Unauthorized
Now the error was clear: The WebView itself is unauthenticated.
The Fix
I introduced a deterministic authentication mechanism specifically for E2E flows.
For automation runs, we triggered an explicit authentication prompt that established a fresh authenticated session before entering the protected WebView flow.
This ensured:
- predictable browser authentication state,
- fresh session initialization,
- reproducible behavior in clean cloud environments.
The key shift was architectural:
I stopped assuming authentication state already existed. Instead, the test flow established it explicitly.
That distinction made the E2E behavior significantly more stable.

What I have learned
1. Local success proves less than you think
Local devices often contain invisible state, cached sessions, stored credentials, persisted browser auth.
2. UI failures are often downstream symptoms
The UI assertion was technically correct. But it was only the final symptom of a much deeper infrastructure problem.
3. WebViews add hidden complexity
WebViews are not just “another screen.”
They involve, browser state, authentication boundaries, session persistence, cookies, environment-specific behavior. That complexity is always amplified in CI.
4. Artifacts are mandatory for cloud mobile debugging
Screenshots, adb logcat, workflow artifacts, and recordings stopped being “nice to have.” They became mandatory part of debugging.
Final Thoughts
The deeper I investigated, the clearer it became that what looked like another flaky mobile UI test had invisible layers underneath: Things like browser session state, authentication boundaries, clean cloud environments got clearer.That was the most important lesson from this debugging journey.
Local success does not guarantee production-grade reliability.
Especially in mobile E2E systems where WebViews, OAuth flows, and cloud infrastructure intersect, tests often fail far away from the place where the real bug actually lives.
This shift in thinking changed the way I now approach mobile E2E testing entirely.
메타데이터
- post_id
- 87c761e322a2
- slug
- why-my-react-native-e2e-tests-passed-locally-but-failed-in-expo-cloud-87c761e322a2
- url
- https://medium.com/@_.sirsha/why-my-react-native-e2e-tests-passed-locally-but-failed-in-expo-cloud-87c761e322a2
- canonical_url
- https://medium.com/@_.sirsha/why-my-react-native-e2e-tests-passed-locally-but-failed-in-expo-cloud-87c761e322a2
- author_url
- https://medium.com/@_.sirsha
- status
- ok
- fetched_at
- 2026-06-16 19:09:56