Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot mock admin.firestore() during unit tests

I am reading how to mock google cloud functions for firebase and have issues of properly mocking the following code:

const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
var db = admin.firestore();

The example in the link uses the following code to mock initializeApp which does work

admin = require('firebase-admin');
adminInitStub = sinon.stub(admin, 'initializeApp');

Now admin.firestore is defined in firebase-namespace.js as following:

Object.defineProperty(FirebaseNamespace.prototype, "firestore", {
    get: function () {
        var ns = this;
        var fn = function (app) {
            return ns.ensureApp(app).firestore();
        };
        return Object.assign(fn, require('@google-cloud/firestore'));
    },
    enumerable: true,
    configurable: true
});

I've tried various things to stub this but I fail

  1. Results in firestore is not a function:

        Object.defineProperty(admin, "firestore", {
            get: function () {
                return 32;
            }
        });
    
  2. Does not mock firestore() at all and calls the original function which fails hard:

        sinon.stub(admin, 'firestore').returns({get() { }});
    
  3. TypeError: Cannot stub non-existent own property get

       firestoreStub = sinon.stub(admin.firestore, 'get').callsFake(function () {return {data:"Foo"}});
    

I lack understanding what admin.firebase() actually is. It does not look like it is a property because AFAI when I mock a getter of a property, I would call admin.firebase and not a function admin.firebase(). But it is also not mockable via a function.

like image 428
Samuel Avatar asked Jan 07 '18 16:01

Samuel


1 Answers

That really took me too long.

To be able to mock the admin.firebase() the getter function of the property should actually return a function.

My initial assumption was that firebase() is a function, which it was not. Then by looking at the implementation I understood that this is a property with a custom getter. However I tried to return some json data block via the getter.

I initially failed to understand that admin.firestore is indeed a property but I was missing the key on why I have to call the property as a function, which is typically not needed on the property itself.

After getting to the point I understood that the getter of the property actually returned a function and that the admin.firebase() can be read like

var method = admin.firebase; // calling the property getter function
method(); // assuming the getter returned a function object

So for my future self ;) this does the trick:

sinon.stub(admin, 'firestore')
   .get(function() { 
       return function() { 
           return "data";
       }
   });

Originally I was trying to do

sinon.stub(admin, 'firestore').get( function () { return "data"; } ); which failed because the admin.firestore() ultimately yielded in "data"(), which made no sense.

like image 99
Samuel Avatar answered Sep 30 '22 10:09

Samuel