How to fix TypeError is not a function (testing promises with Jest)

47,499

It looks like the reason why you're getting this error has to do with the data you're mocking through Jest.

Try using jest.fn() to mock your getIdToken as a function, rather than a string:

const mockGetIdToken = jest.fn(() => 'abc123');

jest.mock('services/firebase', () => new Promise(resolve => resolve({
  signInWithEmailAndPassword: () => Promise.resolve({ getIdToken: mockGetIdToken }),
  getIdToken: mockGetIdToken,
  signOut: () => jest.fn()
})));

describe('login actions', () => {
  let store;

  beforeEach(() => {
    store = mockStore({});
  });

  it('signIn should call firebase', () => {
    const user = {
      email: '[email protected]',
      password: 'abd123'
    };

    return store.dispatch(signIn(user.email, user.password))
      .then(() => {
        console.log('TEST signIn SUCCESS');
        expect(mockSignIn).toHaveBeenCalled();
        expect(store.getActions()).toEqual({
          type: USER_ON_LOGGED_IN
        });
      })
      .catch((err) => {
        console.log('TEST signIn ERROR =>', err);
      });
  });
Share:
47,499

Related videos on Youtube

Leon Gaban
Author by

Leon Gaban

Investor, Powerlifter, Crypto investor and global citizen You can also find me here: @leongaban | github | panga.ventures

Updated on May 20, 2020

Comments

  • Leon Gaban
    Leon Gaban about 4 years

    I have a passing test now thanks to the answer here: How to test is chained promises in a jest test?

    However I'm still getting an error in the catch part of my test.

    I seem to not be able to correctly mock or spy this part in the actions file: .then(res => res.getIdToken())

    TEST signIn ERROR => TypeError: res.getIdToken is not a function

    enter image description here

    The Test

    jest.mock('services/firebase', () => new Promise(resolve => resolve({
      signInWithEmailAndPassword: () => Promise.resolve({ getIdToken: 'abc123' }),
      getIdToken: () => jest.fn(),
      signOut: () => jest.fn()
    })));
    
    describe('login actions', () => {
      let store;
    
      beforeEach(() => {
        store = mockStore({});
      });
    
      it('signIn should call firebase', () => {
        const user = {
          email: '[email protected]',
          password: 'abd123'
        };
    
        return store.dispatch(signIn(user.email, user.password))
          .then(() => {
            console.log('TEST signIn SUCCESS');
            expect(mockSignIn).toHaveBeenCalled();
            expect(store.getActions()).toEqual({
              type: USER_ON_LOGGED_IN
            });
          })
          .catch((err) => {
            console.log('TEST signIn ERROR =>', err);
          });
      });
    

    The SignIn actions/Login

    // Sign in action
    export const signIn = (email, password, redirectUrl = ROUTEPATH_DEFAULT_PAGE) => (dispatch) => {
      dispatch({ type: USER_LOGIN_PENDING });
    
      return firebase
        .then((auth) => {
          console.log('auth =>', auth);
          return auth.signInWithEmailAndPassword(email, password);
        })
        .catch((e) => {
          console.error('actions/Login/signIn', e);
          // Register a new user
          if (e.code === LOGIN_USER_NOT_FOUND) {
            dispatch(push(ROUTEPATH_FORBIDDEN));
            dispatch(toggleNotification(true, e.message, 'error'));
          } else {
            dispatch(displayError(true, e.message));
            setTimeout(() => {
              dispatch(displayError(false, ''));
            }, 5000);
            throw e;
          }
        })
    
        // I can't seem to mock this correctly
        .then(res => res.getIdToken())
        .then((idToken) => {
          if (!idToken) {
            dispatch(displayError(true, 'Sorry, there was an issue with getting your token.'));
          }
    
          dispatch(onCheckAuth(email));
          dispatch(push(redirectUrl));
        });
    };
    
    • Daniel Conde Marin
      Daniel Conde Marin over 6 years
      Replace signInWithEmailAndPassword: () => Promise.resolve({ getIdToken: 'abc123' }) with signInWithEmailAndPassword: () => Promise.resolve({ getIdToken: () => 'abc123' }). It needs to be a function, my original answer was already like a function :) stackoverflow.com/questions/48468299/…