Testing the useState hook in React Native

Posted in react-native-testing-library, quality-assurance on July 2, 2023 by Hemanta Sapkota ‐ 3 min read

Testing the useState hook in React Native

As a React Native developer, you need to test the useState hooks to ensure state updates correctly and the component renders as expected based on the state.

Step 1: Write the component code in React Native

Here is an example code for the component:

import React, { useState } from 'react';
import { Text, View } from 'react-native';

function ExampleComponent() {
  const [isLoading, setIsLoading] = useState(true);
  const [hasError, setHasError] = useState(false);

  if (isLoading) {
    return (
      <View>
        <Text>Loading...</Text>
      </View>
    );
  }

  if (hasError) {
    return (
      <View>
        <Text>Error!</Text>
      </View>
    );
  }

  return (
    <View>
      <Text>Data Loaded!</Text>
    </View>
  );
}

Step 2: Write a jest unit test covering all states

When testing a component with useState hooks, you should verify:

1.	The component renders correctly based on the state.
2.	The state updates correctly when the component is interacted with.
3.	The component correctly handles edge cases related to the state.

For the first aspect, render the component in different states and use expect statements to verify the output. For the second aspect, simulate user interactions and verify state updates. For the third aspect, create test cases for edge cases related to the state.

When testing a component with multiple useState hooks, test each hook separately to ensure correct state updates and rendering based on the state.

Here is an example test for the component:

import React from 'react';
import {render} from '@testing-library/react-native';
import {ExampleComponent} from './ExampleComponent';

jest.mock('react', () => ({
  ...jest.requireActual('react'),
  useState: jest.fn(),
}));

describe('MyComponent', () => {
  it('renders error state', () => {
    // @ts-ignore
    React.useState.mockReturnValueOnce([false, jest.fn()]);
    // @ts-ignore
    React.useState.mockReturnValueOnce([true, jest.fn()]);

    const wrapper = render(<ExampleComponent />);
    expect(wrapper.getByText('Error!')).toBeDefined();
    expect(wrapper.toJSON()).toMatchSnapshot();
  });

  it('renders default state', () => {
    // @ts-ignore
    React.useState.mockReturnValueOnce([false, jest.fn()]);
    // @ts-ignore
    React.useState.mockReturnValueOnce([false, jest.fn()]);

    const wrapper = render(<ExampleComponent />);
    expect(wrapper.getByText('Data Loaded!')).toBeDefined();
    expect(wrapper.toJSON()).toMatchSnapshot();
  });

  it('renders loading state', () => {
    // @ts-ignore
    React.useState.mockReturnValueOnce([false, jest.fn()]);
    // @ts-ignore
    React.useState.mockReturnValueOnce([false, jest.fn()]);

    const wrapper = render(<ExampleComponent />);
    expect(wrapper.getByText('Loading...')).toBeDefined();
  });
});

Step 3: Properly Organizing Mock useState Hooks in React Native Tests

When using multiple mock useState hooks in a single test, ensure they are ordered as they appear in the component code. Here’s an example:

  it('renders error state', () => {
    // @ts-ignore
    React.useState.mockReturnValueOnce([false, jest.fn()]);
    // @ts-ignore
    React.useState.mockReturnValueOnce([true, jest.fn()]);

    const wrapper = render(<ExampleComponent />);
    expect(wrapper.getByText('Error!')).toBeDefined();
    expect(wrapper.toJSON()).toMatchSnapshot();
  });

Mock the first hook to return [false, jest.fn()] and the second to return [true, jest.fn()], matching the order in the component code.

Step 3: Understanding the snapshots

Jest snapshots capture the output of a component and compare it to a previous version. When you run your tests, Jest creates a snapshot file containing the component’s output for each test case. These snapshots ensure your component renders correctly.

In the example, we have three test cases, each rendering the component in a different state. Jest creates separate snapshots for each, stored in a snapshot file in JSON format.

Example snapshot for the “renders default state” test case:

exports[`MyComponent renders default state 1`] = `
<View>
  <Text>
    Data Loaded!
  </Text>
</View>
`;

Each snapshot has a key describing the test case and a value with the component’s output.

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`MyComponent renders default state 1`] = `
<View>
  <Text>
    Data Loaded!
  </Text>
</View>
`;

exports[`MyComponent renders error state 1`] = `
<View>
  <Text>
    Error!
  </Text>
</View>
`;

exports[`MyComponent renders loading state 1`] = `
<View>
  <Text>
    Loading...
  </Text>
</View>
`;

By comparing the new output to the previous snapshot, Jest alerts you to changes, allowing you to decide whether to accept or update the snapshot.

And that’s it! You now know how to test the useState hook in React Native using the testing library.

comments powered by Disqus