'Can't define entity in controller's unit test

I want to write a unit test for a controller in NestJS which uses the service. Service uses an entity and typeorm to getting data from postgres.

controller.spec.ts

import { Test, TestingModule } from '@nestjs/testing';
import { EmissionsWeldingController } from '../EmissionsWelding.controller';

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

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

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

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

It failed with an error: Nest can't resolve dependencies of the EmissionsWeldingController (?). Please make sure that the argument EmissionsWeldingService at index [0] is available in the RootTestModule context.

When I define my service and entity

import { Test, TestingModule } from '@nestjs/testing';
import { TypeOrmModule } from '@nestjs/typeorm';
import { EmissionsWeldingController } from '../EmissionsWelding.controller';
import { Mark, Substance, WorkType, WorkSpecification, InputField, SummaryValue } from '../EmissionsWelding.entity';
import { EmissionsWeldingService } from '../EmissionsWelding.service';

describe('EmissionsWeldingController', () => {
  let controller: EmissionsWeldingController;
  let service: EmissionsWeldingService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      imports: [TypeOrmModule.forFeature([Mark, Substance, WorkType, WorkSpecification, InputField, SummaryValue])],
      controllers: [EmissionsWeldingController],
      providers: [EmissionsWeldingService],
    }).compile();

    controller = module.get<EmissionsWeldingController>(EmissionsWeldingController);
    service = module.get<EmissionsWeldingService>(EmissionsWeldingService);
  });

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

It's failing with an error: Nest can't resolve dependencies of the MarkRepository (?). Please make sure that the argument Connection at index [0] is available in the TypeOrmModule context.

How should I define providers and entities without getting above error?

service.ts

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { GetResultDto } from './dto/GetResult.dto';
import { InputField, Mark, Substance, SummaryValue, WorkSpecification, WorkType } from './EmissionsWelding.entity';

@Injectable()
export class EmissionsWeldingService {
  constructor(
    @InjectRepository(Mark)
    private markRepository: Repository<Mark>,
    @InjectRepository(Substance)
    private substanceRepository: Repository<Substance>,
    @InjectRepository(WorkSpecification)
    private workSpecificationRepository: Repository<WorkSpecification>,
    @InjectRepository(WorkType)
    private workTypeRepository: Repository<WorkType>,
    @InjectRepository(InputField)
    private inputFieldRepository: Repository<InputField>,
    @InjectRepository(SummaryValue)
    private summaryValueRepository: Repository<SummaryValue>,
  ) {}

  async getMarks(work_type_id: number, work_specification_id: number): Promise<Mark[]> {
    return await this.markRepository.find({ where: { work_type_id, work_specification_id } });
  }

  async getSubstances(): Promise<Substance[]> {
    return await this.substanceRepository.find();
  }

  async getWorkSpecifications(): Promise<WorkSpecification[]> {
    return await this.workSpecificationRepository.find();
  }

  async getWorkTypes(): Promise<WorkType[]> {
    return await this.workTypeRepository.find();
  }

  async getInputFields(): Promise<WorkType[]> {
    return await this.inputFieldRepository.find();
  }

  async getSummaryValues(mark_id: number, substance_id: number): Promise<SummaryValue[]> {
    return await this.summaryValueRepository.find({ where: { mark_id, substance_id } });
  }

  async getResult(body: GetResultDto): Promise<GetResultDto[]> {
    const result = [];
    const { mark_id, input_fields_values } = body;
    const substances = await this.getSubstances();
    let currentSummaryValue;

    for (let i = 0; i <= substances.length - 1; i++) {
      currentSummaryValue = await this.getSummaryValues(mark_id, i + 1);
      result.push({
        code: substances[i].code,
        name: substances[i].name,
        year:
          ((input_fields_values.year * currentSummaryValue[0].value) / 10 ** 6) *
          (1 - (input_fields_values.clean ? input_fields_values.clean : 0)),
        second:
          ((currentSummaryValue[0].value * input_fields_values.hour) / 3600) *
          (1 - (input_fields_values.clean ? input_fields_values.clean : 0)),
      });
    }
    return result;
  }
}

controller.ts

import { Body, Controller, Get, Post, Query } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { GetResultDto } from './dto/GetResult.dto';
import { EmissionsWeldingService } from './EmissionsWelding.service';

@ApiTags('EmissionsWelding')
@Controller('EmissionsWelding')
export class EmissionsWeldingController {
  constructor(private emissionsWeldingService: EmissionsWeldingService) {}

  @Get('getMarks')
  getMarks(@Query('work_type_id') work_type_id: number, @Query('work_specification_id') work_specification_id: number) {
    return this.emissionsWeldingService.getMarks(work_type_id, work_specification_id);
  }

  @Get('getSubstances')
  getSubstances() {
    return this.emissionsWeldingService.getSubstances();
  }

  @Get('getWorkSpecifications')
  getWorkSpecifications() {
    return this.emissionsWeldingService.getWorkSpecifications();
  }

  @Get('getWorkTypes')
  getWorkTypes() {
    return this.emissionsWeldingService.getWorkTypes();
  }

  @Get('getInputFields')
  getInputFields() {
    return this.emissionsWeldingService.getInputFields();
  }

  @Post('getResult')
  getResult(@Body() body: GetResultDto) {
    return this.emissionsWeldingService.getResult(body);
  }
}


Solution 1:[1]

You need to provide a mock for every repository that is injected into your service.

This answer provides the necessary detail so please give it an upvote: https://stackoverflow.com/a/55366343/588734

describe('EmissionsWeldingController', () => {
  let controller: EmissionsWeldingController;
  let service: EmissionsWeldingService;
  let markRepositoryMock: MockType<Repository<Mark>>;
  // repeat for every repository let __RepositoryMock: MockType<Repository<__>>;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      controllers: [EmissionsWeldingController],
      providers: [
        EmissionsWeldingService,
        { 
          provide: getRepositoryToken(Mark),
          useValue: jest.fn(() => ({
            findOne: jest.fn(entity => entity),
            // provide a mock for each function you are calling
          })) 
        },
        // repeat for every mock
      ],
    }).compile();

    controller = module.get<EmissionsWeldingController>(EmissionsWeldingController);
    service = module.get<EmissionsWeldingService>(EmissionsWeldingService);
    markRepositoryMock = module.get(getRepositoryToken(Mark));
    // repeat for every mock repository

  });

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

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 Eamonn McEvoy