Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error trying to instantiate controller in a test (Error: No matching bindings found for serviceIdentifier: Symbol(HttpContext)) #360

Open
marcosdipaoloSV opened this issue Feb 25, 2021 · 1 comment

Comments

@marcosdipaoloSV
Copy link

I'm trying to write a unit test for a controller that has an injected service at the constructor, that's why (unlike the docs where controllers are instantiated with the new keyword in a test) i need to instantiate it with the container.
The controller extends the BaseHttpController from inversify-express-utils I'm failing trying to do:

Test

import { expect } from "chai"
import { container } from '../../src/container/inversify.config'
import { HealthControllerV1 } from "../../src/controllers/v1/HealthControllerV1"
import { results } from "inversify-express-utils"

describe("ExampleController", () => {
    let controller: HealthControllerV1

    beforeEach(() => {
        controller = container.get<HealthControllerV1>(HealthControllerV1)
    })

    describe("Health", () => {
        it("should return 200 status with Json response", async () => {
            const response = controller.health()
            expect(response).to.be.an.instanceof(results.JsonResult)
        })
    })
})  

Container:

import { Container } from "inversify";
import { HealthControllerV1 } from "../controllers/v1/HealthControllerV1";
import { GoalsService, IGoalsService } from "../services/GoalsService";

const container = new Container()

container.bind<HealthControllerV1>(HealthControllerV1).toSelf()
container.bind<IGoalsService>('goalsService').to(GoalsService)

export { container }

Controller:

import 'reflect-metadata'
import { BaseHttpController, controller, httpGet, interfaces, results } from 'inversify-express-utils'
import { inject } from 'inversify'
import { IGoalsService } from '../../services/GoalsService'

@controller('/v1/health')
export class HealthControllerV1 extends BaseHttpController implements interfaces.Controller {

    constructor(@inject('goalsService') private goalsService: IGoalsService){super()}
    
    @httpGet('/')
    health(): results.JsonResult {
        this.goalsService.log('111')
        return this.json({ msg: 'OK' })
    }
}   

Error:

HealthControllerV1
    Health
      1) "before each" hook for "should return 200 status with Json response"


  0 passing (8ms)
  1 failing

  1) HealthControllerV1
       "before each" hook for "should return 200 status with Json response":
     Error: No matching bindings found for serviceIdentifier: Symbol(HttpContext)

My Environment

"inversify": "^5.0.5",
"inversify-express-utils": "^6.3.2",
"node": "12.20.0"
"chai": "^4.3.0",
"express": "^4.17.1",
"mocha": "^8.3.0",
"reflect-metadata": "^0.1.13",

Stack trace

 Error: No matching bindings found for serviceIdentifier: Symbol(HttpContext)
      at _validateActiveBindingCount (node_modules/inversify/lib/planning/planner.js:63:23)
      at _getActiveBindings (node_modules/inversify/lib/planning/planner.js:49:5)
      at _createSubRequests (node_modules/inversify/lib/planning/planner.js:92:26)
      at /home/marcosdipaolo/Documents/dev/goals-backend/node_modules/inversify/lib/planning/planner.js:116:17
      at Array.forEach (<anonymous>)
      at /home/marcosdipaolo/Documents/dev/goals-backend/node_modules/inversify/lib/planning/planner.js:115:26
      at Array.forEach (<anonymous>)
      at _createSubRequests (node_modules/inversify/lib/planning/planner.js:95:20)
      at Object.plan (node_modules/inversify/lib/planning/planner.js:137:9)
      at /home/marcosdipaolo/Documents/dev/goals-backend/node_modules/inversify/lib/container/container.js:319:37
      at Container._get (node_modules/inversify/lib/container/container.js:312:44)
      at Container.get (node_modules/inversify/lib/container/container.js:232:21)
      at Context.<anonymous> (test/unit/health.test.ts:10:32)
      at processImmediate (internal/timers.js:461:21)

thanks a lot

@marcosdipaoloSV marcosdipaoloSV changed the title Error trying to instantiate controller in a test (extending BaseHttpController, using inversify-express-utils) Error trying to instantiate controller in a test (Error: No matching bindings found for serviceIdentifier: Symbol(HttpContext)) Feb 25, 2021
@marcosdipaoloSV
Copy link
Author

For some reason i neither know nor understand, in a test you need to mock the httpContext (the one you get from BaseHttpController) and bind it to the container before you try to instantiate the controller

The mocked httpContext

import { mockReq, mockRes } from 'sinon-express-mock'
import { interfaces } from "inversify-express-utils"
import { container } from '../src/container/inversify.config'

const mockRequest = mockReq()
const mockResponse = mockRes()

const mockUser: interfaces.Principal = {
    details: "",
    isAuthenticated: () => Promise.resolve(true),
    isResourceOwner: () => Promise.resolve(true),
    isInRole: () => Promise.resolve(true)
}

export const mockedHttpContext: interfaces.HttpContext = {
    request: mockRequest,
    response: mockResponse,
    user: mockUser,
    container
}

The test

import { expect } from "chai"
import { container } from '../../src/container/inversify.config'
import { HealthControllerV1 } from "../../src/controllers/v1/HealthControllerV1"
import { results, interfaces } from "inversify-express-utils"
import { mockedHttpContext } from '../mockedHttpContext'

describe("HealthControllerV1", () => {
    let controller: HealthControllerV1
    
    container.bind<interfaces.HttpContext>(Symbol.for("HttpContext")).toConstantValue(mockedHttpContext)
    
    beforeEach(() => {
        controller = container.get<HealthControllerV1>(HealthControllerV1)
    })

    describe("Health", () => {
        it("should return 200 status with Json response", async () => {
            const response = controller.health()
            expect(response).to.be.an.instanceof(results.JsonResult)
        })
    })
})      

@PodaruDragos PodaruDragos transferred this issue from inversify/InversifyJS Jan 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant