Search code examples
node.jsexpressjestjstimeoutsupertest

Async callback was not invoked jest/supertest - simple endpoint


I'm not calling an external API endpoint, I just want to test my own local endpoint with supertest/jest. Setting a timeout obviously won't solve my problem because this is a extremely simple request. I'm calling done on this request so I don't understand what is wrong here.

router.get('/photo', Photo.getFromRequest, function (request, res) {
  // making this simple just for the first step
  return res.status(200).send
})
jest.mock('../models/photo', () => ({
  getFromRequest: jest.fn().mockReturnValueOnce({ id: xxx })
}))

const photo = require('./photo')
const request = require('supertest')
const express = require('express')

const app = express()
app.use('/', photo)
describe('validate photo endpoint', () => {
  it('returns 200 and object photo link/image', function (done) {
    request(app)
      .get('/photo')
      // assert things later
      .end(function (err, res) {
        done(err)
      })
  })
})
   : Timeout - Async callback was not invoked within the 30000 ms timeout specified by jest.setTimeout.Timeout - Async callback was not invoked within the 30000 ms timeout specified by jest.setTimeout.Error:

Solution

  • Usually the express Router-level middleware are called with (req, res, next), they do something (for example applying properties to the request or the response) and call the callback and don't return anything.

    So you should probably mock it to actually call the next callback like this:

    jest.mock('../models/photo', () => ({
      getFromRequest: jest.fn().mockImplementation((req, res, next) => {
        req.photo = { id: xxx };
        next();
      })
    }))
    

    Edit: to check if the middleware have been called you can also import it in the test

    import { getFromRequest } from '../models/photo'
    
    // ...your mock and other tests here
    // and after you've executed the request you may assert
    expect(getFromRequest).toHaveBeenCalled()