SpyOn express route handler function in controller

Viewed 333

So i have a simple express route which I am trying to test using Jest. Below are the code snippets

auth.route.ts

import * as authController from '../controllers/auth.controller';

const router = express.Router();

// POST /api/user/register
router.post(`${userApis.register}`, authController.register);
export { router };

auth.route.test.ts

it('register', async() => {
  const spy = jest.spyOn(authController, "register");
  await request(app).post('/api/user/register');
  expect(spy).toHaveBeenCalled();
});

But the test fails. Below is the error.

expect(jest.fn()).toHaveBeenCalled()

Expected number of calls: >= 1
Received number of calls:    0

One way i got it working is re writing my route as below but that is not the right way i think

import * as authController from '../controllers/auth.controller';

const router = express.Router();

// POST /api/user/register
router.post(`${userApis.register}`, (req, res, next) => {
  authController.register(req, res, next);
});
export { router };

What would be solution for this. I am new to Jest. Thanks in Advance

1 Answers

* import object is read-only by specs and can fail to be spied or mocked depending on a specific setup.

router.post(`${userApis.register}`, authController.register)

line is evaluated on import, jest.spyOn in test scope is evaluated later and cannot affect it.

In case an import should be only spied and not mocked, this can be done for all tests in a module mock:

import * as authController from '../controllers/auth.controller';

jest.mock('../controllers/auth.controller', () => {
  const controller = jest.requireActual('../controllers/auth.controller');
  jest.spyOn(controller, "register");
  return controller
});

That register call is asserted doesn't have a lot of value, asserting a response that is expected from this route handler would be enough. A request most likely causes side effects (database queries), they can be mocked or asserted instead.

Related