Skip to content
Based in Colombia, serving US and Canadian teams in your time zone
BugsQA

Cross-platform mobile testing: the native iOS and Android bugs React Native's own docs say component tests won't catch

Cross-platform mobile testing for React Native and Flutter: the iOS and Android bugs unit and component tests miss, what Android 16 changed, and a release checklist.

BugsQA team · · 13 min read

  • Mobile QA
  • Test automation
We test onChromeSafariFirefoxEdgeiOSAndroidREST APIs
Smartphone on a desk in front of monitors showing code
Photo by Fotis Fotopoulos on Unsplash

Cross-platform mobile testing has to include the installed app on real iOS and Android devices, because the unit and component tests most React Native and Flutter teams rely on never touch native code. React Native’s documentation says it plainly: component tests run in Node.js, and “if there is a bug in the iOS or Android code, they will not find it.” BugsQA tests that gap for product teams through our cross-platform app testing service.

The usual story goes like this. Jest is green, CI is green, the build goes to the stores, and then Android users report that the back gesture closes the app on the checkout screen.

This guide shows which bugs live in that gap, what Android 16 and the 2026 Google Play deadline changed, and how to split testing between developers and QA.

What do React Native and Flutter unit and component tests actually cover?

React Native and Flutter unit and component tests cover your app logic and how screens render in a test environment, not how the app behaves on an operating system. React Native component tests run in Node.js, and Flutter widget tests run in a test environment without a real device, so neither sees native modules, system dialogs or OS gestures.

Test layer Where it runs What it catches What it misses
Unit tests (Jest, Dart test) Node.js or Dart VM Logic, calculations, state Everything native
Component and widget tests Simulated renderer Rendering, props, user events in JS or Dart Native modules, permissions, gestures, OS UI
End-to-end tests (Detox, Maestro, Appium, integration_test) Device, simulator or emulator Full user journeys on a built app Anything outside the scripted path
Manual and exploratory QA Real devices Platform differences, odd states, usability Slow to repeat at scale

All four layers are useful. The bugs that reach users usually sit in the last two rows, because most teams only automate the first two.

What do React Native’s docs say component tests miss?

React Native’s docs say component tests miss all native platform code. The React Native testing overview states that component tests “do not take into account any iOS, Android, or other platform code which is backing the React Native components” and “cannot give you a 100% confidence that everything works for the user.”

The same page recommends end-to-end tests that build the app “in the release configuration” and run it on a device or simulator from the user’s perspective. It also warns that end-to-end tests are slower to write and more prone to flakiness, which is why many teams skip them.

Our read: treat a passing component suite as proof that your JavaScript works, not that your app works.

Which iOS vs Android bugs only show up on a real device?

The iOS and Android bugs that only show up on a real device come from features the operating system owns: permission prompts, notifications, deep links, the keyboard, safe areas, the back gesture and the release build itself. These are the areas BugsQA checks on both platforms in every cross-platform test plan.

Smartphone screen showing a list of notifications
Photo by Jay Openiano on Unsplash
Area iOS behavior Android behavior What we test
Permission prompts System prompt appears once; after a denial the user must go to Settings Can ask again; notification permission only exists from Android 13 Allow, deny, “don’t ask again”, change in Settings
Push notifications APNs, provisional and focus modes FCM, channels, battery saver Received, tapped from closed app, tapped from background
Deep links Universal Links App Links with domain verification Link opens the right screen when the app is closed, open or not installed
Back navigation Swipe from edge inside the app System back gesture and predictive back Every form and modal, unsaved data
Keyboard and safe areas Notch and Dynamic Island Edge-to-edge, gesture bar, Samsung keyboards Inputs hidden by keyboard, buttons under system bars

Why do permission prompts behave differently on iOS and Android?

Permission prompts behave differently because each operating system owns the prompt, not your app. On iOS the system dialog appears once, and a denied permission can only be changed in Settings. On Android 13 and later, notifications need a runtime permission that older Android versions never asked for, so one feature has two code paths.

The bug pattern we look for is the denied state. Teams test “Allow” and forget that a user who taps “Don’t allow” still needs a working screen, a clear message and a way back to Settings.

Push notifications and deep links break across platforms because they arrive through different native services: APNs and Universal Links on iOS, Firebase Cloud Messaging and verified App Links on Android. A notification or link can open the right screen when the app is running and the wrong one, or nothing, when the app was fully closed.

We test each notification type and each link in three app states (closed, in the background, open) on both platforms. That is six checks per link, which is why deep links are one of the first flows we automate.

