3

I cannot figure out how to jest mock firebase authentication with google login properly.I have the following code:

simple.tsx

import React, { Component } from 'react';
import * as firebase from 'firebase'
import { withRouter} from 'react-router-dom';

class simple extends Component {

  signInWithgoogle() {
    var provider = new firebase.auth.GoogleAuthProvider();
    // how to mock provider when simulate click event.
    firebaseApp.auth().signInWithRedirect(provider)

  }

  render() {
    return (
      <div>
        <button onClick={this.signInWithgoogle.bind(this)}>
          Login with Google
        </button>
      </div>

    );
  }
export default withRouter(connect(
)(simple));

simple.test.tsx

const mockStore = configureMockStore([thunk]);
const store = mockStore();

describe('<simple />', () => {
    test("simulate click button", () =>{
        const withProvider = (
            <Provider store={store}>
                <simple.WrappedComponent {...FirebaseAuthProps} />
            </Provider>
        );

        const wrapper = mount(withProvider);
        wrapper.find('Button').simulate('click');
    });
});

Any help would be appreciated with examples?

amstriker
  • 339
  • 7
  • 19

2 Answers2

4

Typescript namespace is some kind of a JS function after compiling and type erasure. After knowing this, of course, you can assign properties to JS function. Here is the solution:

simple.tsx:

import React, { Component } from 'react';
import firebase from 'firebase';
import { withRouter } from 'react-router-dom';

class simple extends Component {
  signInWithgoogle() {
    var provider = new firebase.auth.GoogleAuthProvider();
    firebase.auth().signInWithRedirect(provider);
  }

  render() {
    return (
      <div>
        <button onClick={this.signInWithgoogle.bind(this)}>Login with Google</button>
      </div>
    );
  }
}

export default withRouter(simple as any);

simple.spec.tsx:

import React from 'react';
import { mount } from 'enzyme';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import simple from './simple';
import firebase from 'firebase';

const mockStore = configureMockStore([thunk]);
const store = mockStore();
const FirebaseAuthProps = {};

jest.mock('firebase', () => {
  const auth = jest.fn();
  const mAuth = { signInWithRedirect: jest.fn() };
  // @ts-ignore
  auth.GoogleAuthProvider = jest.fn();
  // @ts-ignore
  auth.Auth = jest.fn(() => mAuth);
  return { auth };
});

describe('<simple />', () => {
  afterEach(() => {
    jest.resetAllMocks();
  });
  test('simulate click button', () => {
    // @ts-ignore
    firebase.auth.mockImplementation(() => new firebase.auth.Auth());
    const withProvider = (
      <Provider store={store}>
        <simple.WrappedComponent {...FirebaseAuthProps} />
      </Provider>
    );

    const wrapper = mount(withProvider);
    expect(wrapper.find('button').text()).toBe('Login with Google');
    wrapper.find('button').simulate('click');
    expect(firebase.auth.GoogleAuthProvider).toBeCalledTimes(1);
    expect(firebase.auth).toBeCalledTimes(1);
    expect(firebase.auth().signInWithRedirect).toBeCalledTimes(1);
  });
});

Unit test result with 100% coverage:

 PASS  src/stackoverflow/58554920/simple.spec.tsx (15.341s)
  <simple />
    ✓ simulate click button (82ms)

------------|----------|----------|----------|----------|-------------------|
File        |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
------------|----------|----------|----------|----------|-------------------|
All files   |      100 |      100 |      100 |      100 |                   |
 simple.tsx |      100 |      100 |      100 |      100 |                   |
------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        17.245s

Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/58554920

Lin Du
  • 88,126
  • 95
  • 281
  • 483
  • FYI: I used `jest.clearAllMocks()` instead of `jest.resetAllMocks()` otherwise it kept returning `undefined` for my mocks. – Richard Nov 13 '20 at 04:21
2

I also have a similar solution, if you decide to use Firebase Auth with Firebase Analytics:

jest.mock('firebase/app', () => {
  const analytics = jest.fn().mockReturnValue({
    logEvent: jest.fn(),
  });

  const auth: any = jest.fn().mockReturnValue({
    signInWithRedirect: jest.fn(),
    getRedirectResult: jest.fn().mockResolvedValue({
      credential: {
        providerId: 'Google',
      },
      user: {
        getIdToken: jest.fn().mockResolvedValue('abc1234'),
      },
      additionalUserInfo: {
        profile: {
          email: 'test@test.com',
          name: 'John Doe',
        },
      },
    }),
  });

  auth.GoogleAuthProvider = class {
    addScope = jest.fn();
  };

  return { auth, analytics };
});
Felipe
  • 6,312
  • 11
  • 52
  • 70