React-Native Use Jest to test the AppState
Asked Answered
H

2

6

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?

Handgrip answered 2/1, 2020 at 9:9 Comment(0)
R
8

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.
});
Redound answered 14/1, 2022 at 18:39 Comment(2)
How can you call something within mock.calls, how can this be used to trigger the appState change. The documentation says mock.calls is used to track calls made, how can we trigger something that hasn't happened yet ? I'd love help please @RedoundRobb
Mock.calls is also an array of parameters in the functions invoked on the spy addEventListener which was called on mount. When we grab the parameter it was called with it happens to be a function, as a function it's just a value like anything else, we can invoke it with ('active').Redound
L
3

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.

Lennon answered 2/1, 2020 at 21:45 Comment(3)
@elyakvarado I am getting the error: Cannot find module '@services/appState', also dont understand why you need to do this: const svc = require('@services/appState').default. Can you give some more explanation and explain why I am getting that error?Handgrip
Hi @Hans, @services/appState is in my code, the above fragment is an example. In your case you'll have to substitute it by the code the code that calls AppState.addEventListener.Lennon
Dont exactly understand what you mean the addEventlistener is created on the mount of the componentHandgrip

© 2022 - 2025 — McMap. All rights reserved.