Search code examples
javascriptfirebasegoogle-cloud-functionssinonauth0

Stubbing auth0 in firebase functions


I have the following Firebase Function that makes use of Auth0 to get a user profile.

'use strict';

const {
    dialogflow,
    Image,
  } = require('actions-on-google')

const functions = require('firebase-functions');
const admin = require('firebase-admin');

admin.initializeApp(functions.config().firebase);

const db = admin.firestore();

// database collection and key names
const DB_BANK_COLLECTION_KEY = 'bank'
// the action name from all Dialogflow intents
const INTENT_WELCOME_USER = 'Default Welcome Intent';

// Initialize the Auth0 client
var AuthenticationClient = require('auth0').AuthenticationClient;
var auth0 = new AuthenticationClient({
    domain: functions.config().familybank.auth0.domain,
    clientID: functions.config().familybank.auth0.clientid
});

const app = dialogflow();

app.intent(INTENT_WELCOME_USER, async (conv) => {
    console.log('Request: ' + JSON.stringify(conv.request));

    const userInfo = await auth0.getProfile(conv.user.access.token)
    .catch( function(err) {
        console.error('Error getting userProfile from Auth0: ' + err);
        conv.close("Something went wrong. Please try again in a few minutes. " + err)
    });
    console.log('userInfo: ' + JSON.stringify(userInfo));

    // check for existing bank, if not present, create it
    var bankRef = db.collection(DB_BANK_COLLECTION_KEY).doc(userInfo.email);
    const bankSnapshot = await bankRef.get()

})

exports.accessAccount = functions.https.onRequest(app);

I tried to mock auth0 in my tests using the following code (and several permutations), but the actual function always gets called instead of the mock.

const chai = require('chai');
const assert = chai.assert;

const sinon = require('sinon');

// Require firebase-admin so we can stub out some of its methods.
const admin = require('firebase-admin');
const test = require('firebase-functions-test')();

var AuthenticationClient = require('auth0').AuthenticationClient;
var auth0 = new AuthenticationClient({
  domain: "mock",
  clientID: "mock"
});

describe('Cloud Functions', () => {
  let myFunctions, adminInitStub;

  before(() => {
    test.mockConfig({"familybank": {"auth0": {"domain": "mockdomain", "clientid": "mockid"}}});
    adminInitStub = sinon.stub(admin, 'initializeApp');
    sinon.stub(admin, 'firestore')
   .get(function() { 
       return function() { 
           return "data";
       }
    });
    sinon.stub(auth0, 'getProfile').callsFake( function fakeGetProfile(accessToken) {
      return Promise.resolve({"email": "[email protected]", "accessToken": accessToken});
    });
    myFunctions = require('../index');
  });

  after(() => {
    adminInitStub.restore();
    test.cleanup();
  });

  describe('accessAccount', () => {

    it('should return a 200', (done) => {
      const req = {REQUESTDATA};
      const res = {
        redirect: (code, url) => {
          assert.equal(code, 200);
          done();
        }
      };

      myFunctions.accessAccount(req, res);
    });
  });
})

Is there some way to mock auth0 for my offline tests?


Solution

  • I discovered that rather than initialize the Auth0 AuthenticationClient, I could first require the UsersManager, where the getProfile (which wraps getInfo) is defined.

    var UsersManager = require('auth0/src/auth/UsersManager');
    

    In my before() method, I can then create a stub for getInfo, like this

    sinon.stub(UsersManager.prototype, 'getInfo').callsFake( function fakeGetProfile() {
      return Promise.resolve({"email": "[email protected]"});
    });
    

    All the calls to auth0.getProfile then return a Promise that resolves to the document shown in my stub fake function.