Why do the keyboard, safe areas and the Android back button cause bugs?

The keyboard, safe areas and the Android back button cause bugs because the shared code draws the screen, but the operating system decides how much screen is left. A form that fits on an iPhone simulator can hide its submit button behind a Samsung keyboard, and a swipe back on Android can leave a screen your iOS flow never exits.

Here is a sample report from our free bug report template that shows the pattern:

Field Example
Title Android 16: back gesture on the address form exits the app and empties the cart
Environment Samsung Galaxy S25, Android 16, gesture navigation
Steps Open cart, tap Checkout, type part of an address, swipe back from the left edge
Expected App returns to the cart and keeps the items
Actual App closes; when reopened, the cart is empty
Frequency Always on Android 16 (3 of 3). Not on Android 15 or iOS

The useful detail is the last row. Comparing OS versions points the developer straight at the cause.

Which bugs only appear in release builds?

Some bugs only appear in release builds because the release build is a different app from the one developers run all day. Release builds strip debug tools, minify and shrink code (R8 on Android), use production API keys and signing, and switch off the developer menu, so a crash can exist only in the version users download.

That is why we test the store build (TestFlight and Google Play internal testing) before sign-off, never only the debug build on a developer’s machine.

Which parity bugs show up most often in cross-platform apps?

The parity bugs that show up most often in cross-platform apps are a keyboard covering the submit button on Android, a dead button after a permission is denied on iOS, a deep link that opens the home screen from a closed app, and a crash that only exists in the Android release build. In every one of them, the unit and component tests pass.

Bug Platform Why the tests passed The check that catches it
Keyboard covers the input or the submit button on a long form Android (worse with edge-to-edge and Samsung keyboards) The renderer has no real keyboard Fill every form on a real Android phone with the keyboard open
“Enable notifications” button does nothing after the user tapped “Don’t allow” iOS (the system prompt only appears once) The permission call is mocked Deny every permission, then try the feature again
Tapping a link or notification opens the home screen, not the right page Mostly iOS, when the app was fully closed Navigation is tested with the app already running Open each link with the app closed, in the background and open
App crashes on launch or on one screen, but only in the store build Android release build (code removed by R8) Tests run on the debug build Install the Play internal testing build before sign-off

None of these need an exotic device. They need someone to use the installed app the way a customer does, on both platforms.

What did Android 16 and the 2026 Google Play deadline change for cross-platform apps?

Android 16 changed how back navigation, edge-to-edge layouts and large screens work for any app that targets API level 36, and Google Play made that target mandatory: from August 31, 2026, new apps and app updates must target Android 16 (API 36) or higher (Google Play target API requirements). Developers can request an extension to November 1, 2026.

Android 16 change (target API 36) What it means for a React Native or Flutter app
Predictive back is on by default; onBackPressed is no longer called Custom back handling can stop working, so screens may close or lose data
Apps can no longer opt out of edge-to-edge Headers, tab bars and bottom buttons can slide under system bars
Orientation, resizability and aspect-ratio locks are ignored on screens 600dp and wider A portrait-only app now runs full-screen and rotated on tablets and foldables

Source: Android 16 behavior changes.

None of these changes show up in a JavaScript or Dart test. Every one of them shows up the first time someone swipes back, opens the app on a tablet or looks at the bottom of the screen on a gesture-navigation phone.

If you raised your target SDK this year and didn’t run a full regression on Android 16 devices, that is the release to test now. Our cross-platform QA plan starts with exactly that regression.

How do you test Flutter apps across iOS and Android?

You test Flutter apps across iOS and Android by combining Flutter’s three test layers (unit, widget and integration tests) with manual testing of the installed app on both platforms. Flutter’s integration tests run the app on a real Android or iOS device, or on Firebase Test Lab, which makes them the closest automated check to what users see.

Flutter draws its own interface, so it has fewer native UI differences than React Native. The platform still owns permissions, notifications, deep links, the keyboard, the back gesture and the plugins that call native code (camera, payments, maps, biometrics).

For Flutter apps we focus manual testing on those plugin-backed flows and on Android 16 edge-to-edge layouts, because a widget test can’t see a system bar.

Which cross-platform mobile testing tools fit which job?

The right cross-platform mobile testing tool depends on what you need to check: Detox for fast gray-box tests inside React Native, Maestro for simple black-box flows on React Native, Flutter and native apps, and Appium for full WebDriver automation across almost any mobile app.

