From 26355dd39a5e559d93f1d7697af643301a045d0e Mon Sep 17 00:00:00 2001 From: naftalimurgor Date: Wed, 6 Dec 2023 17:58:18 +0300 Subject: [PATCH] test: fix `user.service` tests #108 --- apps/api/src/user/user.service.spec.ts | 119 ++++++++++++++++--------- 1 file changed, 79 insertions(+), 40 deletions(-) diff --git a/apps/api/src/user/user.service.spec.ts b/apps/api/src/user/user.service.spec.ts index b9b0308..6c212e8 100644 --- a/apps/api/src/user/user.service.spec.ts +++ b/apps/api/src/user/user.service.spec.ts @@ -1,69 +1,95 @@ import { Test, type TestingModule } from '@nestjs/testing' import { getRepositoryToken } from '@nestjs/typeorm' -import { createMock } from 'ts-auto-mock' import type { Repository } from 'typeorm' import type { UserUpdate } from './dto/user-update.dto' import { UserService } from './user.service' import { UserEntity } from '../entities/user.entity' +import { NotFoundException } from '@nestjs/common' + +type MockType = { + [P in keyof T]?: jest.Mock<{}> +} describe('UserService', () => { - let service: UserService - let mockedUserRepository: jest.Mocked> + let userService: UserService + let mockedUserRepository: MockType> + + const testUser = { + id: 1, + firstName: 'John', + lastName: 'Doe', + email: 'john@doe.me', + password: 'Pa$$w0rd' + } + + const userRepositoryMockFactory: () => MockType> = jest.fn( + () => ({ + create: jest.fn(entity => entity), + findOne: jest.fn(({ where }) => testUser), + update: jest.fn(), + save: jest.fn().mockImplementationOnce((entity) => { + return Promise.resolve(testUser) + }), + findOneBy: jest.fn(), + merge: jest.fn(), + }) + ) + beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ - providers: [UserService] - }) - .useMocker(token => { - if (Object.is(token, getRepositoryToken(UserEntity))) { - return createMock>() + providers: [ + UserService, + { + provide: getRepositoryToken(UserEntity), + useFactory: userRepositoryMockFactory } - }) - .compile() + ] + }).compile() - service = module.get(UserService) + userService = module.get(UserService) mockedUserRepository = module.get(getRepositoryToken(UserEntity)) }) + afterEach(() => { + jest.clearAllMocks() + }) + it('should be an instanceof UserService', () => { - expect(service).toBeInstanceOf(UserService) + expect(userService).toBeInstanceOf(UserService) }) it('should create a new user', async () => { - const data = { - firstName: 'John', - lastName: 'Doe', - email: 'john@doe.me', - password: 'Pa$$w0rd' - } - - mockedUserRepository.save.mockResolvedValueOnce( - createMock(data) - ) - const user = await service.create(data) + mockedUserRepository.create.mockReturnValueOnce(testUser) + const user = await userService.create(testUser) - expect(user).toBeDefined() + expect(user.id).toEqual(testUser.id) }) it('should find one user', async () => { const email = 'john@doe.me' - mockedUserRepository.findOne.mockResolvedValueOnce( - createMock({ email }) - ) - const user = await service.findOne({ where: { email } }) + mockedUserRepository.findOne.mockImplementation(() => { + return Promise.resolve(testUser) + }) + + const user = await userService.findOne({ where: { email } }) expect(user).toBeDefined() expect(user).toHaveProperty('email', 'john@doe.me') + expect(mockedUserRepository.findOne).toHaveBeenCalledTimes(1) }) it('should throw on find one when the user not exist', async () => { - mockedUserRepository.findOne.mockResolvedValueOnce(undefined) + mockedUserRepository.findOne.mockImplementationOnce(({ where }) => { + return Promise.reject( + new NotFoundException("\"There isn't any user with identifier: [object Object]\"")) + }) await expect( - service.findOne({ where: { email: 'notexisting@example.com' } }) - ).rejects.toThrowErrorMatchingInlineSnapshot( + userService.findOne({ where: { email: 'notexisting@example.com' } }) + ).rejects.toThrow( `"There isn't any user with identifier: [object Object]"` ) }) @@ -71,31 +97,44 @@ describe('UserService', () => { it('should update an user', async () => { const id = 1 const updates: UserUpdate = { - firstName: 'Jhonny', + firstName: 'John', lastName: 'Doe' } - mockedUserRepository.save.mockResolvedValueOnce( - createMock(updates) - ) - const user = await service.update(id, updates) + mockedUserRepository.findOneBy.mockImplementation(({ id }) => { + return Promise.resolve(testUser) + }) + + jest.spyOn(mockedUserRepository, 'merge').mockImplementationOnce((user, updates) => { + return Promise.resolve({ testUser, ...updates }) + }) + + const user = await userService.update(id, updates) expect(user).toBeDefined() expect(user).toHaveProperty('firstName', updates.firstName) + expect(mockedUserRepository.merge).toHaveBeenCalled() + expect(mockedUserRepository.merge).toHaveBeenCalledTimes(1) + }) it('should throw on update when the user not exist', async () => { - const id = 0 + const id = 1 const updates: UserUpdate = { firstName: 'Jhonny', lastName: 'Doe' } - mockedUserRepository.findOneBy.mockResolvedValueOnce(undefined) + + mockedUserRepository.findOneBy.mockImplementationOnce(({ id }) => { + return Promise.reject(new NotFoundException(`There isn't any user with id: ${id}`)) + }) await expect( - service.update(id, updates) + userService.update(id, updates) ).rejects.toThrowErrorMatchingInlineSnapshot( - `"There isn't any user with id: 0"` + `"There isn't any user with id: 1"` ) + expect(mockedUserRepository.findOneBy).toHaveBeenCalledWith({ id }) + expect(mockedUserRepository.findOneBy).toHaveBeenCalledTimes(1) }) })