skip to content

[ 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

migration guide: detox to e2e

[ at a glance ]

what each tool is.

  • 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 init

  • waiting for the app

    [ e2e ]

    Black box: actions wait for their target, assertions retry, agent.waitFor waits for a condition in plain language; settle and transition options

    [ 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.

detox
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();
  });
});
e2e
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.

  • gray box and black box

    Detox lives inside the app build, so it knows when the app is idle: network requests, timers, animations, and the JavaScript thread. That is how it removes sleep() from tests. It is also why it needs its own build, a Jest setup, and native changes on Android.

    e2e stays outside the app and drives it through the accessibility layer with agent-device. Actions wait for their target, assertions retry, agent.waitFor waits for a condition in plain language, and settle and transition set how long a screen must hold still. There is nothing to disable, so device.disableSynchronization() has no equivalent.

    For a pure React Native app, Detox's synchronization is the deeper mechanism. e2e gives it up so a test runs against the build you ship, the way a real user uses the app, on more platforms.

  • what runs in ci

    Detox needs detox build for each configuration, the binary path in .detoxrc.js, and Jest.

    e2e takes the release .app and .apk the project already produces. CI installs them with simctl, adb, or device.installApp(), one job per platform. There are guides for GitHub Actions, EAS Workflows, Bitrise, and Codemagic.

  • when ai is used

    Detox Pilot takes natural-language steps, pilot.perform(...) and pilot.autopilot(goal), and turns them into Detox actions through a prompt handler you write for your LLM. Its docs mark it as in active development.

    e2e's agent.act is a built-in step, with a model from any AI SDK provider or a subscription. The first run of a goal uses the model, a later passing assertion saves the taps as a recording, and every run after that replays it with no model call. If the screen changes, the agent takes over for that goal and saves a new recording.

    Secret params keep passwords out of prompts and reports, and a test with only locator steps never calls a model.

  • platforms

    Detox is React Native first, on iOS and Android. The official React Native docs describe it as a framework tailored for React Native apps.

    e2e runs the same test on iOS, Android, Chromium, Firefox, and WebKit, with examples for Expo, SwiftUI, Jetpack Compose, Kotlin Multiplatform, Flutter, and .NET MAUI.

  • device control and mocks

    Detox's gray-box access gives module mocks through Metro file extensions, reloadReactNative, control over the status bar, and a url blacklist.

    e2e's device fixture sets location, appearance, permissions, biometrics, and the clipboard. It turns airplane mode on and off on Android, installs builds, opens deep links, and folds foldable devices, all without a model call. Module mocks and reloadReactNative have no equivalent.

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.

  • 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, settle and transition options

    [ detox ]

    Gray-box idle detection: network, timers, animations, js thread

  • run artifacts

    [ detox ]

    [ e2e ]

    A video per attempt, screenshots, and a trace.md page per failed test

    [ detox ]

    Screenshots, video, logs, timeline, and Instruments traces

  • finding elements

    [ even ]

    [ e2e ]

    getByTestId, getByText, getByLabel, getByRole, filter, nth; device.locator for native selectors

    [ detox ]

    by.id, by.text, by.label, by.type, withAncestor, atIndex

  • when 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; Secret redaction

    [ 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.

  • 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.

[ switching ]

run both, move one spec at a time.

  1. [step 1]

    Run npx e2e init and choose the mobile engine, then npx agent-device doctor. Set bundleId and appPath for each platform. Both runners can use the same simulator.

  2. [step 2]

    Port the apps, devices, and configurations from .detoxrc.js into targets in e2e.config.ts.

  3. [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 the migrate-to-e2e skill 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.

ask anything else

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.

[ get started ]

your verificationlayerstarts withjust one command

npx e2e@latest init