1
votes

I want to unit-test a class which getCustomRepository in it's constructor but I just can't figure an easy way to mock it. Here is my class code

import {getCustomRepository} from 'typeorm';

export class Controller {
  private repository: UserRepository;

  constructor() {
    this.repository = getCustomRepository(UserRepository); //I want to mock this.
  }

  async init() {
    return this.repository.findUser(1);
  }
}

and here are tests

describe('User Tests', () => {
  it('should return user', async () => {
    //Fake user to be resolved.
    const user = new User();
    user.id = 2;

    //I want to mock  getCustomRepository(UserRepository); here
    //getCustomRepository = jest.fn().mockResolvedValue(UserRepository); HERE HOW???

    //Mocking find user
    UserRepository.prototype.findUser = jest.fn().mockResolvedValue(user);

    const controller = new Controller();
    const result = await controller.init();
    expect(result).toBeDefined();
  });
});

Note: Mocking repository methods works well but I really want to mock getCustomRepository so as It may reduce time which is wasted trying to connect to database.

This is how getCustomRepository in typeORM looks like

export declare function getCustomRepository<T>(customRepository: ObjectType<T>, connectionName?: string): T;

UserRepository.ts

@EntityRepository(User)
export class UserRepository extends Repository<User> {
  public async findUser(id: number) {
    return 'real user';
  }
}

User.ts

@Entity('users')
export class User{
  @PrimaryGeneratedColumn()
  id: number;

  @Column({type: 'varchar', length: 100})
  name: string;
}

So question is how do I mock it? Any help will be much appreciated.

2
In your Controller class, how does the getCustomRepository get imported? Can you add that part to your question?mgarcia
@mgarcia I have edited. It is imported like this import {getCustomRepository} from 'typeorm';Nux
@mgarcia any suggestion?Nux

2 Answers

2
votes

You can use jest.mock(moduleName, factory, options) to mock typeorm module, getCustomRepository function and its returned value.

E.g.

controller.ts:

import { getCustomRepository } from 'typeorm';
import { UserRepository } from './userRepo';

export class Controller {
  private repository: UserRepository;

  constructor() {
    this.repository = getCustomRepository(UserRepository);
  }

  async init() {
    return this.repository.findUser(1);
  }
}

userRepo.ts:

export class UserRepository {
  public async findUser(id: number) {
    return 'real user';
  }
}

controller.test.ts:

import { Controller } from './controller';
import { getCustomRepository } from 'typeorm';
import { mocked } from 'ts-jest/utils';
import { UserRepository } from './userRepo';

jest.mock('typeorm', () => ({ getCustomRepository: jest.fn() }));

describe('61693597', () => {
  it('should pass', async () => {
    const userRepo = { findUser: jest.fn().mockResolvedValueOnce('fake user') };
    mocked(getCustomRepository).mockReturnValueOnce(userRepo);
    const controller = new Controller();
    const actual = await controller.init();
    expect(actual).toBe('fake user');
    expect(getCustomRepository).toBeCalledWith(UserRepository);
    expect(userRepo.findUser).toBeCalledWith(1);
  });
});

unit test results with coverage report:

 PASS  stackoverflow/61693597/controller.test.ts (13.53s)
  61693597
    ✓ should pass (9ms)

---------------|---------|----------|---------|---------|-------------------
File           | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
---------------|---------|----------|---------|---------|-------------------
All files      |   92.31 |      100 |      80 |   90.91 |                   
 controller.ts |     100 |      100 |     100 |     100 |                   
 userRepo.ts   |      80 |      100 |      50 |      75 | 3                 
---------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        15.596s

source code: https://github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/stackoverflow/61693597

0
votes

I've run into the same issue a bit later as it seems. Here is for future visitors a version that is currently working:

my spec.ts file

import { Test, TestingModule } from '@nestjs/testing';

import { GraphDataService } from './graph-data.service';

jest.mock('typeorm', () => ({
  ...jest.requireActual('typeorm'),
  getCustomRepository: jest.fn(),
}));

describe('GraphDataService', () => {
  let service: GraphDataService;

  beforeAll(() =>
    jest.mock('typeorm', () => ({
      ...jest.requireActual('typeorm'),
      getCustomRepository: jest.fn(),
    })),
  );

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [GraphDataService, { provide: 'ObjectValidator', useValue: {} }],
    }).compile();

    service = module.get<GraphDataService>(GraphDataService);
  });

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

Works with [email protected] and [email protected]