Search code examples
reactjsreact-nativejestjsreact-native-testing-libraryreact-native-community-netinfo

Writing a unit test to check if the app is offline in react-native


I have the following component which displays a text on the app if the app is offline.

import React from 'react';

import { useNetInfo } from '@react-native-community/netinfo';

import { Label } from 'components/ui';

const OfflineNotice = () => {
  const netInfo = useNetInfo();

  if (netInfo.type !== 'unknown' && netInfo.isInternetReachable === false) {
    return <Label size={18} text='No Internet Connection' />;
  }

  return null;
};

export default OfflineNotice;

I want to write a unit test to this to check if this works properly. How can I do this? Im new to unit tests. I don't understand how to mock this.

I use typescript and testing-library/react-native.

UPATED: Why does this first test fail? It should NOT TO BE NULL. But it fails. The error is,

OfflineNotice component › test

expect(received).not.toBeNull()

Received: null

  15 | 
  16 |     const { queryByText } = render(<OfflineNotice />);
> 17 |     expect(queryByText(/no internet connection/i)).not.toBeNull();
     |                                                        ^
  18 |   });
  19 | 

  at Object.<anonymous> (src/components/offline-notice/offline-notice.test.tsx:17:56)

Solution

  • Cruising the react-native-netinfo github repo, troubleshooting section

    You should then add the following to your Jest setup file to mock the NetInfo Native Module:

    import mockRNCNetInfo from '@react-native-community/netinfo/jest/netinfo-mock.js';
    
    jest.mock('@react-native-community/netinfo', () => mockRNCNetInfo);
    

    Their mock for testing is:

    const defaultState = {
      type: 'cellular',
      isConnected: true,
      isInternetReachable: true,
      details: {
        isConnectionExpensive: true,
        cellularGeneration: '3g',
      },
    };
    
    const RNCNetInfoMock = {
      configure: jest.fn(),
      fetch: jest.fn(),
      addEventListener: jest.fn(),
      useNetInfo: jest.fn(),
    };
    
    RNCNetInfoMock.useNetInfo.mockResolvedValue(defaultState);
    

    Given this I think you could craft your own mock resolved values in each unit test case:

    import { useNetInfo } from '@react-native-community/netinfo';
    
    jest.mock('@react-native-community/netinfo', () => {
      useNetInfo: jest.fn(),
    });
    
    ...
    
    // Happy path test, known type and internet unreachable
    useNetInfo.mockResolvedValueOnce({
      type: 'test', // not 'unknown'
      isInternetReachable: false,
    });
    // assert render non-null
    const { queryByText } = render(<OfflineNotice />);
    expect(queryByText(/no internet connection/i)).not.toBeNull();
    
    ...
    
    // Sad path test, known type and internet reachable
    useNetInfo.mockResolvedValueOnce({
      type: 'test', // not 'unknown'
      isInternetReachable: true,
    });
    // assert render null
    const { queryByText } = render(<OfflineNotice />);
    expect(queryByText(/no internet connection/i)).toBeNull();
    
    ...
    
    // Sad path test, unknown type and internet unreachable
    useNetInfo.mockResolvedValueOnce({
      type: 'unknown',
      isInternetReachable: false,
    });
    // assert render null
    const { queryByText } = render(<OfflineNotice />);
    expect(queryByText(/no internet connection/i)).toBeNull();
    
    ...
    
    // Sad path test, unknown type and internet reachable
    useNetInfo.mockResolvedValueOnce({
      type: 'test', // not 'unknown'
      isInternetReachable: true,
    });
    // assert render null
    const { queryByText } = render(<OfflineNotice />);
    expect(queryByText(/no internet connection/i)).toBeNull();
    

    React-Native-Testing-Library

    React-Testing-Library