How to use firebase emulators pubsub to test timed functions locally?

The Firebase local emulator currently doesn't simulate the actual scheduled functions. The documentation says:

The Firebase CLI includes a Cloud Functions emulator which can emulate the following function types:

  • HTTPS functions
  • Callable functions
  • Cloud Firestore functions

I suggest filing a feature request with Firebase support.

When you deploy a scheduled function, you are actually using Google Cloud Scheduler behind the scenes. The details are managed for you. As stated in the documentation:

If you want to schedule functions to run at specified times, use functions.pubsub.schedule().onRun() This convenience method creates a Google Cloud Pub/Sub topic and uses Google Cloud Scheduler to trigger events on that topic, ensuring that your function runs on the desired schedule.

I suggest refactoring your function's code into a method that you can test by invoking it directly using a test framework of your choice. You could also temporarily wrap it in an HTTP function and invoke it that way.


Actually there is a Firebase PubSub emulator. To enable it you need to have the recent CLI installed (it's in 8.2.0 for sure)

  • Rerun Firebase Init
  • Select Emulators (spacebar)
  • Select PubSub (and others you wish)
  • Configure your desired dev ports
  • Have the CLI install the emulators

Create a test script locally to submit PubSub messages into the queue:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

const { PubSub } = require('@google-cloud/pubsub');
const pubsub = new PubSub();

exports.pubsubWriter = functions.https.onRequest(async (req, res) => {
    console.log("Pubsub Emulator:", process.env.PUBSUB_EMULATOR_HOST);

    const msg = await pubsub.topic('test-topic').publishJSON({
        foo: 'bar',
        date: new Date()
    }, { attr1: 'value' });

    res.json({
        published: msg
    })
});

Workaround

The PubSub emulator still not yet support scheduled functions.

But you can use firebase functions:shell and setInterval to simulate scheduler.

NOTE: Please ensure you are running the firebase emulator locally, or the shell may call the functions in Production !!

firebase functions:shell

firebase > setInterval(() => yourScheduledFunc(), 60000)

Don't exit, then it will run your functions every 60 seconds.

NOTE: functions ran in shell will not be shown in emulator's log.


Reruning firebase init didn't work for me because reasons.

I ended up manually modifying the firebase.json file,

Quoting the related docs:

Change emulator ports by running firebase init emulators or by editing firebase.json manually.

// firebase.json
{
  "hosting": {
    // stuff...
  },
  "functions": {
    // stuff...
  },
  "emulators": {
    "functions": {
      "port": 5001
    },
    "hosting": {
      "port": 5000
    },
    "ui": {
      "enabled": true
    },
    "firestore": {
      "port": 8080
    },
    // * * * * * * * * *THIS👇 * * * * * * * * * * * * * * * * * * * * * * * 
    "pubsub": {
      "port": "8085"
    }
    // * * * * * * * * *THIS👆 * * * * * * * * * * * * * * * * * * * * * * * 
  },
  // more stuff...
}