soumak77 / firebase-mock

Firebase mock library for writing unit tests
https://soumak77.github.io/firebase-mock
349 stars 97 forks source link

Firebase-mock's firestore() function does not return a singleton #156

Open Venryx opened 4 years ago

Venryx commented 4 years ago

The official require("firebase/app").firestore() function returns a singleton -- that is:

import firebase from "firebase/app";
firebase.initializeApp(/* ... */);
assert(firebase.firestore() === firebase.firestore()`); // always succeeds

However, the firebase-mock equivalent is inconsistent with that:

import {MockFirebaseSdk} from "firebase-mock";
const firebase = new MockFirebaseSdk();
assert(firebase.firestore() === firebase.firestore()); // always fails

To be consistent with the official firebase API, shouldn't additional calls to firestore() return the same singleton-value each time?

(This issue caused a lot of lost time in my project, as the configuration I made to one instance was mysteriously not being "seen" by another section of code, and it turned out to be due to the non-singleton behavior of the firebase-mock firestore() equivalent.)

Venryx commented 4 years ago

Anyway, in the meantime, this is what I use to fix it:

// By default, mockFirebaseSdk.firestore() will return a new/different instance each time it's called!
// So, we modify it to return the same singleton-value each time.

window.globalMockFirebaseSdk = new MockFirebaseSdk(); // use this globally

const firestoreSingleton = globalMockFirebaseSdk.firestore();
globalMockFirebaseSdk.firestore = ()=>firestoreSingleton; // always return the same instance
Venryx commented 4 years ago

Found a better way to resolve the issue, as seen here:

import {MockFirebaseSdk, MockAuthentication, MockFirestore} from "firebase-mock";

const realTimeDBMock = null;
const authMock = new MockAuthentication();
authMock.autoFlush();
const firestoreMock = new MockFirestore();
firestoreMock.autoFlush();
const storageMock = null;
const messagingMock = null;

const firebaseSdkMock = new MockFirebaseSdk(()=>realTimeDBMock, ()=>authMock, ()=>firestoreMock, ()=>storageMock, ()=>messagingMock);
console.log("Set up Firebase app/sdk mock:", firebaseSdkMock);

While this resolves the issue, I think the default behavior should be changed, such that if no values are supplied for the new MockFirebaseSDK(...) parameters, they default to "singleton" behavior (consistent with the official API), instead of the current "return new instance each time you call .auth(), .firestore(), etc" behavior.