Skip to content

Reference

Testing

The testing skill provides knowledge for writing and running UI test flows for React Native feature verification. Covers test runner selection, timing rules, flow structure, multi-device testing, auth pre-flight, and permission handling.

Activates when Claude encounters tasks involving Maestro tests, E2E flows, testIDs, UI test execution, network mocking, store state inspection, or test assertions.

A Go-based drop-in replacement for Maestro with the same YAML syntax:

MetricMaestro (Java)maestro-runner (Go)
Binary size~300MB (with JVM)21MB
Startup time2-4s<100ms
Memory~400MB~30MB
Flow executionBaseline2-3x faster

After any UI interaction, React needs time to commit updates to the fiber tree.

Correct sequence:

  1. device_find / Maestro tap
  2. device_snapshot / Maestro assertVisible (wait for settle)
  3. cdp_store_state (now safe to read)

Wrong (race condition): tapping then immediately querying CDP returns stale state.

Per-step timing with maestro-runner + JPEG: ~1.4s (2.2x faster than Maestro + PNG baseline of ~3.1s).

  • Basic structure: appId header + step list
  • Never use clearState: true with Expo Dev Client (wipes Metro URL)
  • Navigation via deep links or testID taps
  • Assertions: assertVisible, assertNotVisible, text content matching
  • Stable semantic names: add-to-cart-btn, cart-badge, search-input
  • Dynamic IDs for list items: testID={`product-item-${item.id}`}
  • Every Pressable, TouchableOpacity, Button, TextInput, and scrollable container must have a testID
  • Never call cdp_component_tree without a filter parameter (full dumps produce 10K+ tokens)
  • Fiber tree presence does not mean screen visibility

Before testing, checks cdp_navigation_state for auth screens. If logged out:

  1. Scans for Maestro subflows (prefer login over registration)
  2. Strips clearState: true for Dev Client builds
  3. Wraps subflows with appId if missing
  4. Runs via maestro-runner, verifies arrival at main screen

For permission-gated flows, queries and sets the correct state:

PlatformQueryGrantRevokeReset
Androiddumpsyspm grantpm revokepm reset-permissions
iOS SimNot supportedsimctl privacy grantsimctl privacy revokesimctl privacy reset

Injects mocks via cdp_evaluate using global.__RN_AGENT_MOCKS__ before navigating to the screen under test.

Zustand v4+ uses useSyncExternalStore (not React Context), so fiber tree walking cannot detect stores. Projects must register store hooks:

if (__DEV__) {
global.__ZUSTAND_STORES__ = {
auth: useAuthStore,
cart: useCartStore,
};
}

Then cdp_store_state(path="cart.items") reads the live state.