I have started to work with NestJS and have a question about mocking guards
for unit-test.
I'm trying to test a basic HTTP controller
that has a method Guard attach to it.
My issue started when I injected a service to the Guard (I needed the ConfigService
for the Guard).
When running the test the DI is unable to resolve the Guard
● AppController › root › should return "Hello World!"
Nest can't resolve dependencies of the ForceFailGuard (?). Please make sure that the argument at index [0] is available in the _RootTestModule context.
My force fail Guard:
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { ConfigService } from './config.service';
@Injectable()
export class ForceFailGuard implements CanActivate {
constructor(
private configService: ConfigService,
) {}
canActivate(context: ExecutionContext) {
return !this.configService.get().shouldFail;
}
}
Spec file:
import { CanActivate } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ForceFailGuard } from './force-fail.guard';
describe('AppController', () => {
let appController: AppController;
beforeEach(async () => {
const mock_ForceFailGuard = { CanActivate: jest.fn(() => true) };
const app: TestingModule = await Test
.createTestingModule({
controllers: [AppController],
providers: [
AppService,
ForceFailGuard,
],
})
.overrideProvider(ForceFailGuard).useValue(mock_ForceFailGuard)
.overrideGuard(ForceFailGuard).useValue(mock_ForceFailGuard)
.compile();
appController = app.get<AppController>(AppController);
});
describe('root', () => {
it('should return "Hello World!"', () => {
expect(appController.getHello()).toBe('Hello World!');
});
});
});
I wasn't able to find examples or documentation on this issues. Am i missing something or is this a real issue ?
Appreciate any help, Thanks.
Testing NestJS with unit tests The job of a unit test is to verify an individual piece of code. A tested unit can be a module, a class, or a function. Each of our tests should be isolated and independent of each other.
If you would like to get to know Jest better first, check out the first part of the JavaScript testing tutorial. The job of a unit test is to verify an individual piece of code. A tested unit can be a module, a class, or a function.
To write isolated unit tests, it’s common to mock all dependencies of a method/service. In the StudentService unit test, we’ll mock AppService by creating an ApiServiceMock class. Test Doubles: Fakes, stubs, and mocks all belong to the category of test doubles. A test double is an object or system you use in a test instead of something else.
Introduction. Nest (NestJS) is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with and fully supports TypeScript (yet still enables developers to code in pure JavaScript) and combines elements of OOP (Object Oriented Programming), FP (Functional Programming),...
There are 3 issues with the example repo provided:
There is a bug in Nestjs v6.1.1 with .overrideGuard()
- see https://github.com/nestjs/nest/issues/2070
I have confirmed that its fixed in 6.5.0.
ForceFailGuard
is in providers
, but its dependency (ConfigService
) is not available in the created TestingModule
.
If you want to mock ForceFailGuard
, simply remove it from providers
and let .overrideGuard()
do its job.
mock_ForceFailGuard
had CanActivate
as a property instead of canActivate
.
Working example (nestjs v6.5.0):
import { CanActivate } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ForceFailGuard } from './force-fail.guard';
describe('AppController', () => {
let appController: AppController;
beforeEach(async () => {
const mock_ForceFailGuard: CanActivate = { canActivate: jest.fn(() => true) };
const app: TestingModule = await Test
.createTestingModule({
controllers: [AppController],
providers: [
AppService,
],
})
.overrideGuard(ForceFailGuard).useValue(mock_ForceFailGuard)
.compile();
appController = app.get<AppController>(AppController);
});
describe('root', () => {
it('should return "Hello World!"', () => {
expect(appController.getHello()).toBe('Hello World!');
});
});
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With