diff --git a/src/apis/auth/__test__/auth.resolver.spec.ts b/src/apis/auth/__test__/auth.resolver.spec.ts index 38ddc8c..4233021 100644 --- a/src/apis/auth/__test__/auth.resolver.spec.ts +++ b/src/apis/auth/__test__/auth.resolver.spec.ts @@ -15,9 +15,9 @@ const EXAMPLE_USER: User = { password: 'exampleUserPassword', phone: 'exampleUserPhone', image: 'exampleUserImage', - createAt: new Date(), - deleteAt: new Date(), - updateAt: new Date(), + createdAt: new Date(), + deletedAt: new Date(), + updatedAt: new Date(), dogs: [null], reservation: [null], }; diff --git a/src/apis/auth/__test__/auth.service.spec.ts b/src/apis/auth/__test__/auth.service.spec.ts index 95d1a91..4fd7978 100644 --- a/src/apis/auth/__test__/auth.service.spec.ts +++ b/src/apis/auth/__test__/auth.service.spec.ts @@ -1,6 +1,9 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { getRepositoryToken } from '@nestjs/typeorm'; -import { CACHE_MANAGER, UnprocessableEntityException } from '@nestjs/common'; +import { + CACHE_MANAGER, + UnauthorizedException, + UnprocessableEntityException, +} from '@nestjs/common'; import { Cache } from 'cache-manager'; import { UsersService } from 'src/apis/users/user.service'; import { User } from 'src/apis/users/entities/user.entity'; @@ -8,8 +11,6 @@ import { AuthService } from '../auth.service'; import { IContext } from 'src/commons/interface/context'; import { JwtService } from '@nestjs/jwt'; import * as httpMocks from 'node-mocks-http'; -import { MockUsersRepository } from './auth.mocking.dummy'; -import { MailerModule } from '@nestjs-modules/mailer'; jest.mock('../auth.service'); @@ -20,9 +21,9 @@ const EXAMPLE_USER: User = { password: 'exampleUserPassword', phone: 'exampleUserPhone', image: 'exampleUserImage', - createAt: new Date(), - deleteAt: new Date(), - updateAt: new Date(), + createdAt: new Date(), + deletedAt: new Date(), + updatedAt: new Date(), dogs: [null], reservation: [null], }; @@ -30,35 +31,41 @@ const EXAMPLE_USER: User = { describe('AuthResolver', () => { let authService: AuthService; let usersService: UsersService; - let jwtService: JwtService; - let cache: Cache; - let context: IContext; + let jwt: JwtService; + let cacheManager: Cache; + + const context: IContext = { + req: httpMocks.createRequest(), + res: httpMocks.createResponse(), + }; + context.req.user = new User(); + context.req.user.id = EXAMPLE_USER.id; + const email = EXAMPLE_USER.email; + const password = EXAMPLE_USER.password; + const process = { + env: { + JWT_ACCESS_KEY: 'exampleAccess', + JWT_REFRESH_KEY: 'exampleRefresh', + }, + }; beforeEach(async () => { jest.clearAllMocks(); - const usersModule: TestingModule = await Test.createTestingModule({ - imports: [ - MailerModule.forRootAsync({ - useFactory: () => ({ - transport: { - service: 'Gmail', - host: process.env.EMAIL_HOST, - port: Number(process.env.DATABASE_PORT), - secure: false, - auth: { - user: process.env.EMAIL_USER, - pass: process.env.EMAIL_PASS, - }, - }, - }), - }), - ], + const modules: TestingModule = await Test.createTestingModule({ providers: [ AuthService, - UsersService, { - provide: getRepositoryToken(User), - useClass: MockUsersRepository, + provide: UsersService, + useValue: { + findOneByEmail: jest.fn(() => EXAMPLE_USER), + create: jest.fn(() => EXAMPLE_USER), + }, + }, + { + provide: JwtService, + useValue: { + verify: jest.fn(() => 'EXAMPLE_TOKEN'), + }, }, { provide: CACHE_MANAGER, @@ -69,22 +76,13 @@ describe('AuthResolver', () => { }, ], }).compile(); - const authModule: TestingModule = await Test.createTestingModule({ - providers: [AuthService], - }).compile(); - usersService = usersModule.get(UsersService); - authService = authModule.get(AuthService); - cache = usersModule.get(CACHE_MANAGER); - context = { - req: httpMocks.createRequest(), - res: httpMocks.createResponse(), - }; + authService = modules.get(AuthService); + usersService = modules.get(UsersService); + jwt = modules.get(JwtService); + cacheManager = modules.get(CACHE_MANAGER); }); - const email = EXAMPLE_USER.email; - const password = EXAMPLE_USER.password; - describe('login', () => { it('의존성주입한 usersService 에서 email로 찾아오기', async () => { jest @@ -129,10 +127,58 @@ describe('AuthResolver', () => { }); describe('logout', () => { - // - }); + const req = context.req; + it('토큰 증명해서 로그아웃 인가', async () => { + const req = { + headers: { + authorization: 'Bearer ACCESS_TOKEN', + cookie: 'refreshToken=REFRESH_TOKEN', + }, + }; - describe('restoreAccessToken', () => { - // + try { + const accessToken = await req.headers['authorization'].replace( + 'Bearer ', + '', + ); + const refreshToken = await req.headers['cookie'].split( + 'refreshToken=', + )[1]; + + // accessToken 토큰 + const jwtAccessKey = jwt.verify(accessToken); + + // refresh 토큰 + const jwtRefreshKey = jwt.verify(refreshToken); + + await cacheManager.set(`accessToken:${accessToken}`, 'accessToken', { + ttl: jwtAccessKey['exp'] - jwtAccessKey['iat'], + }); + + await cacheManager.set(`refreshToken:${refreshToken}`, 'refreshToken', { + ttl: jwtRefreshKey['exp'] - jwtRefreshKey['iat'], + }); + + expect(jwt.verify).toBeCalled(); + + return '로그아웃에 성공했습니다.'; + } catch (error) { + expect(error).toBeInstanceOf(Error); + expect(error.message).toBe('로그아웃을 실패했습니다.'); + throw new UnauthorizedException('로그아웃을 실패했습니다.'); + } + }); + + describe('restoreAccessToken', () => { + const user = EXAMPLE_USER; + + beforeEach(async () => { + await authService.getAccessToken({ user }); + }); + + it('getAccessToken should be called', () => { + expect(authService.getAccessToken).toBeCalled(); + }); + }); }); }); diff --git a/src/apis/reviews/__test__/reviews.service.spec.ts b/src/apis/reviews/__test__/reviews.service.spec.ts new file mode 100644 index 0000000..4fb4b5c --- /dev/null +++ b/src/apis/reviews/__test__/reviews.service.spec.ts @@ -0,0 +1,112 @@ +import { UnprocessableEntityException } from '@nestjs/common'; +import { Test, TestingModule } from '@nestjs/testing'; +import { getRepositoryToken } from '@nestjs/typeorm'; +import { ShopsService } from 'src/apis/shops/shops.service'; +import { Repository } from 'typeorm'; +import { Review } from '../entities/review.entity'; +import { ReviewsService } from '../reviews.service'; + +jest.mock('../reviews.service'); +const EXAMPLE_REVIEW = { + id: 'EXAMPLE_REVIEW_ID', + contents: 'EXAMPLE_REVIEW_CONTENTS', + createdAt: new Date(), + star: 5, + reservation: { id: '33bcbf41-884b-46f2-96a2-f3947a1ca906' }, + shop: { id: '500d75e0-0223-4046-be13-55887bfbf6f0' }, +}; + +const MockReviewsRepository = () => ({ + find: jest.fn((where, skip, take, order, relations) => { + EXAMPLE_REVIEW; + }), + findOne: jest.fn((where, relations) => { + EXAMPLE_REVIEW; + }), + save: jest.fn(({ contents, star, reservation, shop }) => { + EXAMPLE_REVIEW; + }), +}); + +type MockRepository = Partial, jest.Mock>>; + +describe('ReviewsService', () => { + let reviewsService: ReviewsService; + let shopsService: ShopsService; + let mockReviewsRepository: MockRepository; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + ReviewsService, + { + provide: getRepositoryToken(Review), + useValue: MockReviewsRepository(), + }, + { + provide: ShopsService, + useValue: { + findById: jest.fn(() => true), + }, + }, + ], + }).compile(); + + reviewsService = module.get(ReviewsService); + mockReviewsRepository = module.get(getRepositoryToken(Review)); + }); + + const reviewId = EXAMPLE_REVIEW.id; + const shopId = 'shopId'; + + describe('find', () => { + it('reviewsRepository의 findOne을 실행하고 값이 없으면 error 반환해야함', async () => { + try { + const result = await mockReviewsRepository.findOne({ + where: { id: reviewId }, + relations: ['shop', 'reservation'], + }); + } catch (error) { + expect(error).toBeInstanceOf(UnprocessableEntityException); + expect(error.message).toEqual('아이디를 찾을 수 없습니다'); + } + expect(mockReviewsRepository.findOne).toBeCalled(); + }); + }); + + describe('findByShopIdWithPage', () => { + it('', () => { + try { + shopsService.findById({ shopId }); + } catch (error) { + expect(error).toBeInstanceOf(Error); + throw new UnprocessableEntityException('유효하지 않은 가게ID 입니다'); + } + const page = 1; + const count = 12; + const result = mockReviewsRepository.find({ + where: { shop: { id: shopId } }, + skip: (page - 1) * count, + take: count, + order: { + createdAt: 'ASC', + }, + relations: ['shop', 'reservation'], + }); + + expect(mockReviewsRepository.find).toBeCalled(); + }); + }); + + describe('create', () => { + it('', async () => {}); + }); + + describe('averageStar', () => { + it('', async () => {}); + }); + + describe('checkReviewAuth', () => { + it('', async () => {}); + }); +}); diff --git a/src/apis/shopImages/__test__/shopImage.service.spec.ts b/src/apis/shopImages/__test__/shopImage.service.spec.ts index 9cef58d..d5d4294 100644 --- a/src/apis/shopImages/__test__/shopImage.service.spec.ts +++ b/src/apis/shopImages/__test__/shopImage.service.spec.ts @@ -100,7 +100,8 @@ describe('shopImagesService', () => { try { await checkShop({ shopId }); } catch (error) { - expect(error).toThrow(UnprocessableEntityException); + throw new UnprocessableEntityException(); + expect(error).toBeInstanceOf(UnprocessableEntityException); } const result = mockShopImagesRepository.find({ @@ -117,7 +118,8 @@ describe('shopImagesService', () => { try { await checkURL({ shopId }); } catch (error) { - expect(error).toThrow(ConflictException); + throw new ConflictException(); + expect(error).toBeInstanceOf(ConflictException); } const result = mockShopImagesRepository.save({ @@ -163,6 +165,7 @@ describe('shopImagesService', () => { try { await checkImage({ shopId }); } catch (error) { + throw new UnprocessableEntityException('아이디를 찾을 수 없습니다'); expect(error).toThrow(UnprocessableEntityException); } const result = await mockShopImagesRepository.delete({