I'm attempting to write a unit test for a @nestjs service and need to mock the HttpService. My unit test implementation is returning with the following error:
TypeError: Cannot read properties of undefined (reading 'get')
Within the context of the unit test, httpService is never being defined despite the @Injectable decorator being used within the air-gateway.service module.
air-gateway.service.spec.ts
import { AirGatewayService } from './air-gateway.service';
import { HttpService } from '@nestjs/axios';
import { createMock, DeepMocked } from '@golevelup/ts-jest';
import { Test, TestingModule } from '@nestjs/testing';
describe('AirGateway Service', () => {
let service: AirGatewayService;
let httpService: DeepMocked<HttpService>;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
AirGatewayService,
{
provide: HttpService,
useValue: createMock<HttpService>(),
},
],
})
.useMocker(createMock)
.compile();
service = await module.get<AirGatewayService>(AirGatewayService);
httpService = await module.get(HttpService);
});
afterEach(() => {
jest.clearAllMocks();
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
Here is the implementation of the service. I can confirm that is is successfully making calls to the endpoint within my developer environment.
air-gateway.service.ts
import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { TerminusArgs } from './dto/terminus.args';
import { AirSchedules } from './models/air-schedules.model';
@Injectable()
export class AirGatewayService {
constructor(private readonly httpService: HttpService) {}
public async findAll(terminusArgs: TerminusArgs): Promise<AirSchedules> {
const { data } = await firstValueFrom(
this.httpService
.get<GatewayResponse<AirSchedules>>(gatewayURL.href, { headers })
.pipe(
catchError((error: AxiosError) => {
throw `GatewayServiceError -> findAll: an error has occurred fetching for Gateway\n${error}`;
})
)
);
}
}
I have updated dependencies for anything nest, axios, jest, typescript up to recent versions.
"@nestjs/apollo": "12.0.3","@nestjs/axios": "^3.0.0","@nestjs/core": "10.0.3","typescript": "5.1.6",I have the babel.config.js for my project to allow me to run typescript within my tests
module.exports = {
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-typescript'
],
plugins: [['@babel/plugin-proposal-decorators', { version: '2023-11' }]]
};
- Tried setting up and removing the
jest.config.jsfile as such:
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
moduleNameMapper: {
axios: 'axios/dist/node/axios.cjs'
}
}
- Experimented with the
@automock/jestnpm package But this just fails for pretty much the same error just expressed differently within the error logs.
Automock snippet
let service: AirGatewayService;
let httpService: jest.Mocked<HttpService>;
beforeAll(() => {
const { unit, unitRef } =
TestBed.create(AirGatewayService).compile();
service = unit;
httpService = unitRef.get(HttpService);
});
Fails with: IdentifierNotFoundError: Missing class dependency identifier (code ER010) The dependency associated with the specified token or identifier ('HttpService') could not be located within the current testing context. This issue pertains to the usage of the UnitReference API. Please ensure accurate spelling and correspondence between the provided token or identifier and the corresponding injection configuration. If you are utilizing a custom token, it is essential to confirm its proper registration within the DI container
- I get this trace when running
npx jest air-gateway.service.spec.tswith tracing enabled.
Trace: gateway
at GatewayService.trace [as findAll] (/Users/pingwinZloty/Projects/centrus-active/apps/gateway-subgraph/src/gateway/gateway.service.ts:41:9)
at Object.findAll (/Users/pingwinZloty/Projects/centrus-active/apps/gateway-subgraph/src/gateway/tests/gateway.service.spec.ts:140:35)
at Promise.then.completed (/Users/pingwinZloty/Projects/centrus-active/node_modules/jest-circus/build/utils.js:298:28)
at new Promise (<anonymous>)
at callAsyncCircusFn (/Users/pingwinZloty/Projects/centrus-active/node_modules/jest-circus/build/utils.js:231:10)
at _callCircusTest (/Users/pingwinZloty/Projects/centrus-active/node_modules/jest-circus/build/run.js:316:40)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at _runTest (/Users/pingwinZloty/Projects/centrus-active/node_modules/jest-circus/build/run.js:252:3)
at _runTestsForDescribeBlock (/Users/pingwinZloty/Projects/centrus-active/node_modules/jest-circus/build/run.js:126:9)
at _runTestsForDescribeBlock (/Users/pingwinZloty/Projects/centrus-active/node_modules/jest-circus/build/run.js:121:9)
at run (/Users/pingwinZloty/Projects/centrus-active/node_modules/jest-circus/build/run.js:71:3)
at runAndTransformResultsToJestFormat (/Users/pingwinZloty/Projects/centrus-active/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
at jestAdapter (/Users/pingwinZloty/Projects/centrus-active/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
at runTestInternal (/Users/pingwinZloty/Projects/centrus-active/node_modules/jest-runner/build/runTest.js:367:16)
at runTest (/Users/pingwinZloty/Projects/centrus-active/node_modules/jest-runner/build/runTest.js:444:34)
Try mocking using overrideProvider
You can mock your HttpService like this