Allow disabling the dev menu while keeping Fast Refresh (for E2E / agent-driven testing)
m
mysliwiec67344
## Summary
Add a way to fully suppress the dev menu (shake, Cmd+D / Cmd+M, Android dev notification, programmatic triggers) on a development build while keeping HMR, Fast Refresh, and the Metro connection intact.
Ideally exposed as one of:
- DevSettings.setDevMenuEnabled(false)at runtime, or
- expo.developmentClient.devMenu: "disabled"inapp.json, or
- EXPO_DEV_MENU=disabledenv var for ephemeral CI / agent runs.
## Motivation
Maestro E2E tests against a
development build
are increasingly common, especially in AI-assisted workflows where an agent iterates on UI, runs maestro test
, reads results, and tries again. The dev build is preferred over preview/release because the rebuild cycle is seconds vs. minutes — critical for tight agent loops.The dev menu is the single biggest source of flakiness in this loop:
- Simulated input misfires the shake gesture
- Cmd+D/Cmd+Mcan be triggered by the harness or focus changes
- Android's persistent dev notification gets tapped by coordinate-based input
- The native SwiftUI dev menu on iOS lives in a separate UIWindowand is invisible to Maestro's text matching, so it can't be reliably dismissed from a flow
Today the only "complete" mitigation is
getUseDeveloperSupport() = false
, which also disables HMR — defeating the purpose of the dev build. DevSettings.setIsShakeToShowDevMenuEnabled(false)
exists but only covers shake.The Maestro maintainers' documented recommendation for this problem is
"Perform a Release rather than a Debug build"
(see mobile-dev-inc/Maestro discussion #3041). That works but kills the fast iteration loop that makes the dev build worth using in the first place.## Proposed API
```ts
import { DevSettings } from 'react-native';
DevSettings.setDevMenuEnabled(false); // suppress ALL dev menu entry points
Or Expo-level config in app.json:
```json
{ "expo": { "developmentClient": { "devMenu": "disabled" } } }
Fast Refresh, HMR, error overlays (optionally — agents benefit from those), and the Metro connection remain on. Only the menu is gone.
## Alternatives considered
- Preview/release build — too slow for agent iteration (minutes per cycle)
- Maestro subflow that dismisses the menu if visible — only partially works; iOS native dev menu is in a separate UIWindow and isn't matchable
- setIsShakeToShowDevMenuEnabled(false) — covers shake only; keyboard shortcuts and Android notification still fire
- getUseDeveloperSupport() = false — kills HMR, defeats the use case
## Why now
Agent-driven UI iteration (Claude Code, Cursor, etc.) is a fast-growing workflow. Maestro is the de facto E2E tool for it. The dev menu is the most common cause of false-negative test runs in this loop. A single flag would remove that entire class of flake without forcing teams onto the slow release-build path.
## Repro
Happy to provide a minimal repro repo on request — the behavior is reliably triggered by any npx create-expo-app + expo-dev-client + a Maestro flow that exercises gestures.