Chapter 23 · Expo Web To Native
Subchapter 23.4
references/verify-on-device.mdMarkdown4 KBView on GitHub
Disclosed reference for expo-web-to-native, steps 3–4. Verification means running both apps and comparing the same screen - the native port beside the web original. A clean compile or a green proves nothing - a screen can build and still render blank or mis-render. This parity check is the gate the strangle loop runs each iteration.
expo exportTwo agents drive it, and this skill is opinionated: it requires both and installs them rather than falling back to manual screenshots.
agent-browser (vercel-labs, a Rust browser CLI): open <url>, snapshot --json (accessibility tree with refs), screenshot <path>, read (rendered DOM/text).argent (@swmansion/argent): drives the simulator — describe (a11y tree), debugger-component-tree (RN tree), gesture-tap/keyboard, flow to record a check and replay it each pass. Invoke as argent run <tool> --udid <udid> (get the udid from argent run list-devices).Check both are on PATH; if either is absent, ask the user, then install before proceeding:
which agent-browser || (npm i -g agent-browser && agent-browser install) # web agent (+ its Chrome)
which argent || npm i -g @swmansion/argent # device agentA. Capture the web original with agent-browser — the source of truth for parity. Run the web app (its pnpm dev server, or the deployed URL if local setup needs DB/auth env), then:
agent-browser open "<web-url>/<route>?<params>"
agent-browser snapshot --json # structure to diff
agent-browser screenshot web.png # visual referenceTip: capture web baselines for every screen once, up front, then diff against them instead of re-opening the web app each iteration.
B. Capture the native screen (iOS shown via simctl; Android note below):
npx expo start --ios (Expo Go). On SDK 56+ both @expo/ui and DOM components run in Expo Go — no dev build, no react-native-webview to install; reach for a dev build (the expo-dev-client skill) only for custom native modules. Stale-bundle trap: a CI-mode Metro + cached Expo Go can show an old build — terminate Expo Go and add --clear if a change doesn’t appear.xcrun simctl boot <udid> (xcrun simctl list devices available); open -a Simulator.xcrun simctl openurl booted "exp://<lan-ip>:8081/--/<route>?<params>", or argent launch-app + gesture-tap.xcrun simctl io booted screenshot native.png, or argent run describe --udid <udid> for structure.Android:
simctl/expo run:iosare iOS-only. Use an Android emulator +adb—adb exec-out screencap -p > native.png,adb shell am start -a android.intent.action.VIEW -d "<deep-link>",adb shell screenrecordfor motion — ornpx expo run:androidfor a dev build.
C. Compare the two for the same route — layout, content, behavior. Diff the structures (agent-browser snapshot against argent describe / debugger-component-tree), not just pixels. Pass only on parity: same data, and params passed into a DOM webview must produce the same result.
Feel needs motion, not a still. For a nativized screen with transitions, gestures, or haptics, a screenshot can’t catch a janky push or wrong easing — capture a short recording (iOS xcrun simctl io booted recordVideo feel.mov; Android adb shell screenrecord; or an argent flow) and confirm it moves like a native app (see native-patterns.md → Feel).