Skip to content
Merged
91 changes: 26 additions & 65 deletions src/apis/reviews/__test__/reviews.resolver.spec.ts
Original file line number Diff line number Diff line change
@@ -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',
Expand All @@ -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>(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>(ReviewsResolver);
reviewsService = module.get<ReviewsService>(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();
});
});
});
174 changes: 104 additions & 70 deletions src/apis/reviews/__test__/reviews.service.spec.ts
Original file line number Diff line number Diff line change
@@ -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<Repository<Review>>;
let mockShopsService: jest.Mocked<ShopsService>;

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>(ReviewsResolver);
context = {
req: httpMocks.createRequest(),
res: httpMocks.createResponse(),
};

reviewsService = module.get<ReviewsService>(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();
});
});
});
2 changes: 1 addition & 1 deletion src/apis/reviews/entities/review.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export class Review {
@Field(() => Float)
star: number;

@DeleteDateColumn()
@DeleteDateColumn({ nullable: true })
deletedAt: Date;

// 예약(own) : 리뷰 = 1 : 1 // FK컬럼이 생기는 곳 = 리뷰
Expand Down
4 changes: 0 additions & 4 deletions src/apis/reviews/reviews.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,6 @@ export class ReviewsService {
}: IReviewServiceCreate): Promise<Review> {
const shopId = createReviewInput.shopId;

// //리뷰 작성 권한 체크하기
// // -> 브라우저에서 유저의 권한 여부에 따라 다른 페이지를 보여준다면, create 시 권한 체크는 불필요하지 않은지?
// this.checkReviewAuth({ shopId, userId, reservationCountByUser });

// 리뷰 저장하기
const result = await this.reviewsRepository.save({
contents: createReviewInput.contents,
Expand Down
Loading