I have a Firebase Project using Functions, Storage, and Auth that I would like to do some rudimentary unit testing using mocha and the Emulator Suite (already working for local development).
I've read the documentation front to back several times and I don't seem to understand how to set this up. My specific challenge currently is that I cannot seem to get a simple function that returns a defined environment variable to return properly due to the environment variables not loading.
My setup is as follows:
functions/index.js
const functions = require("firebase-functions")
const admin = require('firebase-admin')
admin.initializeApp()
const { getFunctions } = require('firebase-admin/functions')
...
exports.requiresEnvVariable = functions.https.onCall((data, context) => {
return process.env.MYENV_VARIABLE || ':('
})
functions/tests/test.spec.js
const { expect } = require("chai")
const sinon = require("sinon")
const admin = require("firebase-admin")
console.log(process.env.GCLOUD_PROJECT)
const test = require("firebase-functions-test")({
projectId: process.env.GCLOUD_PROJECT
}, 'serviceAccount.json')
// I've played with calling this here and stubbing, asmentioned in the docs. Nothing seems to work.
//admin.initializeApp()
//adminInitStub = sinon.stub(admin, 'initializeApp')
const myFunctions = require("../index")
describe("Unit tests", () => {
it("A good and cool test description", async () => {
const wrapped = test.wrap(myFunctions.getTToken)
const data = {}
const result = await wrapped(data)
expect('yayitworked').to.eql(result)
})
})
functions/package.json
{
"name": "functions",
"description": "Cloud Functions for Firebase",
"scripts": {
"serve": "firebase emulators:start --only functions",
"shell": "firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log",
"tests": "mocha --exit tests/*.spec.js"
},
"engines": {
"node": "18"
},
"main": "index.js",
"dependencies": {
"axios": "^1.1.3",
"cors": "^2.8.5",
"firebase-admin": "^11.4.1",
"firebase-functions": "^4.1.1",
},
"devDependencies": {
"chai": "^4.3.7",
"firebase-functions-test": "^3.0.0",
"mocha": "^10.2.0",
"sinon": "^15.0.1"
},
"private": true
}
functions/.env
MYENV_VARIABLE=yayitworked
And I run from the functions folder:
firebase emulators:exec 'npm run tests'
giving AssertionError: expected ':(' to deeply equal 'yayitworked'
Why can I not access the environment variables?
CodePudding user response:
Short answer is that firebase-functions-test
package doesn't load environment variables stored in .env
file. You'd need to load the .env
file manually as part of your mocha test setup by using packages like https://www.npmjs.com/package/dotenv.
Longer answer is that the setup described in the question - combining the Firebase Emulator and firebase-functions-test
package - probably isn't working as you expect them to work.
When running
firebase emulators:exec 'npm run tests'
we get 2 separate instances of requiresEnvVariable
function:
One spun up by the Firebase Emulator. This function would have loaded the
.env
variables because Firebase Emulator includes logic to load environment variables in appropriate.env
files before spinning up a function.One spun up by your mocha test. This "function" is really a plain JS function and will inherit environment variables in the parent process.
Tests written using firebase-functions-test
are testing (2) function, not (1). In order to invoke the function (1) spun up by the Firebase Emulator, you'd need to make HTTP request to the URL exposed by the Firebase Emulator (see sample code)
(Side note: firebase-functions-test
package was released years before Firebase Emulator so isn't "Firebase emulator-aware" so to speak.)