I am new to Typescript and currently do not understand how to mock a Kafka Client in a NestJS Application.
What I want to achieve
I have a NestJS Application which has the following controller:
consumer.controller.ts
import { Controller} from '@nestjs/common';
import { EventPattern, Payload } from '@nestjs/microservices';
import { ConsumerService } from './consumer.service';
@Controller()
export class ConsumerController {
constructor(private readonly consumerService: ConsumerService) {}
/**
* Handles events from the 'Topic-1' topic.
* @param context - The Kafka context containing the message and metadata.
*/
@EventPattern('Topic-1')
async dosomething(@Payload() message: any) {
// do something
}
}
consumer.service.ts
import { Injectable, OnModuleDestroy, OnModuleInit, Inject } from '@nestjs/common';
import { Client, ClientKafka } from '@nestjs/microservices';
@Injectable()
export class ConsumerService implements OnModuleInit, OnModuleDestroy {
constructor() {}
@Client(microserviceConfig)
private readonly client: ClientKafka;
/**
* Lifecycle hook that is called when the module is destroyed.
* Closes the Kafka client connection.
*/
async onModuleDestroy() {
await this.client.close();
}
async onModuleInit() {
const requestPatterns = [
'Topic-1',
'Topic-2',
];
requestPatterns.forEach((pattern) => {
this.client.subscribeToResponseOf(pattern);
});
await this.client.connect();
}
}
I skipped the microserviceconfig
for the real KafkaClient because I want to Use my Kafka Mock for Unit testing.
This is the module
consumer.module.ts
import { Module } from '@nestjs/common';
import { ConsumerController } from './consumer.controller';
import { ConsumerService } from './consumer.service';
@Module({
controllers: [ConsumerController],
providers: [ConsumerService],
})
export class ConsumerModule {}
And this is My Unit-Test for the Service:
import { Test, TestingModule } from '@nestjs/testing';
import { ConsumerService } from "./consumer.service";
import { ClientKafka } from '@nestjs/microservices';
describe('ConsumerService', () => {
let emailService: ConsumerService;
let kafka: ClientKafka;
let emailNotificationService: EmailNotificationService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
ConsumerService,
{
provide: ClientKafka,
useValue: {
subscribeToResponseOf: jest.fn(),
connect: jest.fn().mockResolvedValue(undefined),
emit: jest.fn(),
}
}
],
}).compile();
emailService = module.get(ConsumerService);
kafka = module.get(ClientKafka);
});
it('Subscribe to right topics', async() => {
await emailService.onModuleInit();
expect(kafka.subscribeToResponseOf).toHaveBeenCalledWith('Topic-1');
expect(kafka.subscribeToResponseOf).toHaveBeenCalledWith('Topic-2');
})
});
But when I run the tests I get an error when trying to call this.client
which indicates client is null.
I guess that is because Dependency Injection of my Kafka Mock is not working. Do I need to add the ClientKafka to the constructor? I tried doing that, but then building the consumer.module.ts failed.
How to do this?