Nest: TypeORM test save() with a mock repository?

Created on 22 Aug 2018  ·  14Comments  ·  Source: nestjs/nest

I'm submitting a...


[ ] Regression 
[ ] Bug report
[ ] Feature request
[x] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

I'm trying to write a test to test the creation of a User object and saving it to a database.

user.service.spec.ts

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

  beforeAll(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        UserService,
        {
          provide: getRepositoryToken(User),
          useClass: UserRepository,
        },
      ],
    }).compile();
    service = module.get<UserService>(UserService);
  });

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

  it('can create a user', async () => {
    const userDto = new UserDto();
    userDto.email = '[email protected]';
    userDto.password = 'password123';
    const user = await service.create(userDto);
    expect(user.username).toEqual(userDto.email);
  });
});

user.service.ts

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User) private readonly userRepository: UserRepository,
  ) {}

  async create(userDto: UserDto): Promise<User> {
    const user = new User();
    user.username = userDto.email;
    user.password = userDto.password; // TODO: Need to hash this later
    return await this.userRepository.save(user);
  }
}

However it throws an error when trying to save() - How can I properly test this?

The error is:

 FAIL  src/user/user.service.spec.ts
  ● UserService › can create a user

    TypeError: Cannot read property 'save' of undefined

      at UserRepository.Object.<anonymous>.Repository.save (repository/Repository.ts:138:29)
      at UserService.<anonymous> (user/user.service.ts:17:38)
          at Generator.next (<anonymous>)
      at user/user.service.ts:19:71
          at new Promise (<anonymous>)
      at Object.<anonymous>.__awaiter (user/user.service.ts:15:12)
      at UserService.create (user/user.service.ts:33:16)
      at Object.<anonymous> (user/user.service.spec.ts:32:32)
          at Generator.next (<anonymous>)
      at user/user.service.spec.ts:7:71
          at new Promise (<anonymous>)
      at Object.<anonymous>.__awaiter (user/user.service.spec.ts:3:12)
      at Object.it (user/user.service.spec.ts:28:38)
          at new Promise (<anonymous>)
      at process._tickCallback (../internal/process/next_tick.js:68:7)
needs clarification question 🙌

Most helpful comment

@BrunnerLivio your test in your example are integration test. You should not hit the database if you make unit test, everything should be mocked.

All 14 comments

Could you show us your UserRepository class?

It’s just an empty class that extends Repository<User>. I’ve tried with Repository<User> and I still get the same error.

Please, provide a repository that reproduces this issue, I can't do it locally

@kamilmysliwiec Please try this: https://gitlab.com/kheob/nestjs-test

I have the same problem trying to write a test for my service.

user.service.ts

@Injectable()
export class UsertService {
    constructor(
        @InjectRepository(UserEntity)
        private readonly userRepository: UserEntityRepository,        
    ) { }

    async saveUser(user: UserEntity) {
       await this.userRepository.save(user);
    }

    test() {
        this.userRepository.test();
    }
}

user.service.spec.ts

describe('UserService', () => {
  let userService: UserService;

  beforeAll(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [UserService,
        {
          provide: getRepositoryToken(UserEntity),
          useClass: UserEntityRepository,
        }],
    }).compile();
    userService = module.get<UserService>(UserService);
  });

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

  it('should save a user', async () => {
    const user = new UserEntity('test', 0);
    await userService.saveUser(user);
  });

  it('should call test method', async () => {
    userService.test();
  });

user.repository.ts

@EntityRepository(UserEntity)
@Injectable()
export class UserEntityRepository extends Repository<UserEntity> {

    test() {
        console.log('it works');
    }
}

If i try to run a test using save() or findOne() (or any other method from Repository) i get the following error:

● ConsentService › should save a user

    TypeError: Cannot read property 'save' of undefined

But if i use test() method from my custom repository (user.repository.ts) it works fine.

It looks like UserService its defined and it uses my custom repository however, when I run the test it says that the repository is undefined.

I would like to know the proper way to do this tests.

Honestly, I don' think that this issue has something to do with Nest.

Hi @kamilmysliwiec,

Could you explain the steps that I should follow to test this service? I would like to use a test database instead of a fake repository.

I´ve been trying to do it following the documentation but I could not make it work.

Thank you.

Maybe this helps you guys:

Mocking querybuilder approach:
https://github.com/typeorm/typeorm/issues/1774

Some time ago there was a similar issue, but unit testing with a real database. Created a boilerplate example for Nest 4.x.x back then, maybe you can inspire it from there.
https://github.com/BrunnerLivio/nestjs-unit-test-db-example

@BrunnerLivio your test in your example are integration test. You should not hit the database if you make unit test, everything should be mocked.

For anyone that finds themselves here:

export const mockRepository = jest.fn(() => ({
  metadata: {
    columns: [],
    relations: [],
  },
}));

and

const module: TestingModule = await Test.createTestingModule({
      providers: [{ provide: getRepositoryToken(Entity), useClass: mockRepository }],
    }).compile();

@vincilbishop does the save method work with this? I’ve tried this and still getting errors that save is undefined.

@vincilbishop does the save method work with this? I’ve tried this and still getting errors that save is undefined.

In the mockRepository object define a save: jest.fn as a sibling to metadata: and that should work. It was not a complete mock, just an example. You'll have to mock any methods you use. (as I mocked metaData:)

Ah alright, I somehow misunderstood this. Makes sense to define all the methods and mock them.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rlesniak picture rlesniak  ·  3Comments

menme95 picture menme95  ·  3Comments

KamGor picture KamGor  ·  3Comments

thohoh picture thohoh  ·  3Comments

2233322 picture 2233322  ·  3Comments