firebase-admin-node: Unit Testing: The default Firebase app does not exist.

Environment

  • Operating System version: macOS High Sierra 10.13
  • Firebase SDK version: 4.6.0
  • Library version: 5.4.3
  • Firebase Product: any

Problem

Steps to reproduce:

  1. Create a project with Cloud functions enabled.
  2. Have at least the following dependencies:
  • “firebase”: “^4.6.0”,
  • “firebase-admin”: “^5.4.3”,
  • “firebase-functions”: “^0.7.1”,
  • “jasmine”: “^2.8.0”,
  1. Write a spec file which utilizes mocking data, e.g.
// onUserEmailWrite.spec.ts
// ...
functions = require('firebase-functions');
spyOn(functions, 'config').and.returnValue({
  firebase: {
    databaseURL: 'https://not-a-project.firebaseio.com',
    storageBucket: 'not-a-project.appspot.com',
    apiKey: '...',
    authDomain: 'not-a-project.firebaseapp.com',
  }
});
admin = require('firebase-admin');
spyOn(admin, 'initializeApp');
myFunctions = require('./onUserEmailWrite');
// ...
event = {
  params: {
    userId: 'AbmlJhRrdwg2kf6OKwKYlu0lLv52'
  },
  data: new functions.database.DeltaSnapshot(null, admin, null, 'user@example.com')
};
// ...
spyOn(admin, 'auth').and.returnValue({
  updateUser: (uid, properties) => {
    expect(uid).toBe(event.params.userId);
    expect(properties).toEqual({
      email: 'user@example.com',
    });

    return Promise.resolve();
  }
});
await myFunctions.onUserEmailWrite(event);
// ...
// onUserEmailWrite.ts
// ...
import * as admin from 'firebase-admin';
import * as functions from 'firebase-functions';
admin.initializeApp(functions.config().firebase);
// ...
functions.database.ref('/users/{userId}/email').onWrite(async event => {
  // ...
  const userId = event.data.adminRef.parent.key;
  const email = event.data.val();
  admin.auth().updateUser(userId, {email: email}); // causes issue
  // ...
});
// ...
  1. Run jasmine

Changing back firebase-admin to 5.3.0 made my unit tests run fine again. Any 5.4.* version does not resolve the issue.

Relevant Code:

Started
(node:2441) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: The default Firebase app does not exist. Make sure you call initializeApp() before using any of the Firebase services.
F

Failures:
1) onUserEmailWrite can skip if user is being deleted.
  Message:
    Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
  Stack:
    Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
        at ontimeout (timers.js:386:14)
        at tryOnTimeout (timers.js:250:5)
        at Timer.listOnTimeout (timers.js:214:5)

1 spec, 1 failure

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 18 (9 by maintainers)

Most upvoted comments

Following worked for me in mocha/sinon world:

    const updateUserStub = sinon.stub().returns('done');
    // admin.auth must return a callable object, so that admin.auth() would work.
    sinon.stub(admin, 'auth').get(function getterFn(){
        return () => {
            return {updateUser: updateUserStub};
        };
    })

Man, that took a while. I’m so glad it got resolved today. Thank you again for the guidance @hiranya911! For anyone who wants a reference in Jasmine:

spyOnProperty(admin, 'auth', 'get').and.returnValue(() => {
  return {
    updateUser: (uid, properties) => {
      expect(uid).toBe(event.params.userId);
      expect(properties).toEqual({
        email: 'user@example.com',
      });

      return Promise.resolve();
    }
  };
});

@zgosalvez Please update your stubs accordingly. All namespaces except admin.database are now exposed as getters that return functions. Soon, we will also expose admin.database in the same fashion (see #112).

Ok. In the latest admin SDK admin.auth is not a function, but a getter that returns a function. See https://github.com/firebase/firebase-admin-node/blob/master/src/firebase-namespace.ts#L284

You need to update your tests/stubs accordingly.