How to stub external services in Firebase emulator?

Viewed 219

I have one firestore trigger function that is creating DNS record based on the slug attribute. I have some unit tests where I am stubbing @google-cloud/dns module so no external HTTP request is made. However, I have several integration tests as well. Those are hitting local firebase emulator (localhost:8080).

For instance, whilst testing firestore rules, I am simply calling db.collection('path').add(model) and that is triggering callable function inside emulator process.

Tests are running by this command: firebase emulators:exec 'mocha --config spec/.mocharc.yml At first, it is initializing emulators and then running tests. As far as I understood these are different processes. So inside the mocha process, I am able to stub, mock with modules. On the other hand, inside the emulator process, functions, modules, dependencies are already loaded as it is. So when I am running this test script for testing firestore rules inside mocha test suite:

await assertSucceeds(db.doc('stores').set(store));

It actually runs the handler and sends the request to the google cloud DNS. Did anyone face issues something like this? Thanks in advance.

1 Answers

I'm facing the same situation. My plan is to make the Cloud Function initialize itself with a stubbed service that will record its own calls to a log collection in Firestore when NODE_ENV=test. Then the test will check whether the call was recorded by querying that collection.

test('fanOutCategoryFields', async () => {
  // Initialize Firebase and seed test data
  const app = await setup({
    'categories/1': {
      name: 'Some Name',
    },
    'posts/1': {
      categoryId: '1',
    },
  })

  // Update a document (will trigger the Cloud Function)
  await app
    .firestore()
    .collection('categories')
    .doc('1')
    .update({ name: 'New Name' })

  // Wait for the Cloud Function to run
  await new Promise(resolve => setTimeout(resolve, 3000))

  // Query the collection where function calls are recorded
  const calls = await app
    .firestore()
    .collection('_calls')
    .get()
    .then(snap => snap.docs.map(snap => snap.data()))

  // Check if Algolia was called with the expected arguments
  expect(calls).toEqual([
    {
      fn: 'algolia.update',
      args: ['products', '1', { categoryName: 'New Name' }],
    },
  ])
})
Related