0

I'm currently trying to unit test my HTTPS functions. I would like to test my error responses so I voluntarily cause an exception in my https function. I catch an error displayed in the console.debug(e) but the res.status().json() that I provide in my unit tests is never called, and so the done() function is never called neither.

However, it seems that when the onCreateUserAndAgency() is successful, the res.json() that I provide is called, and the test is successful.

Is there a step when the Response object is replaced in case of an exception ? Am I doing something wrong ?

The stack I use is Firebase Functions with Typescript and Mocha for unit testing.

export default functions.https.onRequest((req, res) => {
    /* here, when I put res.status(200).json({}), the test's successful so it means done() is called */
    onCreateUserAndAgency({
        body: req.body,
    }).then(r => {
        res.json(r);
    }).catch(e => {
        console.debug(e);
        res.status(e.error.status).json(e);
    })
});
describe('User', async function() {
  describe('#createUser()', async function() {
    it('should return error 500 for unknown errors', async function(done) {
      const req: any = { };
      const res: any = {
        status: (status: number) => {
          assert.equal(status, 500);
          console.log("TEST");
          done();
        },
        json: (data: any) => {
          console.log("TEST");
          done();
        } 
      };
      fcts.createUserViaEmail(req, res);
    });
  });
});

The error log :

> test
> mocha --require ts-node/register test/**/*.spec.ts

{"severity":"WARNING","message":"Warning, estimating Firebase Config based on GCLOUD_PROJECT. Initializing firebase-admin may fail"}


  User
    #createUser()
TypeError: Cannot read properties of undefined (reading 'user')
    at onCreateUserAndAgency (C:\Users\Orionss\Projets\PATH\functions\src\users\on-create.ts:20:70)
... Many less specific error lines
{
  error: {
    status: 500,
    message: "Une erreur inattendue s'est produite.",
    date: 2021-12-21T14:04:42.842Z
  }
}
      1) should return error 500 for unknown errors


  0 passing (2s)
  1 failing

  1) User
       #createUser()
         should return error 400 for missing info:
     Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (C:\Users\Orionss\Projets\PATH\functions\test\main.spec.ts)
      at listOnTimeout (node:internal/timers:557:17)
      at processTimers (node:internal/timers:500:7)
Orionss
  • 725
  • 2
  • 10
  • 26
  • 1
    You might also have a look at this SO [thread](https://stackoverflow.com/questions/43813013/test-will-not-call-done-when-failing) – Sergi Dec 24 '21 at 11:48

1 Answers1

1

I found where the error was

The code of the express res.status method (https://github.com/expressjs/express/blob/master/lib/response.js) is :

res.status = function status(code) {
  this.statusCode = code;
  return this;
};

However, when my createUserViaEmail() function fails, I use res.status().send() which means that the first res.status() returns this.

It seems that in Javascript, returning this restore the previous send function, so done() was never called.

My unit test works when in my exception catcher, I do :

res.statusCode = e.error.status;
res.send(e);

Which is not very clean, I'm looking for a cleaner workaround.

Orionss
  • 725
  • 2
  • 10
  • 26