falcon
falcon

Reputation: 13

How to test an async error/exception handler in express with jest

I'm new to development and I'm trying to build my first project with TDD. I got this function (handleAsync) from a tutorial supposed to catch errors in async route handlers. To truly understand how it works, I am trying to come up with some tests.

./utils/handle-async.js

// ./utils/handle-async.js
module.exports = (fn) => (req, res, next) => {
  fn(req, res, next).catch((err) => next(err));
};

./tests/utils/handle-async.test.js

// ./tests/utils/handle-async.test.js
const handleAsync = require('../../utils/handle-async');

describe('catch errors in async functions', () => {
  it('should throw an error if a promise is rejected or an error occurs', (done) => {
    // const fn=async()=>await Promise.resolve(1)
    const fn = async () => Promise.reject(new Error('Rejected!'));

    expect(handleAsync(fn)).toThrowError('Rejected!');

    done();
  });

  it('should not throw and error if a promise is resolved', (done) => {
    // yet to be written, don't know what to do here since first test shows I don't get it yet

  });
});

I get the following error

● catch errors in async functions › should throw an error if a promise is rejected or an error occurs

expect(received).toThrowError(expected)

Expected substring: "Rejected!"

Received function did not throw

  7 |     // console.log(typeof fn);
  8 |     // console.log('rejected prom:', fn);
 *9 |     expect(handleAsync(fn)).toThrowError('Rejected!');
    |                             ^
 10 |     done();
 11 |   });
 12 |

 at Object.<anonymous> (tests/utils/handle-async.test.js:9:29)

I'm probably doing some super dumb things but if anyone could help and/or point me in the right directions, that would be awesome. Don't hesitate to say whatever is wrong/stupid. I'm eager to learn.

Upvotes: 1

Views: 1377

Answers (1)

cbr
cbr

Reputation: 13652

Recall that handleAsync doesn't execute the handler - it only creates the middleware. You're also expecting it to not throw, but rather to pass the error on via the next callback. That's the reason you're using a middleware like this - so you can have async route handlers and have any possible errors be passed automatically to next so that the errors get passed to your error handler.

You can test whether it actually catches a promise rejection from a wrapped route handler. Here's an example, which I haven't had the chance to test:

describe("catch errors in async functions", () => {
  it("should catch rejected promises and pass the error to next", (done) => {
    const rejectError = new Error("Rejected!");
    const fn = async () => Promise.reject(rejectError);

    const middleware = handleAsync(fn);

    const req = {};
    const res = {};
    const next = (err) => {
      expect(err).toBe(rejectError);
      done();
    };

    middleware(req, res, next);
  });
});

There's also a package called express-async-handler which provides the same functionality as your handleAsync. You might be interested in taking a look how it does its tests.

Upvotes: 1

Related Questions