Search code examples
jestjsrabbitmqnestjs

Mocking @golevelup/nestjs-rabbitmq conditionally in Jest tests


Am trying to write a jest test for my application.My application using @golevelup/nestjs-rabbitmq for establishing the connection.As part of test suite, i have created the RabbitMQWrapperModule conditionally. Here is the RabbitMQWrapperModule

import { Module, DynamicModule } from '@nestjs/common'
import {
  RabbitMQModule,
  RabbitMQConfig,
  MessageHandlerErrorBehavior
} from '@golevelup/nestjs-rabbitmq'
import { ConfigModule, ConfigService } from '@nestjs/config'

@Module({})
export class RabbitMQWrapperModule {
  static register(): DynamicModule {
      return {
          module: RabbitMQWrapperModule,
          imports: [
              RabbitMQModule.forRootAsync(RabbitMQModule, {
                  imports: [ConfigModule],
                  useFactory: async (configService: ConfigService) => {
                      const env = configService.get('NODE_ENV')
                      if (env === 'test') {
                          return {} as RabbitMQConfig
                      } else {
                          return {
                              uri: `${configService.get(
                                  'messageBus.connection.protocol'
                              )}://${configService.get(
                                  'messageBus.connection.username'
                              )}:${configService.get(
                                  'messageBus.connection.password'
                              )}@${configService.get(
                                  'messageBus.connection.hostname'
                              )}:${configService.get('messageBus.connection.port')}`,
                              connectionManagerOptions: {
                                  heartbeatIntervalInSeconds: configService.get(
                                      'messageBus.connection.heartbeatInterval'
                                  )
                              },
                              channels: {
                                  'channel-1': {
                                      prefetchCount: 1,
                                      default: true
                                  }
                              },
                              defaultSubscribeErrorBehavior: MessageHandlerErrorBehavior.ACK
                          }
                      }
                  },
                  inject: [ConfigService]
              })
          ],
          exports: [RabbitMQModule]
      }
  }
}

I have created a test-setup.ts file

jest.mock( '/repository' ) export const createTestModule = async (): Promise => { const repositoryMock = Repository as unknown as jest.Mock

  const module: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
      controllers: [Controller],
      providers: [
          <service1>,
          <service2>,
          {
              provide: JwtService,
              useValue: mockJwtService
          }
      ]
  })
      .overrideProvider(RabbitMQModule)
      .useValue(MockedRabbitMqConnectionModule)
      .overrideProvider(JwtService)
      .useValue({
          decode: () => Promise.resolve(fakeUser)
      })
      .compile()
  config().jwt.skipVerify = true

  return module
}

This is my spec file

let app let module: TestingModule

    beforeAll(async () => {
        jest.clearAllMocks()
        module = await createTestModule()
        app = module.createNestApplication()
        config().jwt.skipVerify = true
        await app.init()
    })

    afterAll(async () => {
        jest.clearAllMocks()
        await app.close()
    })

    it('should call generateIdListService.get with queryParams', (done) => {
        const requestBodyMock: QueryParam = {
            requestId: '111'
        }


        request(app.getHttpServer())
            .get('<url>')
            .send(requestBodyMock)
            .then((response) => {
                expect(response.status).toBe(200)
            
                done()
            })
    })

    
    })
})

Conditionally import the RabbitMQModule based on the environment. In the RabbitMQWrapperModule, i have added a conditional check to return an empty object ({}) as the RabbitMQ configuration when the environment is set to 'test'.if the value is empty object {} which means rabitmq not initialized and not established the connection.But in this case its trying to connect and getting this error

ERROR [AmqpConnection] Disconnected from RabbitMQ broker (default)
TypeError: Cannot read properties of undefined (reading 'heartbeat')
    at /Users/ac/workspace/project/node_modules/amqp-connection-manager/dist/cjs/AmqpConnectionManager.js:231:42

Has anyone successfully mocked RabbitMQ? Please assist if possible.


Solution

  • After some research, I identified the issue. My project had two modules used for RabbitMQ connection. I combined these two RabbitMQ modules into a single one. Now, the mocking is working as expected.