NestJS: HttpService is not mocked or found within unit-test

95 Views Asked by At

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.js file as such:
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  moduleNameMapper: {
    axios: 'axios/dist/node/axios.cjs'
  }
}
  • Experimented with the @automock/jest npm 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.ts with 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)
1

There are 1 best solutions below

1
Nivetha On

Try mocking using overrideProvider

const module: TestingModule = await Test.createTestingModule({
  providers: [
    AirGatewayService,HttpService
  ],
})
  .overrideProvider(HttpService)
  .useValue(mockHttpService)
  .compile();

You can mock your HttpService like this

export const mockHttpService ={
  get: jest.fn().mockImplementation(() => {
     return ;
  }),
}