Search code examples
testingjestjsnestjs

Nest.js and Jest testing framework: Can't resolve dependencies of the AuthGuard in the RootTestModule context


I am using Jest framework for testing my Nest.js application. Here is the recovery.controller.spec.ts file:

import { Test, TestingModule } from '@nestjs/testing';
import { RecoveryController } from './recovery.controller';

describe('RecoveryController', () => {
  let controller: RecoveryController;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      controllers: [RecoveryController]
    }).compile();

    controller = module.get<RecoveryController>(RecoveryController);
  });

  it('should be defined', () => {
    expect(controller).toBeDefined();
  });
});

Right now, when I am executing this test, I am getting the following error message:

Error: Nest can't resolve dependencies of the AuthGuard (?). Please make sure that the argument JwtService at index [0] is available in the RootTestModule context.

And honestly, I just cannot fix it. Application works perfectly fine and I have no error with both controller and service. I have been trying to add RecoveryService to both provides and imports of this module, but it did not help. Also, when I add RecoveryService to the list of provides, the error message changes to the following:

Error: Nest can't resolve dependencies of the RecoveryService (?, CryptographicService, UsersService). Please make sure that the argument ConfirmationHashService at index [0] is available in the RootTestModule context.

Could anyone please explain me where is the error? Below I am going to provide the source code of the related modules and services if this might be helpful:

recovery.module.ts

@Module({
  controllers: [RecoveryController],
  providers: [RecoveryService],
  imports: [
    JwtModule.registerAsync({
      useFactory: async (configService: ApiConfigService) => ({
        secret: configService.jwtAuthConfig.secret
      }),
      inject: [ApiConfigService]
    }),
    ConfirmationHashModule,
    UsersModule
  ]
})
export class RecoveryModule {}

Constructor of the recovery.service.ts:

constructor(
  private readonly confirmationHashService: ConfirmationHashService,
  private readonly cryptographicService: CryptographicService,
  private readonly usersService: UsersService
) {}

auth.module.ts

@Module({
  controllers: [AuthController],
  providers: [AuthService],
  imports: [
    forwardRef(() => UsersModule),
    forwardRef(() => RolesModule),
    SequelizeModule.forFeature([Session, UserSettings]),
    JwtModule.registerAsync({
      useFactory: async (configService: ApiConfigService) => ({
        secret: configService.jwtAuthConfig.secret
      }),
      inject: [ApiConfigService]
    })
  ],
  exports: [AuthService, JwtModule]
})
export class AuthModule {}

Constructor of the auth.service.ts:

constructor(
  private readonly cryptographicService: CryptographicService,
  private readonly jwtService: JwtService,
  private readonly configService: ApiConfigService,
  private readonly phoneService: PhoneService,
  private readonly timeService: TimeService,
  @Inject(forwardRef(() => RolesService))
  private readonly rolesService: RolesService,
  @Inject(forwardRef(() => EmailService))
  private readonly emailService: EmailService,
  @Inject(forwardRef(() => UsersService))
  private readonly usersService: UsersService,
  @InjectModel(Session) private readonly sessionRepository: typeof Session
) {}

Thanks everyone for the help in advance!


Solution

  • Here you have to mock AuthGuard and RecoveryService

     const module: TestingModule = await Test.createTestingModule({
          controllers: [RecoveryController],
          providers: [RecoveryService],
        })
          .overrideProvider(RecoveryService)
          .useValue(mockRecoveryService)
          .overrideGuard(AuthGuard)
          .useValue({ canActivate: jest.fn(() => true) })
          .compile();
    
    export const mockRecoveryService= {
      recoveryServiceMethod: jest.fn().mockImplementation(() => {
        return ;
      }),
    }