#4945·Detox

Expose a public app idle/busy status that works with synchronization disabled

Author: HerrNiklasRaabCreated May 8, 2026Updated May 8, 2026

Describe your idea

Problem

Detox already tracks app idle/busy state internally and exposes it through the undocumented device.deviceDriver.client.currentStatus() (iOS returns a structured { app_status: "idle" | "busy", ... } payload). This is useful for building idle-aware polling on top of waitFor(...).withTimeout(...): if the poll times out and the app is genuinely idle, fail fast; if the app is still busy, keep polling.

The catch: once await device.disableSynchronization() is called, currentStatus() reports app_status: "idle" unconditionally — even while the app is mid-navigation, fetching, laying out, etc. So the idle signal becomes unusable in exactly the scenarios where you'd want to disable sync (slow/flaky sync sources, long-polling sockets, animations you'd rather poll past).

In other words, today users have to choose between:

  • sync on → reliable idle signal, but tests can hang indefinitely on background tasks Detox tracks as "busy" forever, and
  • sync off → tests progress, but no trustworthy idle/busy signal at all.

Proposed enhancement

Expose a public, supported API that reports the app's current idle/busy state and that continues to function when synchronization is disabled. Something like:

typescript
const { idle, busyResources } = await device.appStatus();
// idle: boolean
// busyResources: string[]   // e.g. ["RN bridge", "JS timers", "layout"]

Key requirements:

  1. Independent of disableSynchronization(). Disabling sync should stop Detox from blocking on busy resources, not stop it from observing them.
  2. Cross-platform. Today the underlying currentStatus() returns a structured object on iOS but a free-form string ("The app seems to be idle") on Android, which isn't programmatically usable. A unified shape would help.
  3. Stable / documented. A public method on device so consumers don't reach into device.deviceDriver.client (which can break across versions).

Use case

Layered idle-aware polling for tests that run with sync disabled:

typescript
// pseudo-code
while (Date.now() < deadline) {
  try {
    await waitFor(el).toBeVisible().withTimeout(200);
    return;
  } catch {
    const { idle } = await device.appStatus();
    if (idle) throw new Error(\"element not visible and app is idle\");
    // app is still busy → keep polling
  }
}

This pattern only works if appStatus() reflects real busy/idle state regardless of whether synchronization is enabled.

Alternatives considered

  • Re-enabling sync selectively — not viable for us; some background work legitimately never settles from Detox's perspective.
  • Reading deviceDriver.client.currentStatus() directly — what we do today; fragile (private API) and broken-by-design on Android + when sync is off.
  • Polling app-side test hooks — pollutes production code with test-only paths, which we want to avoid.