skip to content

In a Detox 20 project, what does the detox test command actually run, and what does Jest contribute that Detox itself does not?

level: juniorimportance: should knowfreq 30%

answer

  1. Detox is not a test runner
  2. testRunner.args.$0 defaults to jest
  3. spawns the command it prints
  4. detox/runners/jest/testEnvironment
  5. Detox expect replaces Jest's

basics

~20 s

detox test is a wrapper: it resolves the chosen configuration, starts a Detox session and spawns Jest, by default jest --config e2e/jest.config.js. Jest finds and runs the test files; Detox's Jest environment boots the device, installs the app and supplies device, element and expect.

solid answer

~40 s

Detox is not a test runner; it runs on top of Jest, and Detox 20 dropped Mocha. `detox test` builds a command from `testRunner.args` in `.detoxrc.js` — `$0` defaults to `jest`, and the generated config adds `--config e2e/jest.config.js` — resolves the configuration, starts a Detox session, forwards unknown flags and spawns that command, which it also prints so you can run Jest directly with `DETOX_CONFIGURATION` set. Jest brings test discovery, `describe`/`it`, hooks, timeouts, workers and reporting. Detox plugs in through `testEnvironment: 'detox/runners/jest/testEnvironment'`, plus its global setup, teardown and reporter: the environment allocates a device, installs the app and exposes `device`, `element`, `by`, `waitFor` and its own `expect`, which replaces Jest's global.

code

javascript · 12 lines
javascript
/** @type {import('@jest/types').Config.InitialOptions} */
module.exports = {
  rootDir: '..',
  testMatch: ['<rootDir>/e2e/**/*.test.js'],
  testTimeout: 120000,
  maxWorkers: 1,
  globalSetup: 'detox/runners/jest/globalSetup',
  globalTeardown: 'detox/runners/jest/globalTeardown',
  reporters: ['detox/runners/jest/reporter'],
  testEnvironment: 'detox/runners/jest/testEnvironment',
  verbose: true,
};

go deeper

for a junior

Recall that Detox runs on top of Jest, that detox test spawns jest with the e2e config, and that the tests use Detox's device, element and expect.

for a middle

Explain testRunner.args, how Jest can run without the CLI via DETOX_CONFIGURATION, and why the testEnvironment entry is the core of the integration.

for a senior

Debug by running the printed Jest command directly, extend DetoxCircusEnvironment safely, and explain why Jest mocks never reach the app.

for a principal

Judge whether the Jest-only integration fits the team's tooling, and where e2e and unit Jest configs should stay separate projects.

