E2E Testing for React Native: Setting Up Detox and CI
You launch CI, and tests fail for no apparent reason — an animation wasn't waited for, an element wasn't found. Sound familiar? One of our clients — a FinTech app with 50 screens — suffered from 30% flaky failures on every build. Developers spent hours restarting, and releases were delayed by weeks. After implementing Detox, we reduced the failure rate to 5% and cut run time by three times using parallel execution. Detox is a gray-box framework that embeds a test server directly into the app process. Unlike Appium, Detox automatically synchronizes with the React Native event loop, providing stable tests without sleep(). This is especially important for projects with dynamic animations and frequent network requests. Our experience — 5+ years and over 15 implemented projects — allows us to guarantee test stability even on complex UIs.
Why Detox, Not Appium?
| Criteria | Detox | Appium |
|---|---|---|
| Access Type | Gray-box (embedded server) | Black-box (external) |
| Synchronization | Automatic with JS thread | Requires sleep() and waits |
| Stability on RN | High | Low (frequently fails) |
| Animation Support | Built-in | Through waits |
| Execution Speed | Faster | Slower due to delays |
| CI Flaky Rate | 5-10% | 30-50% |
We use Detox because it's the only framework that understands React Native's internal workings. The result — tests that don't fail randomly in CI.
How We Configure Detox: First Pitfalls
Configuring Detox takes longer than it seems. Especially on iOS. Here's the default configuration we use:
{ "detox": { "testRunner": { "args": { "$0": "jest", "config": "e2e/jest.config.js" }, "jest": { "setupTimeout": 120000 } }, "apps": { "ios.debug": { "type": "ios.app", "binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/MyApp.app", "build": "xcodebuild -workspace ios/MyApp.xcworkspace -scheme MyApp -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build" }, "android.debug": { "type": "android.apk", "binaryPath": "android/app/build/outputs/apk/debug/app-debug.apk", "build": "cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug" } }, "devices": { "simulator": { "type": "ios.simulator", "device": { "type": "iPhone 15", "os": "iOS 17.4" } }, "emulator": { "type": "android.emulator", "device": { "avdName": "Pixel_7_API_34" } } } } } A common issue: the APK must be built with assembleAndroidTest — otherwise synchronization doesn't work. On iOS, only simulator build (-sdk iphonesimulator). Real devices require separate profiling and signing. Also, set setupTimeout — for large projects we use 120 seconds so tests can initialize.
How to Avoid Flaky Tests?
Flaky tests are the main CI pain. Detox reduces them but doesn't eliminate them completely. Here's a table with typical causes and solutions:
| Cause | Solution |
|---|---|
| Infinite animations | Disable in test build via flag detoxDisableHierarchyDump or custom IS_TESTING |
| Network requests not completed | Use waitFor with timeout, or intercept requests via mock |
| Screen state not reset | Call device.reloadReactNative() before each test |
| Insufficient Jest timeouts | Increase jest.setTimeout to 120 seconds |
| Different iOS/Android versions | Test on the same versions as in CI |
We also use a testID convention: screen_component_action. This simplifies maintenance and element lookup.
Parallel Testing: How to Speed Up CI?
Detox supports parallel execution via Jest sharding. Command:
detox test --configuration android.debug --workers 3 Requires 3 emulators or simulators. On macOS, you need 16 GB RAM for 3 simulators. AVDs are created automatically with proper permissions. Parallel execution reduces full run time from 45 minutes to 15 minutes — three times faster.
CI Integration: GitHub Actions Recipe
For iOS, use a macOS runner; for Android, Ubuntu with reactivecircus/android-emulator-runner. Example build and test:
jobs: e2e-ios: runs-on: macos-14 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: '20' } - run: npm ci - run: npx pod-install - run: npx detox build --configuration ios.debug - run: npx detox test --configuration ios.debug --headless For Android, --headless is mandatory; otherwise, the emulator won't find a display. Also, cache simulators and emulators to avoid creating them from scratch.
Typical Detox Commands for Debugging
-
detox test --reuse— reuse an already launched device. -
detox test --record-logs all— record logs of all tests. -
detox build --configuration ios.debug 2>&1 | tee build.log— save build log. -
detox test --debug— run with debug mode.
What's Included
- Full Detox configuration for iOS and Android
- Writing tests for key user flows (authentication, navigation, payments)
- Documentation for setup and test extension
- Integration into your CI/CD (GitHub Actions, GitLab CI, Jenkins)
- Team training (2 hours + access to recording)
- Test stability guarantee: no more than 5% flaky failures
Timeline and Cost
Basic configuration setup and covering main flows takes 5 days. With complex native modules (push notifications, biometrics, camera) — up to 7 days. Cost is calculated individually — contact us, and we'll analyze your app and propose an optimal plan.
We guarantee test stability at all stages. Reach out — we'll help your team forget about flaky tests and accelerate the release cycle. Get a consultation: send a request, and we'll contact you within a day.







