How to mock separate objects under one property?

Viewed 167

I use firebase in my React component:

/App.js

import React, { useEffect } from 'react';
import { firebase } from './be/firebase';

function App() {
  useEffect(() => {
    console.log('@App');
    console.log(firebase.auth.GoogleAuthProvider.PROVIDER_ID);
    firebase.auth().onAuthStateChanged(/* stuff */);
  }, []);

  return <div></div>;
}

export default App;

As you acn see, under one JS object property (auth) I have two separate things: auth() function and auth object. The file where I configure my firebase project looks like this:

/be/firebase.js

import * as firebase from 'firebase/app';
import 'firebase/auth';

const firebaseConfig = { /* my config */ };

if (!firebase.apps.length) {
  firebase.initializeApp(firebaseConfig);
}

export { firebase };

It works fine in production, but how do I mock auth property with Jest? I try mocking it like this:

/App.test.js

jest.mock('./be/firebase', () => {
  return {
    firebase: {
      auth: {
        GoogleAuthProvider: {
          PROVIDER_ID: 'mock',
        },
        onAuthStateChanged: jest.fn(),
      },
    }
  };
});

But I get an error saying that auth() method is not defined (TypeError: _firebase.firebase.auth is not a function).

Thanks in advance for your time!

1 Answers

In JavaScript, functions are objects. A way to define a function this way is:

firebase.auth = () => ...;
firebase.auth.GoogleAuthProvider = ...;

In a mock, it should preferably be a spy and can be written as a single expression with Object.assign:

const mockOnAuthStateChanged = jest.fn();

jest.mock('./be/firebase', () => {
  return {
    firebase: {
      auth: Object.assign(
        jest.fn(() => ({ onAuthStateChanged: mockOnAuthStateChanged })),
        {
          GoogleAuthProvider: {
            PROVIDER_ID: 'mock',
          },
        }
      })
    }
  };
});

onAuthStateChanged is a property of an object that auth returns and not auth itself.

Related