Skip to content

Testing ​

Tests run on Jest (via jest-expo) with @testing-library/react-native.

sh
yarn test              # run the whole suite
yarn test Login        # run tests matching "Login"
yarn test --findRelatedTests src/Scenes/Login/Login.tsx

Conventions ​

  • Query the way a user interacts with the UI (getByText, findByTestId, …). See the RNTL query guide.
  • Do not use react-test-renderer directly.
  • Test files are co-located: ComponentName.tests.tsx for components, util.test.ts for utilities.
  • Do not leave testing shortcuts (fdescribe, describe.only, fit, it.only) in committed code.

Testing Relay components ​

Use setupTestWrapper from src/utils/test/ and mock resolvers through renderWithRelay. It supports both kinds of Relay component:

  • Self-fetching components that issue their own query (via useSystemQueryLoader / useLazyLoadQuery) — pass only the Component. The wrapper renders it under a mock environment and a Suspense boundary.
  • Fragment components (useFragment) — also pass a query that spreads the fragment, so the wrapper can drive it through a QueryRenderer.
tsx
import { setupTestWrapper } from "utils/test/setupTestWrapper"

// Self-fetching component (useSystemQueryLoader / useLazyLoadQuery)
const { renderWithRelay } = setupTestWrapper<HomeQuery>({
  Component: HomeScreen,
})

it("renders the user", () => {
  renderWithRelay({ Me: () => ({ name: "Andy Warhol" }) })
  expect(screen.getByText("Andy Warhol")).toBeTruthy()
})

// Fragment component (useFragment) — pass a query that spreads the fragment
const { renderWithRelay } = setupTestWrapper<HomeUserTestQuery>({
  Component: HomeUser,
  query: graphql`
    query HomeUserTestQuery @relay_test_operation {
      me {
        ...HomeUser_me
      }
    }
  `,
})

Testing non-Relay components ​

Use renderWithWrappers (also from src/utils/test/) for components that don't need a Relay environment — it still provides the store and theme.

Injecting store state ​

Read state in components with GlobalStore.useAppState(...). In tests you can seed the store to exercise a specific state (for example, a signed-in user).

End-to-end tests ​

Unit/integration tests above run in Jest. End-to-end tests drive a real iOS/Android simulator or emulator with agent-device: flows are recorded as .ad scripts under e2e/flows/ and replayed as repeatable checks.

sh
yarn e2e:doctor   # verify the local device environment
yarn e2e          # run all recorded checks (agent-device test e2e/flows)
yarn e2e:impact   # Sniffler: which flows the current diff affects

In CI, Sniffler analyzes a PR's dependency graph and selects only the e2e flows a diff can actually reach (failing open to the full suite when it can't tell). See E2E Testing for the full workflow.

Running in CI ​

Several GitHub Actions workflows run on pull requests and pushes to main:

  • Checks (checks.yml) — the same gates you run locally: yarn relay, yarn tsc, yarn test --ci --maxWorkers=2, yarn lint. yarn lint also enforces auto-sorted imports (simple-import-sort) and surfaces accessibility warnings (react-native-a11y).
  • Conventional Commits (run-conventional-commits-check.yml) — validates the PR title.
  • E2E impact (Sniffler) (e2e-impact.yml) — informational, never blocks; reports which e2e flows the diff affects.
  • E2E (agent-device) (agent-device-e2e.yml) — validates the agent-device setup on every e2e change, plus manual (workflow_dispatch) iOS/Android device runs.
  • Deploy Docs (deploy-docs.yml) — builds and publishes this VitePress site on pushes to main.
sh
yarn relay     # compile Relay artifacts
yarn tsc       # type-check
yarn test --ci --maxWorkers=2
yarn lint

If tests import a package that ships untranspiled ESM, add it to transformIgnorePatterns in jest.config.js.

Released under the MIT License.