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.
C
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) {
}
async findUser(userId: string): Promise {
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> = 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>;
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);
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 mocks (far from perfect, there might be a better solution when jest itself starts using typescript in the upcoming major releases):
export type MockType = {
[P in keyof T]: jest.Mock<{}>;
};