mfrachet
mfrachet

Reputation: 8932

Chai spies and async calls not call once

I m building an application in which I need to test some callback behaviours inside of an express callback resolution.

Actually, it looks like :

const callbackRender = (httpResponse, response) => {
  console.log(httpResponse) // logs the good httpResponse object
  if (httpResponse.content.content) response.send(httpResponse.content.content)
  else response.render(httpResponse.content.page)
}

const callback = (injector, route) => {
  return (request, response) => {
    const ctrl = injector.get(route.controller)
    const result = ctrl[route.controllerMethod](new HttpRequest())
    if (result.then) {
      return result.then(res => callbackRender(res, response))
    } else {
      callbackRender(result, response)
    }
  }
}

The two failing tests look like :

it('should call the callback render method when httpResponse is a promise', (done) => {
      const mock = sinon.mock(injector)
      const ctrl = new UserControllerMock()
      const routes = routeParser.parseRoutes()
      mock.expects('get').returns(ctrl)
      const spy = chai.spy.on(callbackRender)
      callback(injector, routes[3])(request, response).then((res) => {
        expect(spy).to.have.been.called.once
        mock.verify()
        mock.restore()
        done()
      })
    })

    it('should call the callback render method when httpResponse is not a promise', () => {
      const mock = sinon.mock(injector)
      const ctrl = new UserControllerMock()
      const routes = routeParser.parseRoutes()
      mock.expects('get').returns(ctrl)
      const spy = chai.spy.on(callbackRender)
      callback(injector, routes[1])(request, response)
      expect(spy).to.have.been.called.once
      mock.verify()
      mock.restore()
    })

It seems that chai-spies isn't able to detect that my callbackRender function is called in the callback method.

The fact is that, when I log my method, I pass inside of it each time I need it to do.

Does anybody has an idea ?

EDIT : The request / response definition in beforeEach

 beforeEach(() => {
    request = {
      body: {},
      params: {},
      query: {}
    }
    response = {
      send: () => {
      },
      render: () => {
      }
    }});

Upvotes: 0

Views: 938

Answers (1)

robertklep
robertklep

Reputation: 203514

Spies/stubs/mocks can only work if they can replace the original function (with a wrapped version), or if they get passed explicitly (which isn't the case in your code).

In your case, callbackRender isn't replaced (it can't be, due to the const but also because it has no "parent" object in which it can be replaced), so any code that will call it (like callback) will call the original function, not the spy.

A solution depends on how exactly your code is structured.

If callback and callbackRender are located in a separate module together, you might be able to use rewire to "replace" callbackRender with a spy.

However, one caveat is that rewire also can't replace const variables, so your code would have to change.

Upvotes: 1

Related Questions