Silver Android smartphone
Photo by Rami Al-zayat on Unsplash
Tool Type Works with Best for
Detox Gray-box, runs with the app React Native Fast end-to-end tests owned by RN developers
Maestro Black-box, YAML flows React Native, Flutter, native, web Readable smoke tests on the built app
Appium Black-box, WebDriver Native, hybrid, React Native, Flutter Large regression suites in your language of choice
Flutter integration_test Runs with the app Flutter Flutter teams testing full journeys on device

Should you use Detox, Maestro or Appium?

You should use Detox if React Native developers will own the tests, Maestro if you want quick, readable smoke flows across frameworks, and Appium if a QA team will maintain a large regression suite across iOS and Android. Detox needs source access and native build changes; Maestro and Appium test the bundled app as a user would.

We build mobile test automation on top of manual test cases, so the tool follows the flows that already proved worth repeating.

When does manual exploratory testing beat automation?

Manual exploratory testing beats automation on new features, permission and denial states, vendor-specific devices and anything that changes every sprint. Automation only checks the path someone scripted; an experienced tester also tries the swipe back mid-form, the denied permission and the phone in landscape.

How should developers and QA split testing in a shared codebase?

Developers and QA should split testing by layer: developers own unit, component and a few end-to-end tests in CI, and QA owns device coverage, exploratory testing, regression and release sign-off on both platforms. This split keeps developers fast and puts platform differences in front of someone whose job is to look for them.

Laptop on a desk set up for development work
Photo by Matthew Fournier on Unsplash
Task Developers QA
Unit and component tests Own Review gaps
End-to-end tests in CI Own the critical few Extend for regression
Device and OS matrix Agree Own
Exploratory testing per feature Own
Regression on iOS and Android Own
Store build check and sign-off Ship the build Own

What should a cross-platform release checklist cover?

A cross-platform release checklist should cover every native touchpoint on both platforms, on the store build, before you submit. This is the short version of the parity checklist we run:

  1. Install the store build (TestFlight and Play internal testing), not a debug build.
  2. Run core journeys on the current iOS, iOS 18, Android 16 and one older Android version.
  3. Allow and deny every permission, then change it in Settings.
  4. Open every push notification and deep link with the app closed, in the background and open.
  5. Swipe back on every form and modal on Android; check nothing is lost or closed.
  6. Check headers and bottom buttons on a gesture-navigation phone (edge-to-edge).
  7. Rotate on a tablet or foldable, even if the app is portrait-only.
  8. Fill every form with the keyboard open on a small iPhone and a Samsung.
  9. Retest every fixed bug on the platform where it was found and on the other one.

Write each step as a test case so it can be repeated and, later, automated. Our free test case template has the fields.

Frequently asked questions

Is Jest enough to test a React Native app?

Jest is not enough to test a React Native app, because Jest unit and component tests run in Node.js and never execute the iOS or Android code behind your components. React Native’s own documentation says component tests will not find bugs in native code, so you also need end-to-end tests or manual QA on a built app running on real devices or simulators.

What is the difference between cross-platform testing and cross-browser testing?

Cross-platform testing checks a mobile or desktop app on different operating systems such as iOS and Android, while cross-browser testing checks a website in different browsers such as Safari, Chrome and Edge. Both look for the same kind of problem, behavior that differs by environment, but cross-platform testing also covers native features like permissions, notifications and gestures.

Do Flutter apps have fewer platform bugs than React Native apps?

Flutter apps usually have fewer native UI differences than React Native apps, because Flutter draws its own interface instead of using native components. Flutter apps still depend on the operating system for permissions, notifications, deep links, the keyboard, back navigation and native plugins, so they still need testing on both iOS and Android devices.

What does Android 16 change for React Native and Flutter apps?

For apps that target Android 16 (API level 36), predictive back is on by default and onBackPressed is no longer called, apps can no longer opt out of edge-to-edge layouts, and orientation and resizability locks are ignored on screens 600dp and wider. Google Play requires new apps and updates to target API 36 from August 31, 2026, so most cross-platform apps are affected.

Test the native side before your users do

BugsQA tests React Native, Flutter and hybrid apps on real iOS and Android builds, with nearshore QA engineers in Colombia working during North American hours. Send us your store build, your device analytics and your next release date, and we will come back with a cross-platform test plan and a fixed price.

Book a free 30-minute call and bring your latest TestFlight and Play internal testing builds.

  • cross-platform
  • react native
  • flutter
  • android 16

Want us to test your next release?

Book a free consult call and we will tell you what to test first.

More from the blog

Contact us