'Manual mock with Jest in Nestjs not working
Having this mock service:
// /catalogue/__mock__/catalogue.service.ts
export const CatalogueService = jest.fn().mockImplementation(() => {
return {
filterRulesFor: jest.fn().mockImplementation((role: Roles): Rule[] => rules.filter(r => r.roles.includes(role))
fetchCountries: jest.fn().mockReturnValue(of(countriesStub())),
}
});
In the next scaffolding:
/catalogue
/__mock__
catalogue.service.ts
/tests
catalogue.controller.spec.ts
catalogue.module.ts
catalogue.controller.ts
catalogue.service.ts
I want to use the mock service inside the catalogue.controller.spec.ts:
// /catalogue/tests/catalogue.controller.spec.ts
import { CatalogueController } from '../catalogue.controller';
import { CatalogueService } from '../catalogue.service';
jest.mock('../catalogue.service'); // <----- manual mocking here
describe('CatalogueController', () => {
let controller: CatalogueController;
let service: CatalogueService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [UtilsModule],
controllers: [CatalogueController],
providers: [CatalogueService],
})
.compile();
controller = module.get<CatalogueController>(CatalogueController);
service = module.get<CatalogueService>(CatalogueService);
jest.clearAllMocks();
});
}
But when I try to use it:
describe('getCountries', () => {
let countries: Country[];
beforeEach(async () => {
service.fetchCountries()
.subscribe(countries => console.log(countries)); // <----- here
countries = await firstValueFrom(controller.getCountries());
});
it('should be called', () => {
expect(service.fetchCountries).toBeCalledTimes(1);
});
it('should not be empty', () => {
expect(countries.length).toBe(countriesStub().length);
});
});
It gives me TypeError: Cannot read property 'subscribe' of undefined as if the mock service does not have the functions defined.
If I write the mock right in the same file it just works but that's not what I want:
let controller: CatalogueController;
let service: CatalogueService;
// vvvvv Mock service here vvvv
const mockCatalogueService = {
filterRulesFor: jest.fn().mockImplementation((role: Roles): Rule[] => rules.filter(r => r.roles.includes(role))),
fetchCountries: jest.fn().mockReturnValue(of(countriesStub())),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [UtilsModule],
controllers: [CatalogueController],
providers: [CatalogueService],
})
.overrideProvider(CatalogueService) // <--- Implementing here
.useValue(mockCatalogueService) // <--- and here
.compile();
controller = module.get<CatalogueController>(CatalogueController);
service = module.get<CatalogueService>(CatalogueService);
jest.clearAllMocks();
});
Solution 1:[1]
Manual mock in jest only mock via import statement. But Nestjs implement DJ, this mean some objects such as service, controller,... get from container that contain all instance object of application. You can try this way
import { CatalogueService } from '../catalogue.service';
jest.mock('../catalogue.service');
//...
const module: TestingModule = await Test.createTestingModule({
imports: [UtilsModule],
controllers: [CatalogueController],
providers: [CatalogueService],
})
.useMocker((token) => {
switch (token) {
case CatalogueService:
return CatalogueService;
// more mock object at here
}
})
.compile();
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Doan Thai |

