Skip to content

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.