Skip to Content

Testing

NativeExpress includes Jest tests for application logic and components, plus Maestro flows that exercise the installed app.

Run the Jest suite

yarn test yarn test:watch

The suite uses jest-expo and React Native Testing Library. It covers auth flows, session handling, analytics events, paywalls, image storage, chat transport, onboarding and shared components. Add tests for the behavior you introduce.

Tests sit beside the files they cover, except route tests. Keep those under src/__tests__/app/, at the same relative path as the screen. Tests under src/app/ would become routes; yarn check:routes rejects them.

      • useSignUp.ts
      • useSignUp.test.tsx
    • app/(public)/check-email.tsx - Route
    • __tests__/app/(public)/check-email.test.tsx - Route test
  • jest.config.js - Jest configuration
  • jest.setup.ts - Test setup and native mocks

If Jest fails on untranspiled code inside a new dependency, check transformIgnorePatterns in jest.config.js. The configuration already handles packages such as HeroUI Native, Uniwind and react-native-marked.

Run the project checks

yarn ci

This runs formatting, type checking, lint, Jest and the documentation, i18n, environment, skill, edge-function, route, theme and feature-boundary checks. yarn check:theme fails on a hand-edited theme, a missed contrast floor or a raw colour in app code; see Design. yarn check:features fails when a feature imports another one.

CI runs three more checks that are not part of yarn ci:

CheckWhat it proves
yarn check:feature-variantsChat only, Create only, Scan only and the empty shell each pass the gate after yarn remove:feature
yarn check:integration-variantsThe app without Sentry, OneSignal or PostHog passes the gate after yarn remove:integration
yarn check:dbGrants, row-level security and buckets against a running Supabase instance

The first two are described in Removing features and integrations. Maestro flows are separate too.

End-to-end flows

Six flows are included in .maestro/:

FlowWhat it exercisesStarting state
smoke.yamlAll five tabs and a stable element on eachSigned in
auth-signup.yamlOnboarding to email/password sign-upClears app state; expects sign-up to create a session
chat-send.yamlA new chat and an assistant responseSigned in, with working AI configuration and quota
create-generate.yamlImage generation or a Pro-required resultSigned in
scan-history.yamlScan history or its empty stateSigned in
screenshots.yamlListing screenshotsSigned in; receives APP_ID and OUT_DIR

Install Maestro and a test build

Follow the Maestro CLI installation guide . Install a preview or release build on the device or emulator you will test:

eas build --profile preview

A development client’s floating menu can cover header controls. Preview and release builds avoid that interference.

Set the app IDs

The five test flows each declare appId: com.robinfaraj.nativeexpress in their own header. Replace that value in each flow with your iOS bundle identifier or Android package name. Changing .maestro/config.yaml alone does not replace those headers.

screenshots.yaml uses ${APP_ID} instead. The store-assets skill supplies that parameter when capturing listing assets.

Prepare the session and assertions

Sign in with a test account before running the tab flows. The supplied sign-up flow uses a generated .test email address and expects immediate sign-in; it does not read confirmation emails. If Confirm email is enabled, adapt it for your test-mail setup or sign in with a confirmed account for the other flows.

Check the conditional assertions in create-generate.yaml and scan-history.yaml before relying on them. Their bare string assertions select visible text. For a testID, use the explicit Maestro ID selector :

- assertVisible: id: 'create-result'

Use the same form for create-pro-required, scan-history-row and scan-empty-capture. Review the selected elements after changing a screen.

Run a flow

maestro test .maestro/smoke.yaml maestro test .maestro/chat-send.yaml

Run screenshot capture separately with the store-assets skill. It needs its own output directory and app ID.

Verify

Maestro should report that the selected flow passed. Check its assertions cover the result you intended: scan history visibility does not verify a new scan, and a Pro-required state does not verify successful image generation.

Add testIDs to new screens

Use stable testID values for controls and results that a flow needs to find:

<Button testID="onboarding-next" variant="primary"> <Button.Label>{i18n.t('onboarding.continue_button')}</Button.Label> </Button>

ID selectors keep the flow independent of translated labels. The screenshot flow uses these IDs too, so update the flow when you rename one.

Last updated on