In short, I want to test a Firebase function locally, specifically one that is triggered from a realtime database trigger. According to the docs for local testing, it seems that there are two ways of accomplishing local testing of Firebase functions:
firebase emulators:start --only functions
)firebase functions:shell
)First, the differences between the two, at least in the linked guide, are very unclear. For the Firebase folks reading this, doc updates here would be great (considering local testing of this stuff is such an important feature).
My focus in this question (with respect to what I've tried) is based on the emulator, namely because it's mentioned that there are "interactions with other services". Interestingly, the list there only includes two items:
There is a notable omission of Realtime Database, and maybe that's where the gap is, but here we go.
My function looks something like this:
console.log("Hello World")
exports.myDatabaseTrigger = functions.database.ref('/a/path/{id}').onCreate((data, context) => {
console.log(`myDatabaseTrigger triggered - here's my path ${data.ref.path}`);
//manipulate some other stuff in the DB
})
In my project, I am using both Functions and Realtime Database, so I run the command firebase emulators:start
and it starts up both emulators.
In Postman, I use the local Realtime Database REST API to post some data with the following params:
POST
http://localhost:9000/a/path.json
{
"some": "data"
}
And I get back a response containing the name of the newly created item under /a/path
. However, my Firebase function never fires, and I never see the inner log (although the Hello World
log does print when the emulator starts).
So, is the interaction between these two emulators possible? Or, am I forced to use the functions shell? My issue with the shell is that, based on the realtime database examples, it's not clear what the DataSnapshot variables (i.e. data.ref.path
) will be if I simply call my function with some random value (e.g. myDatabaseTrigger({"some": "data"})
).
It looks like you may have just forgotten the project/namespace ID.
Try adding the ?ns=
parameter to your POST:
POST
http://localhost:9000/a/path.json?ns="YOUR_PROJECT_ID"
{
"some": "data"
}
Emulated functions only trigger from writes to a single database instance, just like in production.
As for your points of confusion:
functions:shell
is just a REPL for functions. It does not emulate any other services (Database, Firestore, etc). Instead you directly pass in the data that would come from those services.emulators:start --only database,functions
emulators:start
is that we comprehensively emulate whatever is running. So for example if you're running the Functions and Database emulator, all writes from functions (through admin.database()....
will be redirected to the Database emulator. But writes to Firestore (admin.firestore()...
) will try and hit production because that emulator is not running.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With