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:watchThe 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 ciThis 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:
| Check | What it proves |
|---|---|
yarn check:feature-variants | Chat only, Create only, Scan only and the empty shell each pass the gate after yarn remove:feature |
yarn check:integration-variants | The app without Sentry, OneSignal or PostHog passes the gate after yarn remove:integration |
yarn check:db | Grants, 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/:
| Flow | What it exercises | Starting state |
|---|---|---|
smoke.yaml | All five tabs and a stable element on each | Signed in |
auth-signup.yaml | Onboarding to email/password sign-up | Clears app state; expects sign-up to create a session |
chat-send.yaml | A new chat and an assistant response | Signed in, with working AI configuration and quota |
create-generate.yaml | Image generation or a Pro-required result | Signed in |
scan-history.yaml | Scan history or its empty state | Signed in |
screenshots.yaml | Listing screenshots | Signed 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 previewA 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.yamlRun 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.