diff --git a/src/apis/reviews/__test__/reviews.resolver.spec.ts b/src/apis/reviews/__test__/reviews.resolver.spec.ts index 57458bb..5926426 100644 --- a/src/apis/reviews/__test__/reviews.resolver.spec.ts +++ b/src/apis/reviews/__test__/reviews.resolver.spec.ts @@ -1,11 +1,7 @@ import { Test, TestingModule } from '@nestjs/testing'; import { ReviewsResolver } from '../reviews.resolver'; import { ReviewsService } from '../reviews.service'; -import * as httpMocks from 'node-mocks-http'; -import { IContext } from 'src/commons/interface/context'; -import { CreateReviewInput } from '../dto/create-review.input'; - -jest.mock('../reviews.resolver'); +import { Review } from '../entities/review.entity'; const EXAMPLE_REVIEW = { id: 'EXAMPLE_REVIEW_ID', @@ -16,88 +12,53 @@ const EXAMPLE_REVIEW = { shop: { id: '500d75e0-0223-4046-be13-55887bfbf6f0' }, }; -describe('ReviewResolver', () => { - let mockReviewsService = { - find: jest.fn(({ reviewId }) => EXAMPLE_REVIEW), - findByShopIdWithPage: jest.fn( - ({ page, count, reviewId }) => EXAMPLE_REVIEW, - ), - create: jest.fn(({ userId, createReviewInput }) => EXAMPLE_REVIEW), - }; +describe('ReviewsResolver', () => { let reviewsResolver: ReviewsResolver; - let context: IContext; + let reviewsService: ReviewsService; beforeEach(async () => { - const reviewsModule: TestingModule = await Test.createTestingModule({ + const module: TestingModule = await Test.createTestingModule({ providers: [ ReviewsResolver, { provide: ReviewsService, - useValue: mockReviewsService, + useValue: { + find: jest.fn(), + findByShopIdWithPage: jest.fn(), + create: jest.fn(), + deleteOneById: jest.fn(), + }, }, ], }).compile(); - mockReviewsService = reviewsModule.get(ReviewsService); - reviewsResolver = reviewsModule.get(ReviewsResolver); - context = { - req: httpMocks.createRequest(), - res: httpMocks.createResponse(), - }; - }); - const reviewId = EXAMPLE_REVIEW.id; - const shopId = EXAMPLE_REVIEW.shop.id; - const userId = 'exampleUserId'; + reviewsResolver = module.get(ReviewsResolver); + reviewsService = module.get(ReviewsService); + }); describe('fetchReview', () => { - it('reivewService의 find 메서드 실행', async () => { - const result = await reviewsResolver.fetchReview(reviewId); - return result; - - expect(result).toEqual(EXAMPLE_REVIEW); - expect(mockReviewsService.find({ reviewId })).toBeCalled(); + it('should return a review by reviewId', async () => { + const review = new Review(); + jest.spyOn(reviewsService, 'find').mockResolvedValueOnce(review); + const result = await reviewsResolver.fetchReview(EXAMPLE_REVIEW.id); + expect(reviewsService.find).toBeCalled(); }); }); describe('fetchReviewsByShopId', () => { - it('reivewService의 findByShopIdWithPage 메서드 실행', async () => { - const page = 1; + it('should return reviews by shopId', async () => { + const reviews: Review[] = [new Review(), new Review()]; const count = 100; + const page = 1; + jest + .spyOn(reviewsService, 'findByShopIdWithPage') + .mockResolvedValueOnce(reviews); const result = await reviewsResolver.fetchReviewsByShopId( page, count, - shopId, + EXAMPLE_REVIEW.shop.id, ); - return result; - - expect(result).toEqual(EXAMPLE_REVIEW); - expect( - mockReviewsService.findByShopIdWithPage({ page, count, reviewId }), - ).toBeCalled(); - }); - }); - - describe('createReview', () => { - it('reivewService의 create 메서드 실행', async () => { - const createReviewInput: CreateReviewInput = { - contents: EXAMPLE_REVIEW.contents, - star: EXAMPLE_REVIEW.star, - reservationId: EXAMPLE_REVIEW.reservation.id, - shopId: EXAMPLE_REVIEW.shop.id, - }; - const result = await reviewsResolver.createReview( - createReviewInput, - context, - ); - return result; - - expect(result).toEqual(EXAMPLE_REVIEW); - expect( - mockReviewsService.create({ - userId, - createReviewInput, - }), - ).toBeCalled(); + expect(reviewsService.findByShopIdWithPage).toBeCalled(); }); }); }); diff --git a/src/apis/reviews/__test__/reviews.service.spec.ts b/src/apis/reviews/__test__/reviews.service.spec.ts index 57458bb..ed5682d 100644 --- a/src/apis/reviews/__test__/reviews.service.spec.ts +++ b/src/apis/reviews/__test__/reviews.service.spec.ts @@ -1,103 +1,137 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { ReviewsResolver } from '../reviews.resolver'; +import { UnprocessableEntityException } from '@nestjs/common'; +import { getRepositoryToken } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { Review } from '../entities/review.entity'; +import { ShopsService } from 'src/apis/shops/shops.service'; import { ReviewsService } from '../reviews.service'; -import * as httpMocks from 'node-mocks-http'; -import { IContext } from 'src/commons/interface/context'; -import { CreateReviewInput } from '../dto/create-review.input'; +import { Shop } from 'src/apis/shops/entities/shop.entity'; -jest.mock('../reviews.resolver'); - -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 EXAMPLE_SHOP: Shop = { + id: '1', + name: '1', + phone: '1', + openHour: '1', + closeHour: '1', + address: '1', + code: 123, + lat: '1', + lng: '1', + averageStar: 3, + reservation: null, + image: null, + review: null, + updatedAt: new Date(), + deletedAt: null, }; -describe('ReviewResolver', () => { - let mockReviewsService = { - find: jest.fn(({ reviewId }) => EXAMPLE_REVIEW), - findByShopIdWithPage: jest.fn( - ({ page, count, reviewId }) => EXAMPLE_REVIEW, - ), - create: jest.fn(({ userId, createReviewInput }) => EXAMPLE_REVIEW), - }; - let reviewsResolver: ReviewsResolver; - let context: IContext; +describe('ReviewsService', () => { + let reviewsService: ReviewsService; + let mockRepository: jest.Mocked>; + let mockShopsService: jest.Mocked; beforeEach(async () => { - const reviewsModule: TestingModule = await Test.createTestingModule({ + const module: TestingModule = await Test.createTestingModule({ providers: [ - ReviewsResolver, + ReviewsService, + { + provide: getRepositoryToken(Review), + useValue: { + findOne: jest.fn(), + find: jest.fn(), + save: jest.fn(), + }, + }, { - provide: ReviewsService, - useValue: mockReviewsService, + provide: ShopsService, + useValue: { + findById: jest.fn(), + update: jest.fn(), + }, }, ], }).compile(); - mockReviewsService = reviewsModule.get(ReviewsService); - reviewsResolver = reviewsModule.get(ReviewsResolver); - context = { - req: httpMocks.createRequest(), - res: httpMocks.createResponse(), - }; + + reviewsService = module.get(ReviewsService); + mockRepository = module.get(getRepositoryToken(Review)); + mockShopsService = module.get(ShopsService); }); - const reviewId = EXAMPLE_REVIEW.id; - const shopId = EXAMPLE_REVIEW.shop.id; - const userId = 'exampleUserId'; + describe('find', () => { + it('reviewsService 의 find를 실행해야함', async () => { + const review = new Review(); + const reviewId = 'valid-review-id'; + mockRepository.findOne.mockReturnValue(Promise.resolve(review)); + + const result = await reviewsService.find({ reviewId }); + + expect(result).toBe(review); + expect(mockRepository.findOne).toHaveBeenCalledWith({ + where: { id: reviewId }, + relations: ['shop', 'reservation'], + }); + }); - describe('fetchReview', () => { - it('reivewService의 find 메서드 실행', async () => { - const result = await reviewsResolver.fetchReview(reviewId); - return result; + it('reviewId가 잘못되었을 때 UnprocessableEntityException 반환해야함', async () => { + const reviewId = 'invalid-review-id'; + mockRepository.findOne.mockReturnValue(undefined); - expect(result).toEqual(EXAMPLE_REVIEW); - expect(mockReviewsService.find({ reviewId })).toBeCalled(); + await expect(reviewsService.find({ reviewId })).rejects.toThrow( + UnprocessableEntityException, + ); + expect(mockRepository.findOne).toHaveBeenCalledWith({ + where: { id: reviewId }, + relations: ['shop', 'reservation'], + }); }); }); - describe('fetchReviewsByShopId', () => { - it('reivewService의 findByShopIdWithPage 메서드 실행', async () => { + describe('findByShopIdWithPage', () => { + it('shopsService의 findById 실행해야함', async () => { + const reviews = [new Review(), new Review()]; const page = 1; - const count = 100; - const result = await reviewsResolver.fetchReviewsByShopId( + const count = 10; + mockShopsService.findById.mockResolvedValue(EXAMPLE_SHOP); + mockRepository.find.mockReturnValue(Promise.resolve(reviews)); + + const shopId = 'invalid-shop-id'; + const result = await reviewsService.findByShopIdWithPage({ page, count, shopId, - ); - return result; + }); - expect(result).toEqual(EXAMPLE_REVIEW); - expect( - mockReviewsService.findByShopIdWithPage({ page, count, reviewId }), - ).toBeCalled(); + expect(result).toBe(reviews); + expect(mockShopsService.findById).toBeCalled(); + expect(mockRepository.find).toBeCalled(); }); }); - describe('createReview', () => { - it('reivewService의 create 메서드 실행', async () => { - const createReviewInput: CreateReviewInput = { - contents: EXAMPLE_REVIEW.contents, - star: EXAMPLE_REVIEW.star, - reservationId: EXAMPLE_REVIEW.reservation.id, - shopId: EXAMPLE_REVIEW.shop.id, + describe('create', () => { + it('리뷰 생성하고 shop의 별점평균 업데이트 해야함', async () => { + const userId = 'test-user-id'; + const createReviewInput = { + shopId: 'test-shop-id', + reservationId: 'test-reservation-id', + contents: 'test-contents', + star: 4.5, }; - const result = await reviewsResolver.createReview( + const review = new Review(); + const _averageStar = 4.5; + mockRepository.save.mockResolvedValue(review); + mockRepository.findOne.mockResolvedValue(review); + mockShopsService.update.mockResolvedValue(undefined); + mockRepository.find.mockResolvedValue([]); + + const result = await reviewsService.create({ + userId, createReviewInput, - context, - ); - return result; + }); - expect(result).toEqual(EXAMPLE_REVIEW); - expect( - mockReviewsService.create({ - userId, - createReviewInput, - }), - ).toBeCalled(); + expect(result).toBe(review); + expect(mockRepository.save).toHaveBeenCalled(); + expect(mockRepository.find).toHaveBeenCalled(); + expect(mockShopsService.update).toHaveBeenCalled(); }); }); }); diff --git a/src/apis/reviews/entities/review.entity.ts b/src/apis/reviews/entities/review.entity.ts index b409d8d..f52d162 100644 --- a/src/apis/reviews/entities/review.entity.ts +++ b/src/apis/reviews/entities/review.entity.ts @@ -31,7 +31,7 @@ export class Review { @Field(() => Float) star: number; - @DeleteDateColumn() + @DeleteDateColumn({ nullable: true }) deletedAt: Date; // 예약(own) : 리뷰 = 1 : 1 // FK컬럼이 생기는 곳 = 리뷰 diff --git a/src/apis/reviews/reviews.service.ts b/src/apis/reviews/reviews.service.ts index ca96de7..43320ee 100644 --- a/src/apis/reviews/reviews.service.ts +++ b/src/apis/reviews/reviews.service.ts @@ -67,10 +67,6 @@ export class ReviewsService { }: IReviewServiceCreate): Promise { const shopId = createReviewInput.shopId; - // //리뷰 작성 권한 체크하기 - // // -> 브라우저에서 유저의 권한 여부에 따라 다른 페이지를 보여준다면, create 시 권한 체크는 불필요하지 않은지? - // this.checkReviewAuth({ shopId, userId, reservationCountByUser }); - // 리뷰 저장하기 const result = await this.reviewsRepository.save({ contents: createReviewInput.contents, diff --git a/src/apis/shop-review/__test__/shop-review.resolver.spec.ts b/src/apis/shop-review/__test__/shop-review.resolver.spec.ts new file mode 100644 index 0000000..07571b0 --- /dev/null +++ b/src/apis/shop-review/__test__/shop-review.resolver.spec.ts @@ -0,0 +1,69 @@ +import { Test } from '@nestjs/testing'; +import { AddShopReviewService } from '../shop-review.service'; +import { AddShopReviewResolver } from '../shop-review.resolver'; +import { IContext } from 'src/commons/interface/context'; +import { ShopWithAuthOutput } from '../dto/return-shop-review.output'; +import * as httpMocks from 'node-mocks-http'; + +jest.mock('../shop-review.resolver'); + +const EXAMPLE_SHOP_AUTH: ShopWithAuthOutput = { + id: '1', + name: '1', + phone: '1', + openHour: '1', + closeHour: '1', + address: '1', + code: 123, + lat: '1', + lng: '1', + averageStar: 3, + reservation: null, + image: null, + review: null, + updatedAt: new Date(), + deletedAt: null, + hasReviewAuth: true, +}; + +describe('AddShopReviewResolver', () => { + let addShopReviewService = { + AddShopWithReviewAuth: jest.fn((shopId, context) => EXAMPLE_SHOP_AUTH), + }; + let addShopReviewResolver: AddShopReviewResolver; + let context: IContext; + + beforeEach(async () => { + const moduleRef = await Test.createTestingModule({ + providers: [ + AddShopReviewResolver, + { + provide: AddShopReviewService, + useValue: addShopReviewService, + }, + ], + }).compile(); + addShopReviewResolver = moduleRef.get(AddShopReviewResolver); + addShopReviewService = moduleRef.get(AddShopReviewService); + context = { + req: httpMocks.createRequest(), + res: httpMocks.createResponse(), + }; + }); + + describe('fetchShopWithReviewAuth', () => { + it('로그인되어있다면 AddShopWithReviewAuth 호출해야함', async () => { + let shopId: '1'; + context.req.user = { id: '1', email: 'a@a.com' }; + + const spyFn = jest.spyOn(addShopReviewService, 'AddShopWithReviewAuth'); + const result = await addShopReviewResolver.fetchShopWithReviewAuth( + shopId, + context, + ); + + expect(spyFn).toBeCalled(); + expect(result).toBe(EXAMPLE_SHOP_AUTH); + }); + }); +}); diff --git a/src/apis/shop-review/__test__/shop-review.service.spec.ts b/src/apis/shop-review/__test__/shop-review.service.spec.ts new file mode 100644 index 0000000..90e3ee8 --- /dev/null +++ b/src/apis/shop-review/__test__/shop-review.service.spec.ts @@ -0,0 +1,48 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { ReviewsService } from 'src/apis/reviews/reviews.service'; +import { Shop } from 'src/apis/shops/entities/shop.entity'; +import { ShopsService } from 'src/apis/shops/shops.service'; + +jest.mock('src/apis/shops/shops.service'); +jest.mock('src/apis/reviews/reviews.service'); + +const EXAMPLE_SHOP: Shop = { + id: '1', + name: '1', + phone: '1', + openHour: '1', + closeHour: '1', + address: '1', + code: 123, + lat: '1', + lng: '1', + averageStar: 3, + reservation: null, + image: null, + review: null, + updatedAt: new Date(), + deletedAt: null, +}; + +describe('AddShopReviewService', () => { + let mockShopsRepository = { + find: jest.fn(({ where }) => EXAMPLE_SHOP), + }; + let reviewsService: ReviewsService; + let shopsService: ShopsService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + { + provide: mockShopsRepository, + useValue: mockShopsRepository, + }, + { + provide: reviewsService, + useValue: {}, + }, + ], + }); + }); +}); diff --git a/src/apis/shopImages/__test__/shopImage.resolver.spec.ts b/src/apis/shopImages/__test__/shopImage.resolver.spec.ts index db31ae0..a674cbe 100644 --- a/src/apis/shopImages/__test__/shopImage.resolver.spec.ts +++ b/src/apis/shopImages/__test__/shopImage.resolver.spec.ts @@ -1,123 +1,167 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { MockShopImagesResolver } from './shopImage.moking.dummy'; +import { ShopImagesResolver } from '../shopImage.resolver'; +import { ShopImagesService } from '../shopImage.service'; +import { ShopImage } from '../entities/shopImages.entity'; +import { UpdateShopImageInput } from '../dto/update-shopImage.input'; +import { Shop } from 'src/apis/shops/entities/shop.entity'; -const Example_ShopImage = { +const EXAMPLE_SHOP: Shop = { + id: '1', + name: '1', + phone: '1', + openHour: '1', + closeHour: '1', + address: '1', + code: 123, + lat: '1', + lng: '1', + averageStar: 3, + reservation: null, + image: null, + review: null, + updatedAt: new Date(), + deletedAt: null, +}; + +const EXAMPLE_SHOP_IMAGE: ShopImage = { id: '1e31187d-5c71-4bff-b124-d01081306e07', imageUrl: 'Test-url-222-asdfsadfasdf-asdfsadf', isThumbnail: true, - shop: { - id: '69f836c4-e0e4-4841-960d-2be40d150c44', - }, + shop: EXAMPLE_SHOP, }; -const rightReturn = [ - { - id: '370b960e-55d5-445b-935b-9fdfee36955c', - imageUrl: 'Test-url-111-asdfsadfasdf-asdfsadf', - isThumbnail: false, - shop: { - id: '69f836c4-e0e4-4841-960d-2be40d150c44', - }, - }, - { - id: '1e31187d-5c71-4bff-b124-d01081306e07', - imageUrl: 'Test-url-222-asdfsadfasdf-asdfsadf', - isThumbnail: true, - shop: { - id: '69f836c4-e0e4-4841-960d-2be40d150c44', - }, - }, - { - id: '958472c6-0dea-40c0-b9db-dbfa11cd630e', - imageUrl: 'Test-url-444-asdfsadfasdf-asdfsadf', - isThumbnail: false, - shop: { - id: '69f836c4-e0e4-4841-960d-2be40d150c44', - }, - }, -]; - -describe('shopImagesResolver', () => { - let mockShopImagesResolver: MockShopImagesResolver; + +describe('ShopImagesResolver', () => { + let shopImagesResolver: ShopImagesResolver; + let shopImagesService: ShopImagesService; beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ + const moduleRef = await Test.createTestingModule({ providers: [ + ShopImagesResolver, { - provide: MockShopImagesResolver, - useClass: MockShopImagesResolver, + provide: ShopImagesService, + useValue: { + findThumbnailByShopId: jest.fn(), + findByShopId: jest.fn(), + save: jest.fn(), + update: jest.fn(), + delete: jest.fn(), + }, }, ], }).compile(); - mockShopImagesResolver = module.get(MockShopImagesResolver); + + shopImagesResolver = moduleRef.get(ShopImagesResolver); + shopImagesService = moduleRef.get(ShopImagesService); }); describe('fetchThumbnailByShop', () => { - it('가게이미지 중 썸네일 리턴해야함', async () => { - const shopId = Example_ShopImage.shop.id; - const myThumbnail = await mockShopImagesResolver.findThumbnailByShopId({ - shopId, - }); - expect(myThumbnail.isThumbnail).toEqual(true); + it('썸네일 이미지 리턴해야함', async () => { + const shopImageMock: ShopImage = { + id: '1', + imageUrl: 'https://test.com/image.jpg', + isThumbnail: true, + shop: EXAMPLE_SHOP, + }; + jest + .spyOn(shopImagesService, 'findThumbnailByShopId') + .mockResolvedValueOnce(shopImageMock); + + const result = await shopImagesResolver.fetchThumbnailByShop('1'); + + expect(result).toBe(shopImageMock); }); }); describe('fetchShopImagesByShop', () => { - it('가게이미지 배열 리턴해야함', async () => { - const shopId = Example_ShopImage.shop.id; - const result = await mockShopImagesResolver.findByShopId({ - shopId, - }); + it('ShopImage 배열 리턴해야함', async () => { + const shopImagesMock: ShopImage[] = [ + { + id: '1', + imageUrl: 'https://test.com/image1.jpg', + isThumbnail: true, + shop: EXAMPLE_SHOP, + }, + { + id: '2', + imageUrl: 'https://test.com/image2.jpg', + isThumbnail: false, + shop: EXAMPLE_SHOP, + }, + ]; + jest + .spyOn(shopImagesService, 'findByShopId') + .mockResolvedValueOnce(shopImagesMock); - expect(result).toMatchObject(rightReturn); + const result = await shopImagesResolver.fetchShopImagesByShop('1'); + + expect(result).toEqual(shopImagesMock); }); }); describe('createShopImage', () => { - it('생성한 가게이미지 리턴해야함', async () => { - const input = Example_ShopImage; - const result = await mockShopImagesResolver.save({ - imageUrl: Example_ShopImage.imageUrl, - isThumbnail: Example_ShopImage.isThumbnail, - shopId: Example_ShopImage.shop.id, - }); - - expect(result).toHaveProperty('id'); - expect(result).toHaveProperty('imageUrl'); - expect(result).toHaveProperty('isThumbnail'); - expect(result).toHaveProperty('shop'); + it('새로 생성한 ShopImage 리턴해야함', async () => { + const input = { + imageUrl: 'https://test.com/image.jpg', + isThumbnail: true, + shopId: EXAMPLE_SHOP.id, + }; + const shopImageMock: ShopImage = { + id: '1', + imageUrl: input.imageUrl, + isThumbnail: input.isThumbnail, + shop: EXAMPLE_SHOP, + }; + jest + .spyOn(shopImagesService, 'save') + .mockResolvedValueOnce(shopImageMock); + + const result = await shopImagesResolver.createShopImage( + input.imageUrl, + input.isThumbnail, + input.shopId, + ); + + expect(result).toBe(shopImageMock); }); }); describe('updateShopImage', () => { - it('업데이트한 가게이미지 리턴해야함', async () => { - const updateShopImageInput = Example_ShopImage; - const result = await mockShopImagesResolver.updateShopImage({ - updateShopImageInput, - }); - - expect(result).toHaveProperty('id'); - expect(result).toHaveProperty('imageUrl'); - expect(result).toHaveProperty('isThumbnail'); - expect(result).toHaveProperty('shop'); + const mockShopImage: ShopImage = { + id: '123', + imageUrl: 'https://example.com/image.png', + isThumbnail: true, + shop: EXAMPLE_SHOP, + }; + + const mockUpdateShopImageInput: UpdateShopImageInput = { + id: '123', + imageUrl: 'https://example.com/image.png', + isThumbnail: true, + shopId: EXAMPLE_SHOP.id, + }; + + jest.spyOn(shopImagesService, 'update').mockResolvedValue(mockShopImage); + + it('업데이트한 ShopImage 리턴해야함', async () => { + const result = await shopImagesResolver.updateShopImage( + mockUpdateShopImageInput, + ); + expect(result).toEqual(mockShopImage); }); }); describe('deleteShopImage', () => { - it('boolean 리턴해야함', async () => { - const input = Example_ShopImage; - const removeIdx = mockShopImagesResolver.mydb.findIndex( - (el) => el.id === input.id, - ); + it('삭제 후 true 리턴해아함', async () => { + const shopImageId = 'abc123'; + const expectedResult = true; - if (removeIdx !== -1) { - mockShopImagesResolver.mydb.splice(removeIdx, 1); - } + jest.spyOn(shopImagesService, 'delete').mockResolvedValue(expectedResult); - const result = mockShopImagesResolver.mydb.some( - (el) => el.id === input.id, - ); + const result = await shopImagesResolver.deleteShopImage(shopImageId); - expect(result).toBe(false); + expect(shopImagesService.delete).toHaveBeenCalledWith({ shopImageId }); + expect(result).toEqual(expectedResult); }); }); }); diff --git a/src/apis/shopImages/__test__/shopImage.service.spec.ts b/src/apis/shopImages/__test__/shopImage.service.spec.ts index d5d4294..049c17b 100644 --- a/src/apis/shopImages/__test__/shopImage.service.spec.ts +++ b/src/apis/shopImages/__test__/shopImage.service.spec.ts @@ -100,8 +100,8 @@ describe('shopImagesService', () => { try { await checkShop({ shopId }); } catch (error) { - throw new UnprocessableEntityException(); expect(error).toBeInstanceOf(UnprocessableEntityException); + throw new UnprocessableEntityException(); } const result = mockShopImagesRepository.find({ @@ -118,8 +118,8 @@ describe('shopImagesService', () => { try { await checkURL({ shopId }); } catch (error) { - throw new ConflictException(); expect(error).toBeInstanceOf(ConflictException); + throw new ConflictException(); } const result = mockShopImagesRepository.save({ @@ -165,8 +165,8 @@ describe('shopImagesService', () => { try { await checkImage({ shopId }); } catch (error) { - throw new UnprocessableEntityException('아이디를 찾을 수 없습니다'); expect(error).toThrow(UnprocessableEntityException); + throw new UnprocessableEntityException('아이디를 찾을 수 없습니다'); } const result = await mockShopImagesRepository.delete({ shopImageId, diff --git a/src/apis/shopImages/__test__/shopImage.service2.spec.ts b/src/apis/shopImages/__test__/shopImage.service2.spec.ts new file mode 100644 index 0000000..cf89454 --- /dev/null +++ b/src/apis/shopImages/__test__/shopImage.service2.spec.ts @@ -0,0 +1,175 @@ +import { + ConflictException, + UnprocessableEntityException, +} from '@nestjs/common'; +import { getRepositoryToken } from '@nestjs/typeorm'; +import { Test } from '@nestjs/testing'; +import { Repository } from 'typeorm'; +import { ShopImagesService } from '../shopImage.service'; +import { ShopImage } from '../entities/shopImages.entity'; +import { Shop } from 'src/apis/shops/entities/shop.entity'; + +jest.mock('../shopImage.service'); + +const EXAMPLE_SHOP: Shop = { + id: '1', + name: '1', + phone: '1', + openHour: '1', + closeHour: '1', + address: '1', + code: 123, + lat: '1', + lng: '1', + averageStar: 3, + reservation: null, + image: null, + review: null, + updatedAt: new Date(), + deletedAt: null, +}; + +const EXAMPLE_SHOP_IMAGE: ShopImage = { + id: '1e31187d-5c71-4bff-b124-d01081306e07', + imageUrl: 'Test-url-222-asdfsadfasdf-asdfsadf', + isThumbnail: true, + shop: EXAMPLE_SHOP, +}; + +const shopId = EXAMPLE_SHOP.id; + +describe('ShopImagesService', () => { + let shopImagesService: ShopImagesService; + let mockRepository: jest.Mocked>; + + beforeEach(async () => { + const module = await Test.createTestingModule({ + providers: [ + ShopImagesService, + { + provide: getRepositoryToken(ShopImage), + useValue: { + findOne: jest.fn(), + find: jest.fn(), + save: jest.fn(), + delete: jest.fn(), + }, + }, + ], + }).compile(); + + shopImagesService = module.get(ShopImagesService); + mockRepository = module.get(getRepositoryToken(ShopImage)); + }); + + describe('findThumbnailByShopId', () => { + it('썸네일 이미지 리턴해야함', async () => { + const mockShopImage = new ShopImage(); + jest + .spyOn(mockRepository, 'findOne') + .mockResolvedValueOnce(mockShopImage); + + await shopImagesService.findThumbnailByShopId({ shopId }); + + expect(mockRepository.findOne).toBeCalled(); + }); + + it('썸네일이 없으면 UnprocessableEntityException 던져야 함', async () => { + jest.spyOn(mockRepository, 'findOne').mockResolvedValueOnce(undefined); + + expect(mockRepository.findOne).toBeCalled(); + }); + }); + + describe('findByShopId', () => { + it('한 가게의 모든 이미지 배열 리턴해야함', async () => { + const mockShopImages = [new ShopImage()]; + jest + .spyOn(shopImagesService, 'findByShopId') + .mockResolvedValueOnce(mockShopImages); + jest.spyOn(mockRepository, 'find').mockResolvedValueOnce(mockShopImages); + + const result = await shopImagesService.findByShopId({ shopId }); + + expect(result).toEqual(mockShopImages); + expect(shopImagesService.findByShopId).toHaveBeenCalledWith({ shopId }); + expect(mockRepository.find).toHaveBeenCalledWith({ + where: { shop: { id: 1 } }, + }); + }); + + it('가게를 찾을 수 없는 경우 UnprocessableEntityException 던져야함', async () => { + jest + .spyOn(shopImagesService, 'findByShopId') + .mockResolvedValueOnce(undefined); + + await expect(shopImagesService.findByShopId({ shopId })).rejects.toThrow( + UnprocessableEntityException, + ); + expect(shopImagesService.findByShopId).toHaveBeenCalledWith({ shopId }); + }); + }); + + describe('save', () => { + it('DB테이블에 신규 이미지 저장', async () => { + const checkURL = jest.fn(({ shopId }) => EXAMPLE_SHOP_IMAGE); + try { + const shopId = EXAMPLE_SHOP_IMAGE.shop.id; + await checkURL({ shopId }); + } catch (error) { + expect(error).toBeInstanceOf(ConflictException); + throw new ConflictException(); + } + + const result = mockRepository.save({ + imageUrl: EXAMPLE_SHOP_IMAGE.imageUrl, + isThumbnail: EXAMPLE_SHOP_IMAGE.isThumbnail, + shop: { id: EXAMPLE_SHOP_IMAGE.shop.id }, + }); + + expect(checkURL).toBeCalledTimes(1); + expect(result).toHaveProperty('id'); + expect(result).toHaveProperty('imageUrl'); + expect(result).toHaveProperty('isThumbnail'); + expect(result).toHaveProperty('shop'); + }); + }); + + const updateShopImageInput = { + imageUrl: EXAMPLE_SHOP_IMAGE.imageUrl, + isThumbnail: EXAMPLE_SHOP_IMAGE.isThumbnail, + shop: { id: EXAMPLE_SHOP_IMAGE.shop.id }, + }; + const shopImageId = EXAMPLE_SHOP_IMAGE.id; + + describe('update', () => { + it('delete를 실행한 뒤 save를 실행한다', async () => { + const shopImageId = EXAMPLE_SHOP_IMAGE.id; + await mockRepository.delete(shopImageId); + const result = mockRepository.save({ + imageUrl: EXAMPLE_SHOP_IMAGE.imageUrl, + isThumbnail: EXAMPLE_SHOP_IMAGE.isThumbnail, + shop: { id: EXAMPLE_SHOP_IMAGE.shop.id }, + }); + expect(result).toHaveProperty('id'); + expect(result).toHaveProperty('imageUrl'); + expect(result).toHaveProperty('isThumbnail'); + expect(result).toHaveProperty('shop'); + }); + }); + + const checkImage = jest.fn(({ shopId }) => EXAMPLE_SHOP_IMAGE); + describe('delete', () => { + it('checkImage 통과 후 delete 실행', async () => { + try { + await checkImage({ shopId }); + } catch (error) { + expect(error).toThrow(UnprocessableEntityException); + throw new UnprocessableEntityException('아이디를 찾을 수 없습니다'); + } + const result = await mockRepository.delete(shopImageId); + expect(checkImage).toBeCalled(); + expect(result).toEqual(true); + }); + }); +});