Mock Injectable model in nestjs with Jest

I want to unit test my service. Inside my service I have a constructor that is:

contractService.ts:

export class ContractService {
  private logger = new Logger("ContractService");
  constructor(
    @InjectModel(Contract)
    private contractModel: typeof Contract
  ) {}

  async getContracts(query: PaginationInterface): Promise<FetchContract> {
    const { limit, page, skip } = paginationParseParams(query);
    const { sortBy, direction } = sortParseParams(query, ColumnDetails);
    const { count, rows } = await this.contractModel.findAndCountAll({
      where: {},
      offset: skip,
      limit: limit,
      order: [[sortBy, direction]],
    });
    const pages = Math.ceil(count / limit);
    const meta = {
      limit,
      skip,
      page,
      count,
      pages,
      sortBy,
      direction,
    };
    return { meta, data: rows };
  }
}

My model looks like this: (Model is a class from sequelize-typescript)

export class Contract extends Model<Contract> {
   .... 
} 

So I want to create my unit test with jest. When I try to mock the contractModel, it does not find the method, eventhough I am trying to mock it.

const mockContractModel = () => ({
  findAndCountAll: jest.fn(),
});

describe("ContractService", () => {
  let contractService: ContractService;
  let contractModel: Contract;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        ContractService,
        {
          provide: Contract,
          useFactory: mockContractModel,
        },
      ],
    }).compile();

    contractService = module.get<ContractService>(ContractService);
    contractModel = module.get<Contract>(Contract);
  });

  it("should be defined", () => {
    expect(contractService).toBeDefined();
  });

  describe("Get contracts", () => {
    it("Should return all the contracts", async () => {
      expect(contractModel.findAndCountAll).not.toHaveBeenCalled();
      await contractService.getContracts(defaultPagination);
      expect(contractModel.findAndCountAll).toHaveBeenCalled();
    });
  });
});

What is the right way to mock this contractModel?

Answer

Instead of using

{
  provide: Contract,
  useFactory: mockContractModel
}

You should be using

 {
  provide: getModelToken(Contract),
  useFactory: mockContractModel
}

where getModelToken is imported from @nestjs/mongoose. This will get the correct DI token for Nest to know what you’re mocking. For more examples, check this git repo

Leave a Reply

Your email address will not be published. Required fields are marked *