4

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:

  • Using the firebase functions emulator (firebase emulators:start --only functions)
  • Using the firebase functions shell (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:

  • Cloud Firestore
  • Firebase Hosting

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"})).

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
MandM
  • 3,293
  • 4
  • 34
  • 56
  • Changes to the local database should trigger functions, but it might only work if you're using one of the SDKs locally (not a REST API). I suggest opening an issue on GitHub to get a staffer's thoughts. https://github.com/firebase/firebase-tools – Doug Stevenson Feb 07 '20 at 03:58
  • 1
    Thanks for the docs feedback! I sent this over to our tech writer. – Sam Stern Feb 19 '20 at 21:07

1 Answers1

7

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.
  • If you want to test Functions <--> Database interactions use emulators:start --only database,functions
  • In general the rule with 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.
Sam Stern
  • 24,624
  • 13
  • 93
  • 124
  • 1
    How can this solution/comment be so hard to find (and not in bold somewhere in the Firebase docs..)! Thanks Sam - this did the trick here :) – Ludo Apr 24 '20 at 15:00
  • Hi Sam, in emulator I wrote to: **admin.database().ref(`connections/foo/mentees`)** but my listener to onCreate at **ref("connections/{uid}/mentees")** didn't fire, is that expected here? – Nikos Jul 24 '20 at 06:17
  • If you were running both emulators that's unexpected. Please file a bug on the firebase-tools repo explaining how to reproduce. – Sam Stern Jul 24 '20 at 13:35
  • my mistake, I forgot to call res.json(data) in the previous function that does the set – Nikos Jul 24 '20 at 15:13
  • so it was hanging – Nikos Jul 24 '20 at 15:13