Testing Best Practices

July 2, 2025 ยท View on GitHub

React Native Testing

How should I query

Under the hood we are using @testing-library/react-native to render the component for the testing environment. This means that you can use the query methods that you would use with @testing-library/react-native.

Remember in your tests to always try to resemble how the user interacts with the UI as much as possible.

You can read more on how to query on the official docs here.

Examples

Testing a component that has useLazyLoadQuery

const Foo = () => {
  const data = useLazyLoadQuery(graphql`
    query FooQuery {
      me {
        name
      }
    }
  `)

  return <Text>{data.me.name}</Text>
}

export const FooScreen = () => {
  return (
    <Suspense fallback={<Flex testID="loading" />}>
      <Foo />
    </Suspense>
  )
}

const { renderWithRelay } = setupTestWrapper<FooQuery>({
  Component: FooScreen,
})

it("Displays the user's profile name", async () => {
  renderWithRelay({
    Me: () => ({ name: "name" }),
  })

  await waitForElementToBeRemoved(() => screen.getByTestId("loading"))

  expect(screen.queryByText("name")).toBeTruthy()
})

Testing a component with useFragment

const Bar = () => {
  const data = useFragment(graphql`
    fragment Bar_me on Me {
      name
    }
  `)

  return <Text>{data.name}</Text>
}

const { renderWithRelay } = setupTestWrapper<BarTestQuery>({
  Component: Bar,
  query: graphql`
    query BarTestQuery @relay_test_operation {
      me {
        ...Bar_me
      }
    }
  `,
})

it("Displays the user's profile name", () => {
  renderWithRelay({
    Me: () => ({ name: "Mock Name" }),
  })

  expect(screen.queryByText("name")).toEqual("Mock Name")
})

TODO: add more examples from the codebase

setupTestWrapper

The setupTestWrapper function is a testing helper designed to simplify the testing of components that use Relay for data fetching in a React/ React Native environment. It provides a way to render components under different Relay query configurations, allowing you to test various scenarios efficiently and easily.

setupTestWrapper params

ParameterDescription
ComponentThe React component you want to test. This component should be typed with the expected response shape for your GraphQL query.
preloadedA boolean flag that indicates whether you want to simulate preloaded data. When set to true, you must provide a query as well. Preloading is useful when you want to test scenarios where data is available immediately.
queryThe Relay query you want to test. This query should be typed with the expected response shape for your GraphQL query.
variablesThe variables to be used with the GraphQL query. You can provide default values if needed.

renderWithRelay function

The renderWithRelay function is returned by setupTestWrapper. It can be used to render your component and control the Relay environment for testing purposes.

const { renderWithRelay } = setupTestWrapper({
  Component: Foo,
  query: graphql`
    query FooQuery {
      me {
        name
      }
    }
  `,
})

const { env, mockResolveLastOperation, mockRejectLastOperation } = renderWithRelay()

renderWithRelay params

ParameterDescription
mockResolversThe resolvers for your top level component query
propsAny initial prop that you want to pass to the component that you are testing.

renderWithRelay return values

ParameterDescription
envThe Relay environment that is used to render your component.
mockResolveLastOperationA relay resolver that resolves the last operation that was executed by the Relay environment.
mockRejectLastOperationA relay resolver that rejects the last operation that was executed by the Relay environment.

renderWithWrappers

The renderWithWrappers function is a testing helper designed to simplify the testing of components in our React Native testing environment. It provides a way to render components wrapped with our wrappers, allowing you to test various scenarios efficiently and easily.

We use this function when we want to test something that is not related to Relay but needs the rest of the wrappers of our app, for example, a component that uses useNavigation hook.

Android Native Testing

For Android native code (Java/Kotlin), we use JUnit and MockK for unit testing. The tests are located in android/app/src/test/java/ and follow the standard Android testing patterns.

Running Android Tests

To run Android native tests during development:

# Run all Android unit tests
yarn android:test

# Or run directly with Gradle
cd android && ./gradlew testDebugUnitTest

# Run specific test class
cd android && ./gradlew testDebugUnitTest --tests "net.artsy.app.widgets.FullBleedWidgetProviderTest"

# Run tests matching a pattern
cd android && ./gradlew testDebugUnitTest --tests "net.artsy.app.widgets.*"

Android Test Examples

Widget tests are located in android/app/src/test/java/net/artsy/app/widgets/:

  • FullBleedWidgetProviderTest.kt - Tests core widget functionality
  • ArtworkRotationTest.kt - Comprehensive tests for artwork selection and state management

Test Reports

After running tests, HTML reports are generated at: android/app/build/reports/tests/testDebugUnitTest/index.html

The tests integrate with the existing development workflow and can be run alongside React Native tests in CI/CD pipelines.