Varun Gupta
Varun Gupta

Reputation: 3112

jest test finishes before the mocked firebase function is called and hence fails

I am trying to use jest to test calls to firebase. Firebase is an online database service offered by Google. I am mocking the firebase module like below

'use strict';

const firebase = jest.genMockFromModule('firebase');

const ref = jest.fn(() => {
  return {
    child: jest.fn(() => {
      return ref
    }),
    update: jest.fn(() => {
      console.log('Called update')
      return Promise.resolve()
    })
  }
})

firebase.initializeApp = jest.fn()
firebase.database = jest.fn(() => {
  return {
    ref: ref
  }
})

module.exports = firebase

I am only mocking the functions that I need to test at the moment. Below is my test case.

it('+++ actionCreator addAlarm', () => {
    const store = mockStore(initialState)
    store.dispatch(ActionCreators.addAlarm(alarm));
    // Make sure that the scheduleNotifications API is called
    expect(scheduleNotifications).toHaveBeenCalled();
    expect(firebase.initializeApp).toHaveBeenCalled();
    expect(firebase.database().ref().update).toHaveBeenCalled();
});

The last line in the test case is trying to make sure that I am calling the firebase update function which is mocked.

Below is the console output

abcs-MBP-2:GalarmApp abc$ npm test

> [email protected] test /Users/abc/Projects/GalarmApp
> jest

 FAIL  __tests__/actionsSpecs.js
  ● >>>A C T I O N --- Test galarm actions:  › +++ actionCreator addAlarm

    expect(jest.fn()).toHaveBeenCalled()

    Expected mock function to have been called.

      at Object.<anonymous> (__tests__/actionsSpecs.js:58:52)
      at tryCallTwo (node_modules/promise/lib/core.js:45:5)
      at doResolve (node_modules/promise/lib/core.js:200:13)
      at new Promise (node_modules/promise/lib/core.js:66:3)
      at Promise.resolve.then.el (node_modules/p-map/index.js:42:16)
      at tryCallOne (node_modules/promise/lib/core.js:37:12)
      at node_modules/promise/lib/core.js:123:15

  >>>A C T I O N --- Test galarm actions:
    ✕ +++ actionCreator addAlarm (8ms)
    ✓ +++ actionCreator setConnectionStatus (4ms)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 passed, 2 total
Snapshots:   1 passed, 1 total
Time:        1.989s, estimated 2s
Ran all test suites.
  console.warn node_modules/rn-host-detect/index.js:45
    [SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()

  console.log __mocks__/firebase.js:11
    Called update

The test case is failing on the line where I check that the update function is called. If you look down in the console output, you will see that Called update console is present which means that the update function is called but it is called after the test case has failed.

This is the addAlarm action which is a thunk action

const addAlarm = (alarm) =>  (dispatch, getState) => {
  if(alarm.status) {
    NotificationManager.scheduleNotifications(alarm);
  }

  const alarmObjForFirebase = this.createAlarmObjForFirebase(alarm) 
  firebaseRef.update(alarmObjForFirebase)
}

The call to firebase update function is not happening asynchronously as far as I understand.

Please let me know if you have pointers on how I may be able to fix this problem.

Upvotes: 2

Views: 461

Answers (1)

Varun Gupta
Varun Gupta

Reputation: 3112

I have found the problem in my code and posting as a solution for others benefit. The problem is the way the update mock was defined. The way it was defined, I was getting a new instance of the update mock function every time I will make a call to firebase.database().ref().update. Since this is a new instance of the mock function, it wouldn't contain any data aboutupdate` function being called in the past.

I needed to change the code as follows

const update = jest.fn(() => {
  return Promise.resolve()
})

const ref = jest.fn(() => {
  return {
    update: update
  }
})

This way, I am not creating new instances of the update mock function and I was able to assert that it has been called during the testcase.

Upvotes: 3

Related Questions