## Detox runs on top of a test runner **Detox** is not a test runner. It supplies the mobile half of an end-to-end test — allocating a simulator or emulator, installing the app, synchronising with it and exposing `device`, `element`, `by`, `expect` and `waitFor` — and relies on a separate runner for the rest. Its official integration is **Jest**. Detox 20 dropped Mocha support and requires Jest 27.2.5 or later (its peer range reaches Jest 30), and `detox init` generates a Jest-based layout. | Concern | Provided by | |---|---| | Finding test files, `describe` / `it`, hooks | Jest | | Test timeouts, workers, reporters' core output | Jest | | Booting a device and installing the app per worker | Detox (through its Jest environment) | | `device`, `element`, `by`, `expect`, `waitFor` globals | Detox | | Waiting for the app to be idle between steps | Detox | ## What `detox test` actually runs `detox test` is a thin wrapper. It resolves the selected configuration, starts a Detox session in its own process and then **spawns the test runner command** built from `testRunner.args` in `.detoxrc.js`: 1. `testRunner.args.$0` is the executable, `jest` by default. 2. Other keys become flags; the generated config sets `config: 'e2e/jest.config.js'`. 3. Unknown flags on the `detox test` command line pass straight through to Jest. 4. Jest's workers join the session Detox started, through the global setup and test environment described below. So `detox test -c ios.sim.debug` ends up spawning roughly `jest --config e2e/jest.config.js`. Detox prints the command, and you can run Jest yourself — handy for attaching an IDE debugger — by putting `DETOX_CONFIGURATION=ios.sim.debug` in front, because Detox reads `DETOX_*` environment variables as fallbacks for its CLI options. If Detox and Jest both define a flag, anything after `--` goes to Jest. ## The Jest config that `detox init` writes `e2e/jest.config.js` wires Jest to Detox through a few mandatory entries: - **`testEnvironment: 'detox/runners/jest/testEnvironment'`** — the core integration. During its setup Detox boots or reuses a device and installs the app; the `testRunner.jest.setupTimeout` key (default 120000 ms) bounds that step. Custom environments should extend `DetoxCircusEnvironment` rather than replace it. - **`globalSetup` / `globalTeardown`** pointing at `detox/runners/jest/globalSetup` and `globalTeardown` — session-wide setup through Detox's internals API; wrap them if you add your own. - **`reporters: ['detox/runners/jest/reporter']`** — keeps Detox's reporter in the chain. - **`testMatch`** for `e2e/**/*.test.js`, **`testTimeout: 120000`** (Jest's 5-second default is far too short for an e2e step) and **`verbose: true`** for real-time logs. How many workers run in parallel, and what those workers do on CI, are separate topics; the template starts at a single worker so a laptop does not boot one device per CPU core. ## Shaping the runner command from `.detoxrc.js` The `testRunner` section controls what `detox test` spawns, independently of the Jest config file: - **`testRunner.args._`** — default positional arguments, such as `['e2e/smoke']`. They are appended when you pass no test paths and replaced when you do. - **Boolean values** — `true` becomes a flag, `false` becomes a `--no-` flag, so `color: false` yields `--no-color`. - **`testRunner.jest.reportSpecs`** — prints each test's start and result as it happens; by default it is on with a single worker and off with several. - **`testRunner.forwardEnv`** — off by default; when on, `detox test` also hands its CLI options to Jest as `DETOX_*` environment variables. ## Consequences for writing tests - **Detox's `expect` replaces Jest's.** With `behavior.init.exposeGlobals` at its default of `true`, the global `expect` is Detox's (`expect(element(by.id('title'))).toBeVisible()`); import Jest's from the `expect` package if you need it. Setting it to `false` means importing `device`, `element`, `by`, `expect` and `waitFor` from `detox`. - **No `jest.mock()`.** The tests run in Node while the app runs on the device, so Jest's module mocks never reach the app; Detox's own mocking guide covers replacing app modules at bundle time. - **Unit-test Jest config is separate.** The app's unit tests use React Native's Jest preset in their own config; the e2e config above is a different Jest setup that never loads that preset. ## A quick mental model Jest is the conductor: it finds files, runs `it` blocks, applies timeouts and prints results. Detox is the section of the orchestra that plays on the phone, joining through the test environment Jest calls into. `detox test` is just the usher that seats everyone with the right configuration.

  • Why can't a Detox e2e test use jest.mock() to stub an app module?
    The test file runs in Node on the host, while the app's JavaScript runs inside the app on the device. `jest.mock()` only affects modules loaded in the Node process, so the app never sees the mock. Detox's mocking guide swaps modules when the app bundle is built instead.
  • How do you use Jest's own expect inside a Detox test?
    By default `behavior.init.exposeGlobals` is `true`, so the global `expect` is Detox's element-assertion API. Import Jest's with `import jestExpect from 'expect'` for plain value assertions, or set `exposeGlobals` to `false` and import Detox's primitives explicitly from `detox`.

Jest is the orchestra's conductor, keeping time and order; Detox is the section that plays on the phone, joining through the stand the conductor calls on, and detox test is the usher who seats everyone.

saying these in an interview costs you the question

  • Detox is a self-contained test runner that replaces Jest.
  • Detox 20 still supports Mocha as an alternative runner.
  • detox test runs the tests in-process instead of spawning Jest.
  • Inside a Detox test, the global expect is Jest's value matcher.
  • jest.mock() in an e2e test stubs modules inside the running app.