#How to mock the redis in integration test cases

7 messages · Page 1 of 1 (latest)

shut spear
#

Here is code:

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { UsersModule } from 'src/modules/user/user.module';
import { JwtModule } from '@nestjs/jwt';
import { ConfigService } from 'src/modules/config/config.service';
import { LocalStrategy } from './strategies/local.strategy';
import { JwtStrategy } from './strategies/jwt.strategy';
import { GoogleStrategy } from './strategies/google-strategy';
import { EmailNotificationModule } from 'src/modules/email-notification/email-notification.module';

@Module({
  exports: [AuthService],
  controllers: [AuthController],
  providers: [GoogleStrategy, AuthService, LocalStrategy, JwtStrategy],
  imports: [
    JwtModule.registerAsync({
      inject: [ConfigService],
      useFactory: (configService: ConfigService) => ({
        secret: configService.get('JWT_SECRET'),
        signOptions: {
          expiresIn: configService.getJwtExpiryString(),
        },
      }),
      global: true,
    }),
    UsersModule,
    EmailNotificationModule,
  ],
})
export class AuthModule {}


#
// Other imports
import * as redisMock from 'redis-mock';
class MockedUserModel {
  constructor(private _: any) {}
}
describe('AuthController (e2e)', () => {
  let app: INestApplication;
  let userService: UserService;

  const mockUserService = {
    findOneByOtp: jest.fn(),
    saveTfaSecret: jest.fn().mockResolvedValue(undefined),
    findUserByTfaRecoveryToken: jest.fn().mockResolvedValue(undefined),
    update: jest.fn().mockResolvedValue(undefined),
    findOneByEmail: jest.fn().mockResolvedValue(undefined),
    create: jest.fn().mockResolvedValue(undefined),
  };
  const mockEmailNotificationService = {
    sendActivationEmail: jest.fn().mockResolvedValue(undefined),
  };

  beforeAll(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AuthModule, UsersModule, ConfigModule, EmailNotificationModule],
    })
      .overrideProvider(RedisIoAdapter)
      .useValue({
        getPubClient: () => redisMock.createClient(), // Use redis-mock for pub/sub client
        getSubClient: () => redisMock.createClient(), // Use redis-mock for sub client
        connectToRedis: jest.fn().mockResolvedValue(undefined),
      })
      .overrideProvider(UserService)
      .useValue(mockUserService)
      .overrideProvider(getModelToken(User.name))
      .useValue(MockedUserModel)
      .overrideProvider(EmailNotificationService)
      .useValue(mockEmailNotificationService)
      .compile();

    app = moduleFixture.createNestApplication();
    await app.init();

    userService = moduleFixture.get<UserService>(UserService);
  });

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

 
});```
#

Test Case:

describe('/auth/activate-account (POST)', () => {
    it('should activate the account successfully', async () => {
      const user = {
        active: false,
        save: jest.fn().mockResolvedValue(undefined),
      };
      jest
        .spyOn(userService, 'findOneByOtp')
        .mockResolvedValueOnce(user as any);

      const response = await request(app.getHttpServer())
        .get('/auth/activate/976769')
        .send()
        .expect(200);

      expect(response.body).toEqual({ message: MESSAGES.ACCOUNT_ACTIVATED });
      expect(user.active).toBe(true);
    });
  });
#

Controller:

  @Get('/activate/:token')
  @ApiOkResponse({
    description: 'Success',
    example: {
      message: MESSAGES.ACCOUNT_ACTIVATED,
    },
  })
  @ApiBadRequestResponse({ example: { message: MESSAGES.INVALID_OTP_TOKEN } })
  activateAccount(@Param('token') token: string) {
    return this.authService.activateAccount(token);
  }
#

Auth Service code:

async activateAccount(token: string) {
    console.log('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%');
    console.log(token);
    const hashedToken = await createHashVerifier(token);
    const user = await this.userService.findOneByOtp(hashedToken);
    user.active = true;
    await user.save();
    //TODO send an email to the user that the account is activated successfully
    return { message: MESSAGES.ACCOUNT_ACTIVATED };
  }
#

I am using the BullMQ and redis in my project. When i try to run the test cases i am getting the connection error b/c Redis is not running (i don't want to run the redis instead i want to mock it )

#

Redis adapter:

// imports here 

@Injectable()
export class RedisIoAdapter
  extends IoAdapter
  implements OnModuleInit, OnModuleDestroy
{
  private adapterConstructor: ReturnType<typeof createAdapter> | undefined;
  private pubClient: RedisClientType | undefined;
  private subClient: RedisClientType | undefined;

  async onModuleInit(): Promise<void> {
    await this.connectToRedis();
  }

  async onModuleDestroy(): Promise<void> {
    await this.disconnectFromRedis();
  }

  async connectToRedis(): Promise<void> {
    try {
      this.pubClient = createClient({ url: 'redis://redis:6379' });
      this.subClient = this.pubClient.duplicate();

      await Promise.all([this.pubClient.connect(), this.subClient.connect()]);
  

      this.adapterConstructor = createAdapter(this.pubClient, this.subClient);
    } catch (error) {
      console.error('Error connecting to Redis:', error);
      throw error;
    }
  }

  private async disconnectFromRedis(): Promise<void> {
    try {
      if (this.pubClient) await this.pubClient.quit();
      if (this.subClient) await this.subClient.quit();
    } catch (error) {
      console.error('Error disconnecting from Redis:', error);
    }
  }

  createIOServer(port: number, options?: ServerOptions): any {
    if (!this.adapterConstructor) {
      throw new Error(
        'Redis adapter is not initialized. Call connectToRedis() before creating the server.',
      );
    }

    const server = super.createIOServer(port, options);
    server.adapter(this.adapterConstructor);
    return server;
  }

  getPubClient(): RedisClientType {
    if (!this.pubClient) {
      throw new Error('PubClient is not initialized');
    }
    return this.pubClient;
  }
  getSubClient(): RedisClientType {
    if (!this.subClient) {
      throw new Error('SubClient is not initialized');
    }return this.subClient;
  }
  async getAllConnectedClients(): Promise<string[]> {
    return await this.getPubClient().sMembers('connected_clients');
  }
}