Firebase-functions: Testing async firebase functions.https.onRequest does not await

Created on 13 Jan 2020  路  4Comments  路  Source: firebase/firebase-functions

[REQUIRED] Describe your environment

  • Operating System version: Ubuntu 19.10
  • Browser version: node v8.16.0
  • Jest version: 24.9.0
  • Firebase version: 7.6.1
  • Firebase-Functions version: 3.3.0

[REQUIRED] Describe the problem

Steps to reproduce:


Write an async functions.https.onRequest cloud function
Import the function into a test file
Call the function with await

Relevant Code:

// funcs.js
import * as functions from 'firebase-functions';
import * as firebase from '@firebase/testing';

const admin = firebase.initializeAdminApp({ projectId: 'foo' });
const firestore = admin.firestore();

export const direct = async (req, res) => {
    console.log('inside direct, before await');
    await new Promise(resolve => {
        setTimeout(() => {
            resolve();
        }, 3000);
    });
    console.log('inside direct, after await');

    return res.status(200).send('ok');
};

export const request = functions.https.onRequest(async (req, res) => {
    console.log('inside request, before await');
    await new Promise(resolve => {
        setTimeout(() => {
            resolve();
        }, 3000);
    });
    console.log('inside request, after await');

    return res.status(200).send('ok');
});
// funcs.test.js
import * as funcs from '../funcs';

describe('simple async functions test', () => {
    it('calling directly', async () => {
        const req = {};
        const res = {};
        res.status = jest.fn().mockReturnValue(res);
        res.send = jest.fn().mockReturnValue(res);

        await funcs.direct(req, res);

        expect(res.status).toHaveBeenCalledWith(200);
        expect(res.send).toHaveBeenCalledWith('ok');
    });

    it('calling from https.onRequest', async () => {
        const req = {};
        const res = {};
        res.status = jest.fn().mockReturnValue(res);
        res.send = jest.fn().mockReturnValue(res);

        await funcs.request(req, res);

        expect(res.status).toHaveBeenCalledWith(200);
        expect(res.send).toHaveBeenCalledWith('ok');
    });
});

The first test passes as expected. The 2nd one does not.

I am using jest but should replicate with other test runners
This is a simplified version of my code, my function needs to await some upstream data which is what the setTimeout is faking.
The workaround I have at the moment is to create the function and reference it in the onRequest
I've found that the function is wrapped here:
https://github.com/firebase/firebase-functions/blob/master/src/providers/https.ts#L63
The issue is that this function wrapper is not an async/await.
I have fixed this locally by simply putting await on L63 and async on the wrapping function.
I am not sure if this would affect or impact anything else and I'd rather have you guys look into itas there may be a good reason this is not async/awaited

http

Most helpful comment

It's been released in v3.6.0. Thanks for the contribution @sk- !

All 4 comments

Are there any updates from anybody working on this? Is it being looked into?

I stumbled across this very same issue, and the fix is rather straightforward. The wrapper just needs to return the result of the wrapped function. Specifically on this line https://github.com/firebase/firebase-functions/blob/3491a6d4e57432b5747acddd47e1a6a1109f2b20/src/providers/https.ts#L63.

As a workaround while the patch is accepted, you can do the following before importing your function

const functions = require('firebase-functions');
functions.https.onRequest = (handler) => handler;

Disclaimer: haven't checked whether that affects types.

It's been released in v3.6.0. Thanks for the contribution @sk- !

Was this page helpful?
0 / 5 - 0 ratings