[ compare · mobile testing frameworks ]
e2e vs detox
Detox and e2e both test React Native apps end to end. Detox is built into the app build so it can wait for the app to go idle. e2e tests the build you ship from outside, with exact locators and agent goals, on iOS, Android, and web.
npx e2e@latest init[ at a glance ]
what each tool is.
| dimension | [ e2e ] | [ detox ] |
|---|---|---|
| made by, license | e2e, apache-2.0 | wix, mit |
| apps | React Native, Expo, SwiftUI, Jetpack Compose, Kotlin Multiplatform, Flutter, .NET MAUI; web in the same suite | React Native on iOS and Android; no non-react-native apps on Android |
| app build | Your normal debug or release build, nothing added to the app | A Detox build with the Detox framework inside, plus Gradle and test-runner changes on Android |
| test runner | Built in: fixtures, describe, tags, retries, workers, shards | Jest out of the box, set up by detox init |
| waiting for the app | Black box: actions wait for their target, assertions retry, agent.waitFor waits for a condition in plain language; settle and transition options | Gray box: waits for network requests, timers, animations, and the React Native threads |
| when ai is used | At run time, when a step needs it. Verified goals replay without model calls. | Optional, at run time, through Detox Pilot with an LLM you connect |
| devices | iOS simulators, Android emulators, connected iPhones and Android phones, hosted providers | iOS simulators, Android emulators, attached Android devices, Genymotion cloud; devices not yet supported on iOS |
| expo | Development and release builds, EAS Workflows, EAS Simulators as hosted devices | Community-driven integration |
made by, license
[ e2e ]
e2e, apache-2.0
[ detox ]
wix, mit
apps
[ e2e ]
React Native, Expo, SwiftUI, Jetpack Compose, Kotlin Multiplatform, Flutter, .NET MAUI; web in the same suite
[ detox ]
React Native on iOS and Android; no non-react-native apps on Android
app build
[ e2e ]
Your normal debug or release build, nothing added to the app
[ detox ]
A Detox build with the Detox framework inside, plus Gradle and test-runner changes on Android
test runner
[ e2e ]
Built in: fixtures, describe, tags, retries, workers, shards
[ detox ]
Jest out of the box, set up by
detox initwaiting for the app
[ e2e ]
Black box: actions wait for their target, assertions retry,
agent.waitForwaits for a condition in plain language;settleandtransitionoptions[ detox ]
Gray box: waits for network requests, timers, animations, and the React Native threads
when ai is used
[ e2e ]
At run time, when a step needs it. Verified goals replay without model calls.
[ detox ]
Optional, at run time, through Detox Pilot with an LLM you connect
devices
[ e2e ]
iOS simulators, Android emulators, connected iPhones and Android phones, hosted providers
[ detox ]
iOS simulators, Android emulators, attached Android devices, Genymotion cloud; devices not yet supported on iOS
expo
[ e2e ]
Development and release builds, EAS Workflows, EAS Simulators as hosted devices
[ detox ]
Community-driven integration
[ the same test ]
the same test,written both ways.
describe('login', () => {
beforeAll(async () => { await device.launchApp({ newInstance: true }); });
it('shows the home screen', async () => {
await element(by.id('email')).typeText('ada@example.test');
await element(by.id('password')).typeText('hunter2');
await element(by.text('Sign in')).tap();
await waitFor(element(by.id('home'))).toBeVisible().withTimeout(10000);
await expect(element(by.text('Welcome, Ada'))).toBeVisible();
});
});import { test } from '@e2e-dev/mobile';
import { expect, credentials } from 'e2e';
test('shows the home screen', async ({ agent, app, screen }) => {
await app.open();
const ada = credentials.user('ada');
await agent.act('sign in as {username}', { params: { username: ada.username, password: ada.password } });
await expect(screen.getByTestId('home')).toBeVisible({ timeout: 10_000 });
await expect(screen.getByText('Welcome, Ada')).toBeVisible();
});The sign-in becomes one goal, with the password passed as a credential the model never sees. The two checks stay exact. The testID props you already have work with getByTestId on both platforms.
[ differences ]
the five main differences.
01 / 05
[ side by side ]
feature by feature.
Detox was made for React Native and leads where that is the whole story: synchronization from inside the app, module mocks, and ten years in the React Native docs. e2e leads where the build stays untouched, where one suite covers more platforms, and where the UI changes often.
| dimension | [ e2e ] | [ detox ] | leads |
|---|---|---|---|
| apps | React Native, Expo, SwiftUI, Jetpack Compose, Kotlin Multiplatform, Flutter, .NET MAUI; web in the same suite | React Native on iOS and Android | [ e2e ] |
| app build | Normal debug or release build | Detox build, Detox framework inside, Android native edits | [ e2e ] |
| waiting for the app | Actions wait, assertions retry, settle and transition options | Gray-box idle detection: network, timers, animations, js thread | [ detox ] |
| run artifacts | A video per attempt, screenshots, and a trace.md page per failed test | Screenshots, video, logs, timeline, and Instruments traces | [ detox ] |
| finding elements | getByTestId, getByText, getByLabel, getByRole, filter, nth; device.locator for native selectors | by.id, by.text, by.label, by.type, withAncestor, atIndex | [ even ] |
| when the ui changes | The agent finishes the goal from the changed screen; the runner saves a new recording after a passing check | The test fails; fix it by hand | [ e2e ] |
| plain-language steps | act, assert, waitFor, extract; replay cache; Secret redaction | Pilot, with an LLM you connect, in active development | [ e2e ] |
| module mocks | None; black box | Metro file-extension mocks at bundle time | [ detox ] |
| real devices | Connected iPhones after a signing setup, Android phones; Limrun, EAS Simulators, TestMu AI, BrowserStack | Attached Android devices, Genymotion cloud; not yet on iOS | [ e2e ] |
| expo | Development and release builds, EAS Workflows, EAS Simulators as hosted devices | Community-driven | [ e2e ] |
apps
[ e2e ][ e2e ]
React Native, Expo, SwiftUI, Jetpack Compose, Kotlin Multiplatform, Flutter, .NET MAUI; web in the same suite
[ detox ]
React Native on iOS and Android
app build
[ e2e ][ e2e ]
Normal debug or release build
[ detox ]
Detox build, Detox framework inside, Android native edits
waiting for the app
[ detox ][ e2e ]
Actions wait, assertions retry,
settleandtransitionoptions[ detox ]
Gray-box idle detection: network, timers, animations, js thread
run artifacts
[ detox ][ e2e ]
A video per attempt, screenshots, and a
trace.mdpage per failed test[ detox ]
Screenshots, video, logs, timeline, and Instruments traces
finding elements
[ even ][ e2e ]
getByTestId,getByText,getByLabel,getByRole,filter,nth;device.locatorfor native selectors[ detox ]
by.id,by.text,by.label,by.type,withAncestor,atIndexwhen the ui changes
[ e2e ][ e2e ]
The agent finishes the goal from the changed screen; the runner saves a new recording after a passing check
[ detox ]
The test fails; fix it by hand
plain-language steps
[ e2e ][ e2e ]
act,assert,waitFor,extract; replay cache;Secretredaction[ detox ]
Pilot, with an LLM you connect, in active development
module mocks
[ detox ][ e2e ]
None; black box
[ detox ]
Metro file-extension mocks at bundle time
real devices
[ e2e ][ e2e ]
Connected iPhones after a signing setup, Android phones; Limrun, EAS Simulators, TestMu AI, BrowserStack
[ detox ]
Attached Android devices, Genymotion cloud; not yet on iOS
expo
[ e2e ][ e2e ]
Development and release builds, EAS Workflows, EAS Simulators as hosted devices
[ detox ]
Community-driven
[ which one ]
which one to pick.
pick by the job in front of you: first the jobs where e2e is the better choice, then the jobs where detox is the better choice.
| the job | pick | why |
|---|---|---|
| Testing the build you ship | [ e2e ] | No framework inside the app, no Gradle or test-runner changes. |
| One suite for iOS, Android, and web, or apps in Expo, Flutter, SwiftUI, Jetpack Compose, or .NET MAUI | [ e2e ] | Detox is React Native only. |
| Long flows that change often | [ e2e ] | Goals the agent completes sit beside exact checks, and verified goals replay without model calls. |
| A coding agent that writes and fixes tests | [ e2e ] | It works against the app while it runs on a simulator or device. |
| A React Native app on iOS and Android only, where synchronization matters more than platform reach | [ detox ] | Detox waits from inside the app for network, timers, animations, and the JavaScript thread. |
Module mocks at bundle time or reloadReactNative | [ detox ] | Gray-box access e2e does not have. |
| Performance recordings of a test run on iOS | [ detox ] | Detox's artifacts include timeline and Instruments traces; e2e records a video per attempt and a trace.md page per failed test. |
| Setting the status bar or blocking URLs from inside the app | [ detox ] | Detox's device control reaches inside the app; e2e's device fixture works from outside. |
Testing the build you ship
[ e2e ]No framework inside the app, no Gradle or test-runner changes.
One suite for iOS, Android, and web, or apps in Expo, Flutter, SwiftUI, Jetpack Compose, or .NET MAUI
[ e2e ]Detox is React Native only.
Long flows that change often
[ e2e ]Goals the agent completes sit beside exact checks, and verified goals replay without model calls.
A coding agent that writes and fixes tests
[ e2e ]It works against the app while it runs on a simulator or device.
A React Native app on iOS and Android only, where synchronization matters more than platform reach
[ detox ]Detox waits from inside the app for network, timers, animations, and the JavaScript thread.
Module mocks at bundle time or
[ detox ]reloadReactNativeGray-box access e2e does not have.
Performance recordings of a test run on iOS
[ detox ]Detox's artifacts include timeline and Instruments traces; e2e records a video per attempt and a
trace.mdpage per failed test.Setting the status bar or blocking URLs from inside the app
[ detox ]Detox's device control reaches inside the app; e2e's
devicefixture works from outside.
[ switching ]
run both, move one spec at a time.
[step 1]
Run
npx e2e initand choose the mobile engine, thennpx agent-device doctor. SetbundleIdandappPathfor each platform. Both runners can use the same simulator.[step 2]
Port the apps, devices, and configurations from
.detoxrc.jsinto targets ine2e.config.ts.[step 3]
Rewrite one spec and run it on both platforms with
npx e2e run <file>. Keep the Detox spec until you trust the new one. The agent prompt at the top of the guide does the rewrite, and themigrate-to-e2eskill tracks a migration across sessions.
The migration guide maps every API. Rolling e2e out across a larger team? Book a call and the e2e team sets it up with you.
[ faq ]
questions.
what people on detox ask before they add e2e.
[001]do i need a special build for e2e?
No. e2e tests the normal debug or release build. Nothing is linked into the app, and the Gradle, DetoxTest.java, and network-security changes Detox needs on Android do not apply.
[002]do my testids still work?
Yes. getByTestId reads the accessibility identifier on iOS and the resource id on Android, so testID props carry over as they are.
[003]how does e2e wait without synchronization?
Actions wait for their target, assertions retry until they pass or time out, and agent.waitFor waits for a condition in plain language. The engine's settle and transition options set how long a screen must hold still. For pure React Native, Detox's idle detection is the deeper mechanism.
[004]is e2e's agent like detox pilot?
Both take natural-language steps. Pilot routes them through a prompt handler you write. e2e's agent is built in, takes any AI SDK model or a subscription, replays verified goals without model calls, and never sees Secret values.
[005]does e2e work with expo?
Yes. Development builds open the dev server through launch arguments and app.command, CI runs release builds, and there is an EAS Workflows guide and an EAS Simulators provider.
[006]what's the difference between e2e and detox?
Detox is built into a React Native app build and waits for the app to go idle from inside it. e2e tests the build you ship from outside, through the accessibility layer, with exact locators and agent goals, on iOS, Android, and web.
facts checked 30 october 2026 against wix.github.io/detox (20.51.3) and the e2e docs. something out of date? open an issue on github.
