There’s a longish discussion about how to do this in this issue.
I’ve experimented with a number of the proposed solutions but I’m not having much luck.
Could anyone provide a concrete example of how to test a service with an injected repository and mock data?
Advertisement
Answer
Let’s assume we have a very simple service that finds a user entity by id:
export class UserService { constructor(@InjectRepository(UserEntity) private userRepository: Repository<UserEntity>) { } async findUser(userId: string): Promise<UserEntity> { return this.userRepository.findOne(userId); } }
Then you can mock the UserRepository
with the following mock factory (add more methods as needed):
// @ts-ignore export const repositoryMockFactory: () => MockType<Repository<any>> = jest.fn(() => ({ findOne: jest.fn(entity => entity), // ... }));
Using a factory ensures that a new mock is used for every test.
describe('UserService', () => { let service: UserService; let repositoryMock: MockType<Repository<UserEntity>>; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [ UserService, // Provide your mock instead of the actual repository { provide: getRepositoryToken(UserEntity), useFactory: repositoryMockFactory }, ], }).compile(); service = module.get<UserService>(UserService); repositoryMock = module.get(getRepositoryToken(UserEntity)); }); it('should find a user', async () => { const user = {name: 'Alni', id: '123'}; // Now you can control the return value of your mock's methods repositoryMock.findOne.mockReturnValue(user); expect(service.findUser(user.id)).toEqual(user); // And make assertions on how often and with what params your mock's methods are called expect(repositoryMock.findOne).toHaveBeenCalledWith(user.id); }); });
For type safety and comfort you can use the following typing for your (partial) mocks (far from perfect, there might be a better solution when jest itself starts using typescript in the upcoming major releases):
export type MockType<T> = { [P in keyof T]?: jest.Mock<{}>; };