Testing
An app built with SymbioteNative is tested the same way as any other React Native app — SymbioteNative doesn’t ask for a different tool. Two layers: headless component/integration tests, and real-device end-to-end journeys.
Component and integration tests — Vitest
Section titled “Component and integration tests — Vitest”Unit and integration tests run headless, against a fake Fabric slot — no simulator, no device, no build step:
pnpm test # vitest runTests live next to what they exercise (Component.test.ts(x) beside
Component.ts(x)), the same co-location convention across core/,
adapters/, and the example apps. This is the layer for reducer logic,
render-function output, and adapter-lifecycle behavior — anything that
doesn’t need a real native host to observe.
End-to-end journeys — Detox
Section titled “End-to-end journeys — Detox”Real-device (or simulator) tests drive an actual build of the app:
pnpm -C examples/react e2e:build:ios && pnpm -C examples/react e2e:test:iospnpm -C examples/react e2e:build:android && pnpm -C examples/react e2e:test:androidThe e2e:* scripts live in each example’s own package.json
(examples/react, examples/vue-sfc, examples/vue-tsx, examples/angular),
not the repo root.
A gotcha specific to perpetual animations
Section titled “A gotcha specific to perpetual animations”Detox’s default synchronization waits for the app to go idle before running
the next step — but an app with a perpetual native Animated.loop (a
heartbeat pulse, a spinner) never reports idle, so device.launchApp()
hangs. Disable synchronization for that launch:
await device.launchApp({ newInstance: true, launchArgs: { detoxEnableSynchronization: 0 } });You then drive individual assertions with explicit waitFor(...) calls
instead of relying on Detox’s automatic idle detection.