Expose a public app idle/busy status that works with synchronization disabled
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:
const { idle, busyResources } = await device.appStatus();
// idle: boolean
// busyResources: string[] // e.g. ["RN bridge", "JS timers", "layout"]Key requirements:
- Independent of
disableSynchronization(). Disabling sync should stop Detox from blocking on busy resources, not stop it from observing them. - 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. - Stable / documented. A public method on
deviceso consumers don't reach intodevice.deviceDriver.client(which can break across versions).
Use case
Layered idle-aware polling for tests that run with sync disabled:
// 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.
Source: wix/Detox