React-Native Use Jest to test the AppState

How can I trigger the AppState listener to check if it works correctly?

AppState.addEventListener('change', (nextAppState) =>  { console.log('test')});

Is there a way in Jest to trigger this listener?


Yes, you can mock react-native native modules if you know where they are located. An example below, where I test if an app state service dispatches a given action when the app state changes:

  it('if a store is set dispatches an APP_STATE_CHANGE action with the new state on change', () => {

    let capturedChangeCallback = null

    const mockAddListener = jest.fn((event, callback) => {
      if (event === 'change') {
        capturedChangeCallback = callback
      }
    })

    jest.resetModules()
    jest.doMock('react-native/Libraries/AppState/AppState', () => ({
      addEventListener: mockAddListener,
    }))
    const mockStore = { dispatch: jest.fn() }

    const svc = require('@services/appState').default
    svc.setStore(mockStore)

    // change called
    capturedChangeCallback('active')

    expect(mockStore.dispatch).toHaveBeenCalledTimes(1)
    expect(mockStore.dispatch).toHaveBeenCalledWith({
      type: 'APP_STATE_CHANGE',
      payload: 'active',
    })
  })

The key here is the jest.doMock call passing the full AppState module location, and calling resetModules to make sure to isolate the test case.


I don't really understand how the first solutions works and I tried it but could not get it to work but there is a different way.

First to clarify, you are trying to invoke the function that is the second parameter of AppState.addEventListener('change', functionToInvokeOnChange) called on in the code. Luckily Jest gives a jest.spyOn method to any parameters that we call on AppState.addEventListener(...). If the second parameter is a function, there is no reason you can't call it in the jest environment.

Say you have,

useEffect(() => {
    AppState.addEventListener('change', _handlerFunction);

    /* ... */
}, []);

const _handlerFunction = async (nextAppState) => { /* ...*/ }

You can test this like this:

it('... on state change', async () => {
   const appStateSpy = jest.spyOn(AppState, 'addEventListener');
   rendered = render(<Component />);
   await appStateSpy.mock.calls[0][1]('active');
   //assert this or that happens ect.
});