From 3155de2fada7d464a9ceb06b0143b90bae109d96 Mon Sep 17 00:00:00 2001 From: jeongmin Date: Wed, 22 Nov 2023 18:10:04 +0900 Subject: [PATCH 1/7] =?UTF-8?q?Fix:=20#104=20=EC=9D=BC=EA=B8=B0=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20=EC=8B=9C=20=EC=98=AC=EB=B0=94=EB=A5=B8=20?= =?UTF-8?q?user,=20shape=20=EC=A0=95=EB=B3=B4=EB=A1=9C=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - @GetUser 데코레이터를 사용하여 User 정보 가져오도록 추가 - shapeUuid에 해당하는 shape 객체 추가 --- BE/src/diaries/diaries.controller.ts | 6 +++++- BE/src/diaries/diaries.repository.ts | 6 +++--- BE/src/diaries/diaries.service.ts | 4 +++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/BE/src/diaries/diaries.controller.ts b/BE/src/diaries/diaries.controller.ts index e21dbfb..8116472 100644 --- a/BE/src/diaries/diaries.controller.ts +++ b/BE/src/diaries/diaries.controller.ts @@ -33,8 +33,12 @@ export class DiariesController { @HttpCode(201) async writeDiary( @Body() createDiaryDto: CreateDiaryDto, + @GetUser() user: User, ): Promise { - const diary: Diary = await this.diariesService.writeDiary(createDiaryDto); + const diary: Diary = await this.diariesService.writeDiary( + createDiaryDto, + user, + ); return { uuid: diary.uuid }; } diff --git a/BE/src/diaries/diaries.repository.ts b/BE/src/diaries/diaries.repository.ts index 868d247..73dcdd6 100644 --- a/BE/src/diaries/diaries.repository.ts +++ b/BE/src/diaries/diaries.repository.ts @@ -16,17 +16,17 @@ export class DiariesRepository { createDiaryDto: CreateDiaryDto, encodedContent: string, tags: Tag[], + user: User, ): Promise { - const { title, point, date } = createDiaryDto; + const { title, point, date, shapeUuid } = createDiaryDto; const content = encodedContent; + const shape = await Shape.findOne({ where: { uuid: shapeUuid } }); // 미구현 기능을 대체하기 위한 임시 값 const positiveRatio = 0.0; const negativeRatio = 100.0; const neutralRatio = 0.0; const sentiment = sentimentStatus.NEUTRAL; - const shape = await Shape.findOne({ where: { id: 1 } }); - const user = await User.findOne({ where: { id: 1 } }); const newDiary = Diary.create({ title, diff --git a/BE/src/diaries/diaries.service.ts b/BE/src/diaries/diaries.service.ts index cfc1ea5..1efb5c4 100644 --- a/BE/src/diaries/diaries.service.ts +++ b/BE/src/diaries/diaries.service.ts @@ -9,6 +9,7 @@ import { import { TagsRepository } from "src/tags/tags.repository"; import { Tag } from "src/tags/tags.entity"; import { ReadDiaryDto } from "./dto/diaries.read.dto"; +import { User } from "src/users/users.entity"; @Injectable() export class DiariesService { @@ -17,7 +18,7 @@ export class DiariesService { private tagsRepository: TagsRepository, ) {} - async writeDiary(createDiaryDto: CreateDiaryDto): Promise { + async writeDiary(createDiaryDto: CreateDiaryDto, user: User): Promise { const encodedContent = btoa(createDiaryDto.content); const tags = []; @@ -36,6 +37,7 @@ export class DiariesService { createDiaryDto, encodedContent, tags, + user, ); return diary; From e6f9a99e079905ac861a0284000f62a3b5349cf0 Mon Sep 17 00:00:00 2001 From: jeongmin Date: Wed, 22 Nov 2023 20:56:27 +0900 Subject: [PATCH 2/7] =?UTF-8?q?Refactro:=20DTO=20=EC=83=81=EC=86=8D=20?= =?UTF-8?q?=EA=B4=80=EA=B3=84=20=EC=84=A4=EC=A0=95=20=EB=B0=8F=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EA=B2=80?= =?UTF-8?q?=EC=82=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - UpdateDiaryDto가 CreateDiaryDto를 상속받도록 수정 - 데코레이터로 데이터 유효성 검사 추가 --- BE/src/diaries/dto/diaries.dto.ts | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/BE/src/diaries/dto/diaries.dto.ts b/BE/src/diaries/dto/diaries.dto.ts index ccdd905..3d871da 100644 --- a/BE/src/diaries/dto/diaries.dto.ts +++ b/BE/src/diaries/dto/diaries.dto.ts @@ -35,34 +35,15 @@ export class CreateDiaryDto { shapeUuid: string; } -export class UpdateDiaryDto { - @IsUUID() +export class UpdateDiaryDto extends CreateDiaryDto { + @IsUUID("4", { message: "일기 uuid 값이 uuid 양식이어야 합니다." }) + @IsNotEmpty({ message: "일기 uuid는 비어있지 않아야 합니다." }) uuid: string; - - @IsString() - title: string; - - @IsString() - content: string; - - @IsString() - @Matches(/^-?\d+(\.\d+)?,-?\d+(\.\d+)?,-?\d+(\.\d+)?$/, { - message: "적절하지 않은 포인트 양식입니다", - }) - point: string; - - @IsDate() - date: Date; - - @IsArray() - tags: string[]; - - @IsUUID() - shapeUuid: string; } export class DeleteDiaryDto { @IsUUID("4", { message: "일기 uuid 값이 uuid 양식이어야 합니다." }) + @IsNotEmpty({ message: "일기 uuid는 비어있지 않아야 합니다." }) uuid: string; } From 53b12f11735a68bc05614f58f608cc25c5b15046 Mon Sep 17 00:00:00 2001 From: jeongmin Date: Wed, 22 Nov 2023 21:53:18 +0900 Subject: [PATCH 3/7] =?UTF-8?q?Feat:=20JwtStrategy=20=EC=A0=84=EB=9E=B5=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - payload가 없거나, 올바르지 않은 payload이거나 user가 없을 경우 401 에러 - 에러를 내뱉어도 어디서 catch 하는지 의문.. --- BE/src/auth/jwt.strategy.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/BE/src/auth/jwt.strategy.ts b/BE/src/auth/jwt.strategy.ts index 731230b..9294d63 100644 --- a/BE/src/auth/jwt.strategy.ts +++ b/BE/src/auth/jwt.strategy.ts @@ -13,7 +13,15 @@ export class JwtStrategy extends PassportStrategy(Strategy) { }); } - async validate(payload) { + async validate(payload: any): Promise { + if (!payload) { + throw new UnauthorizedException(); + } + + if (!this.isValidPayload(payload)) { + throw new UnauthorizedException(); + } + const { userId } = payload; const user: User = await this.userRepository.getUserByUserId(userId); @@ -22,4 +30,11 @@ export class JwtStrategy extends PassportStrategy(Strategy) { } return user; } + + isValidPayload(payload: any) { + if (typeof payload !== "object") return false; + if (!payload.hasOwnProperty("userId")) return false; + + return true; + } } From f3880592d9373570d2347d5561c65d6705f58f4c Mon Sep 17 00:00:00 2001 From: jeongmin Date: Wed, 22 Nov 2023 21:54:41 +0900 Subject: [PATCH 4/7] =?UTF-8?q?Feat:=20AuthGuard=EB=A5=BC=20=EC=83=81?= =?UTF-8?q?=EC=86=8D=EB=B0=9B=EC=9D=80=20=EC=BB=A4=EC=8A=A4=ED=85=80=20Jwt?= =?UTF-8?q?AuthGuard=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 예외 메시지를 커스텀하기 위해 추가 --- BE/src/auth/guard/auth.diary-guard.ts | 4 ++-- BE/src/auth/guard/auth.jwt-guard.ts | 19 +++++++++++++++++++ BE/src/shapes/shapes.controller.ts | 4 ++-- 3 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 BE/src/auth/guard/auth.jwt-guard.ts diff --git a/BE/src/auth/guard/auth.diary-guard.ts b/BE/src/auth/guard/auth.diary-guard.ts index 155fd69..8286c85 100644 --- a/BE/src/auth/guard/auth.diary-guard.ts +++ b/BE/src/auth/guard/auth.diary-guard.ts @@ -3,11 +3,11 @@ import { Injectable, NotFoundException, } from "@nestjs/common"; -import { AuthGuard } from "@nestjs/passport"; import { DiariesRepository } from "src/diaries/diaries.repository"; +import { JwtAuthGuard } from "./auth.jwt-guard"; @Injectable() -export class PrivateDiaryGuard extends AuthGuard("jwt") { +export class PrivateDiaryGuard extends JwtAuthGuard { constructor(private readonly diariesRepository: DiariesRepository) { super(); } diff --git a/BE/src/auth/guard/auth.jwt-guard.ts b/BE/src/auth/guard/auth.jwt-guard.ts new file mode 100644 index 0000000..ba7ee97 --- /dev/null +++ b/BE/src/auth/guard/auth.jwt-guard.ts @@ -0,0 +1,19 @@ +import { Injectable, UnauthorizedException } from "@nestjs/common"; +import { AuthGuard as NestAuthGuard } from "@nestjs/passport"; + +@Injectable() +export class JwtAuthGuard extends NestAuthGuard("jwt") { + handleRequest(err, user, info: Error) { + if (err || !user) { + if (info.message === "No auth token") { + throw new UnauthorizedException("비로그인 상태의 요청입니다."); + } else if (info.message === "jwt expired") { + throw new UnauthorizedException("토큰이 만료되었습니다."); + } else if (info.message === "invalid token") { + throw new UnauthorizedException("유효하지 않은 토큰입니다."); + } + throw err || new UnauthorizedException("Unauthorized"); + } + return user; + } +} diff --git a/BE/src/shapes/shapes.controller.ts b/BE/src/shapes/shapes.controller.ts index e2ba2db..1e17926 100644 --- a/BE/src/shapes/shapes.controller.ts +++ b/BE/src/shapes/shapes.controller.ts @@ -8,10 +8,10 @@ import { UseGuards, } from "@nestjs/common"; import { ShapesService } from "./shapes.service"; -import { AuthGuard } from "@nestjs/passport"; import { Shape } from "./shapes.entity"; import { GetUser } from "src/auth/get-user.decorator"; import { User } from "src/users/users.entity"; +import { JwtAuthGuard } from "src/auth/guard/auth.jwt-guard"; @Controller("shapes") export class ShapesController { @@ -23,7 +23,7 @@ export class ShapesController { } @Get("/:uuid") - @UseGuards(AuthGuard()) + @UseGuards(JwtAuthGuard) @Header("Content-Type", "image/png") async getShapeFilesByUuid( @Param("uuid") uuid: string, From 29b82a47a37b2ba62a5496ceabba3891d590b31b Mon Sep 17 00:00:00 2001 From: jeongmin Date: Wed, 22 Nov 2023 22:25:53 +0900 Subject: [PATCH 5/7] =?UTF-8?q?Feat:=20=EC=9D=BC=EA=B8=B0=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20=EC=88=98=EC=A0=95=20API=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=9C=20=EC=84=9C=EB=B2=84=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 일기 수정에 대한 부분을 repository에 구현 - 정상적인 요청 시 일기 수정 후 204 응답 - 인증 토큰 관련 오류일 경우 401 응답 - 존재하지 않는 일기 수정 요청일 경우 404 응답 - 데이터 유효성 검사 실패 시 400 응답 --- BE/src/diaries/diaries.controller.ts | 13 +++++++---- BE/src/diaries/diaries.repository.ts | 32 ++++++++++++++++++++++------ BE/src/diaries/diaries.service.ts | 25 ++++++++++++++++++++-- BE/src/diaries/dto/diaries.dto.ts | 1 - 4 files changed, 58 insertions(+), 13 deletions(-) diff --git a/BE/src/diaries/diaries.controller.ts b/BE/src/diaries/diaries.controller.ts index 8116472..d400d02 100644 --- a/BE/src/diaries/diaries.controller.ts +++ b/BE/src/diaries/diaries.controller.ts @@ -17,15 +17,15 @@ import { UpdateDiaryDto, } from "./dto/diaries.dto"; import { Diary } from "./diaries.entity"; -import { AuthGuard } from "@nestjs/passport"; import { ReadDiaryDto, ReadDiaryResponseDto } from "./dto/diaries.read.dto"; import { PrivateDiaryGuard } from "src/auth/guard/auth.diary-guard"; import { GetUser } from "src/auth/get-user.decorator"; import { User } from "src/users/users.entity"; import { Tag } from "src/tags/tags.entity"; +import { JwtAuthGuard } from "src/auth/guard/auth.jwt-guard"; @Controller("diaries") -@UseGuards(AuthGuard()) +@UseGuards(JwtAuthGuard) export class DiariesController { constructor(private diariesService: DiariesService) {} @@ -65,8 +65,13 @@ export class DiariesController { @Put() @UseGuards(PrivateDiaryGuard) - modifyDiary(@Body() updateDiaryDto: UpdateDiaryDto): Promise { - return this.diariesService.modifyDiary(updateDiaryDto); + @HttpCode(204) + async modifyDiary( + @Body() updateDiaryDto: UpdateDiaryDto, + @GetUser() user: User, + ): Promise { + await this.diariesService.modifyDiary(updateDiaryDto, user); + return; } @Delete("/:uuid") diff --git a/BE/src/diaries/diaries.repository.ts b/BE/src/diaries/diaries.repository.ts index 73dcdd6..278b4fa 100644 --- a/BE/src/diaries/diaries.repository.ts +++ b/BE/src/diaries/diaries.repository.ts @@ -61,15 +61,35 @@ export class DiariesRepository { async updateDiary( updateDiaryDto: UpdateDiaryDto, - encodedContent: string, + encryptedContent: string, + tags: Tag[], + user: User, ): Promise { - const { uuid, title, date, shapeUuid } = updateDiaryDto; + const { uuid, title, point, date, shapeUuid } = updateDiaryDto; + const content = encryptedContent; + const shape = await Shape.findOne({ where: { uuid: shapeUuid } }); + + // 미구현 기능을 대체하기 위한 임시 값 + const positiveRatio = 0.0; + const negativeRatio = 100.0; + const neutralRatio = 0.0; + const sentiment = sentimentStatus.NEUTRAL; + const diary = await this.getDiaryByUuid(uuid); - diary.title = title; - diary.date = date; - diary.content = encodedContent; - diary.shape = await Shape.findOne({ where: { uuid: shapeUuid } }); + Object.assign(diary, { + title, + content, + point, + date, + positiveRatio, + negativeRatio, + neutralRatio, + sentiment, + shape, + user, + tags, + }); await diary.save(); return diary; diff --git a/BE/src/diaries/diaries.service.ts b/BE/src/diaries/diaries.service.ts index 1ed473e..991c641 100644 --- a/BE/src/diaries/diaries.service.ts +++ b/BE/src/diaries/diaries.service.ts @@ -91,7 +91,23 @@ export class DiariesService { return diaryList; } - async modifyDiary(updateDiaryDto: UpdateDiaryDto): Promise { + async modifyDiary( + updateDiaryDto: UpdateDiaryDto, + user: User, + ): Promise { + const tags = []; + + await Promise.all( + updateDiaryDto.tags.map(async (tag) => { + if ((await Tag.findOne({ where: { name: tag } })) !== null) { + const tagEntity = await Tag.findOneBy({ name: tag }); + tags.push(tagEntity); + } else { + tags.push(await this.tagsRepository.createTag(tag)); + } + }), + ); + const cipher = createCipheriv( "aes-256-cbc", process.env.CONTENT_SECRET_KEY, @@ -100,7 +116,12 @@ export class DiariesService { let encryptedContent = cipher.update(updateDiaryDto.content, "utf8", "hex"); encryptedContent += cipher.final("hex"); - return this.diariesRepository.updateDiary(updateDiaryDto, encryptedContent); + return this.diariesRepository.updateDiary( + updateDiaryDto, + encryptedContent, + tags, + user, + ); } async deleteDiary(deleteDiaryDto: DeleteDiaryDto): Promise { diff --git a/BE/src/diaries/dto/diaries.dto.ts b/BE/src/diaries/dto/diaries.dto.ts index 3d871da..f75310e 100644 --- a/BE/src/diaries/dto/diaries.dto.ts +++ b/BE/src/diaries/dto/diaries.dto.ts @@ -1,6 +1,5 @@ import { IsString, - IsDate, Matches, IsUUID, IsArray, From 66aa16e0134aef20a2ade0521375a01459b8b83d Mon Sep 17 00:00:00 2001 From: jeongmin Date: Wed, 22 Nov 2023 22:27:15 +0900 Subject: [PATCH 6/7] =?UTF-8?q?Test:=20=EC=9D=BC=EA=B8=B0=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20API=EC=97=90=20=EB=8C=80=ED=95=9C=20e2e=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 정상적인 요청 시 204 응답 - 인증 토큰 관련 오류일 경우 401 응답 - 존재하지 않는 일기 수정 요청일 경우 404 응답 - 데이터 유효성 검사 실패 시 400 응답 --- BE/test/diaries.update.e2e-spec.ts | 329 +++++++++++++++++++++++++++++ 1 file changed, 329 insertions(+) create mode 100644 BE/test/diaries.update.e2e-spec.ts diff --git a/BE/test/diaries.update.e2e-spec.ts b/BE/test/diaries.update.e2e-spec.ts new file mode 100644 index 0000000..5a876f8 --- /dev/null +++ b/BE/test/diaries.update.e2e-spec.ts @@ -0,0 +1,329 @@ +import { Test, TestingModule } from "@nestjs/testing"; +import { INestApplication } from "@nestjs/common"; +import * as request from "supertest"; +import { AppModule } from "../src/app.module"; +import { ValidationPipe } from "@nestjs/common"; +import { UsersRepository } from "src/users/users.repository"; + +describe("[일기 수정] /diaries PUT (e2e)", () => { + let app: INestApplication; + let accessToken: string; + let diaryUuid: string; + let shapeUuid: string; + const userId = "commonUser"; + + beforeAll(async () => { + const moduleFixture: TestingModule = await Test.createTestingModule({ + imports: [AppModule], + providers: [UsersRepository], + }).compile(); + + app = moduleFixture.createNestApplication(); + app.enableCors(); + app.useGlobalPipes(new ValidationPipe()); + + await app.init(); + + const signInPost = await request(app.getHttpServer()) + .post("/auth/signin") + .send({ + userId, + password: process.env.COMMON_USER_PASS, + }); + + accessToken = signInPost.body.accessToken; + + const defaultShapes = await request(app.getHttpServer()) + .get("/shapes/default") + .set("Authorization", `Bearer ${accessToken}`); + shapeUuid = defaultShapes.body[0]["uuid"]; + + const createResponse = await request(app.getHttpServer()) + .post("/diaries") + .set("Authorization", `Bearer ${accessToken}`) + .send({ + shapeUuid, + title: "title", + content: "this is content.", + point: "1.5,5.5,10.55", + date: "2023-11-14", + tags: ["tagTest", "tagTest2"], + }); + + diaryUuid = createResponse.body.uuid; + }); + + afterAll(async () => { + await app.close(); + }); + + it("정상 요청 시 204 No Content 응답", async () => { + await request(app.getHttpServer()) + .put("/diaries") + .set("Authorization", `Bearer ${accessToken}`) + .send({ + uuid: diaryUuid, + shapeUuid, + title: "update title", + content: "this is content!", + point: "1.5,5.5,10.55", + date: "2023-12-14", + tags: ["tagTest", "tagTest2", "tagTest3"], + }) + .expect(204); + + const expectedResponse = { + uuid: diaryUuid, + userId, + shapeUuid, + title: "update title", + content: "this is content!", + date: "2023-12-14T00:00:00.000Z", + emotion: { + positive: 0, + neutral: 0, + negative: 100, + sentiment: "neutral", + }, + coordinate: { + x: 1.5, + y: 5.5, + z: 10.55, + }, + tags: expect.arrayContaining(["tagTest", "tagTest2", "tagTest3"]), + }; + + const postResponse = await request(app.getHttpServer()) + .get(`/diaries/${diaryUuid}`) + .set("Authorization", `Bearer ${accessToken}`) + .expect(200); + + expect(postResponse.body).toEqual(expectedResponse); + }); + + it("액세스 토큰 없이 요청 시 401 Unauthorized 응답", async () => { + await request(app.getHttpServer()) + .put("/diaries") + .send({ + uuid: diaryUuid, + shapeUuid, + title: "update title", + content: "this is content!", + point: "1.5,5.5,10.55", + date: "2023-12-14", + tags: ["tagTest", "tagTest2", "tagTest3"], + }) + .expect(401); + + const postResponse = await request(app.getHttpServer()) + .get(`/diaries/${diaryUuid}`) + .expect(401); + + expect(postResponse.body).toEqual({ + error: "Unauthorized", + message: "비로그인 상태의 요청입니다.", + statusCode: 401, + }); + }); + + it("만료된 토큰 요청 시 401 Unauthorized 응답", async () => { + const expiredToken = + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJjb21tb25Vc2VyIiwiaWF0IjoxNzAwNjUxMDUxLCJleHAiOjE3MDA2NTQ2NTF9.kJlDPs8XICWA8fhuP8rT5lvYqKBsqp86hMmI-txmL54"; + const postResponse = await request(app.getHttpServer()) + .put("/diaries") + .send({ + uuid: diaryUuid, + shapeUuid, + title: "update title", + content: "this is content!", + point: "1.5,5.5,10.55", + date: "2023-12-14", + tags: ["tagTest", "tagTest2", "tagTest3"], + }) + .set("Authorization", `Bearer ${expiredToken}`) + .expect(401); + + expect(postResponse.body).toEqual({ + error: "Unauthorized", + message: "토큰이 만료되었습니다.", + statusCode: 401, + }); + }); + + it("유효하지 않은 토큰 요청 시 401 Unauthorized 응답", async () => { + const expiredToken = + "1yJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJjb21tb25Vc2VyIiwiaWF0IjoxNzAwNjUxMDUxLCJleHAiOjE3MDA2NTQ2NTF9.kJlDPs8XICWA8fhuP8rT5lvYqKBsqp86hMmI-txmL54"; + const postResponse = await request(app.getHttpServer()) + .put("/diaries") + .send({ + uuid: diaryUuid, + shapeUuid, + title: "update title", + content: "this is content!", + point: "1.5,5.5,10.55", + date: "2023-12-14", + tags: ["tagTest", "tagTest2", "tagTest3"], + }) + .set("Authorization", `Bearer ${expiredToken}`) + .expect(401); + + expect(postResponse.body).toEqual({ + error: "Unauthorized", + message: "유효하지 않은 토큰입니다.", + statusCode: 401, + }); + }); + + it("존재하지 않는 일기 조회 요청 시 404 Not Found 응답", async () => { + const postResponse = await request(app.getHttpServer()) + .put("/diaries") + .send({ + uuid: shapeUuid, + shapeUuid, + title: "update title", + content: "this is content!", + point: "1.5,5.5,10.55", + date: "2023-12-14", + tags: ["tagTest", "tagTest2", "tagTest3"], + }) + .set("Authorization", `Bearer ${accessToken}`) + .expect(404); + + expect(postResponse.body).toEqual({ + error: "Not Found", + message: "존재하지 않는 일기입니다.", + statusCode: 404, + }); + }); + + it("빈 값을 포함한 요청 시 400 Bad Request 응답", async () => { + let postResponse; + + // uuid가 없는 경우 + postResponse = await request(app.getHttpServer()) + .put("/diaries") + .send({ + shapeUuid, + title: "title", + content: "this is content.", + date: "2023-11-14", + point: "1.5,5.5,10.55", + tags: ["tagTest", "tagTest2"], + }) + .set("Authorization", `Bearer ${accessToken}`) + .expect(400); + + expect(postResponse.body.message).toContain( + "일기 uuid는 비어있지 않아야 합니다.", + ); + + // 제목이 없는 경우 + postResponse = await request(app.getHttpServer()) + .put("/diaries") + .send({ + uuid: diaryUuid, + shapeUuid, + content: "this is content.", + point: "1.5,5.5,10.55", + date: "2023-11-14", + tags: ["tagTest", "tagTest2"], + }) + .set("Authorization", `Bearer ${accessToken}`) + .expect(400); + + expect(postResponse.body.message).toContain( + "제목은 비어있지 않아야 합니다.", + ); + + // 좌표가 없는 경우 + postResponse = await request(app.getHttpServer()) + .put("/diaries") + .send({ + uuid: diaryUuid, + shapeUuid, + title: "title", + content: "this is content.", + date: "2023-11-14", + tags: ["tagTest", "tagTest2"], + }) + .set("Authorization", `Bearer ${accessToken}`) + .expect(400); + + expect(postResponse.body.message).toContain( + "좌표는 비어있지 않아야 합니다.", + ); + + // 날짜가 없는 경우 + postResponse = await request(app.getHttpServer()) + .put("/diaries") + .send({ + uuid: diaryUuid, + shapeUuid, + title: "title", + content: "this is content.", + point: "1.5,5.5,10.55", + tags: ["tagTest", "tagTest2"], + }) + .set("Authorization", `Bearer ${accessToken}`) + .expect(400); + + expect(postResponse.body.message).toContain( + "날짜는 비어있지 않아야 합니다.", + ); + + // 모양 uuid가 없는 경우 + postResponse = await request(app.getHttpServer()) + .put("/diaries") + .send({ + uuid: diaryUuid, + title: "title", + content: "this is content.", + point: "1.5,5.5,10.55", + date: "2023-11-14", + tags: ["tagTest", "tagTest2"], + }) + .set("Authorization", `Bearer ${accessToken}`) + .expect(400); + + expect(postResponse.body.message).toContain( + "모양 uuid는 비어있지 않아야 합니다.", + ); + + // 복수의 데이터가 없는 경우 + postResponse = await request(app.getHttpServer()) + .put("/diaries") + .send({ + title: "title", + content: "this is content.", + tags: ["tagTest", "tagTest2"], + }) + .set("Authorization", `Bearer ${accessToken}`) + .expect(400); + + expect(postResponse.body.message).toContain( + "날짜는 비어있지 않아야 합니다.", + ); + expect(postResponse.body.message).toContain( + "좌표는 비어있지 않아야 합니다.", + ); + expect(postResponse.body.message).toContain( + "모양 uuid는 비어있지 않아야 합니다.", + ); + }); + + // 유저 회원가입 및 로그인 후 글 생성하고 commonUser에서 해당 글에 대해 조회 요청 보내기 + // it("타인의 일기에 대한 요청 시 404 Not Found 응답", async () => { + // const postResponse = await request(app.getHttpServer()) + // .get(`/diaries/${unauthorizedDiaryUuid}`) + // .set("Authorization", `Bearer ${accessToken}`) + // .expect(404); + + // co + + // expect(postResponse.body).toEqual({ + // error: "Not Found", + // message: "존재하지 않는 일기입니다.", + // statusCode: 404, + // }); + // }); +}); From e341e80a7e1d7230fe62ad0dc929abeaf76cbdab Mon Sep 17 00:00:00 2001 From: jeongmin Date: Wed, 22 Nov 2023 22:28:34 +0900 Subject: [PATCH 7/7] =?UTF-8?q?Refactor:=20test/e2e=20=ED=8F=B4=EB=8D=94?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EA=B5=AC=EC=A1=B0=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BE/test/{ => e2e}/auth.signin.e2e-spec.ts | 2 +- BE/test/{ => e2e}/diaries.create.e2e-spec.ts | 2 +- BE/test/{ => e2e}/diaries.delete.e2e-spec.ts | 2 +- BE/test/{ => e2e}/diaries.read-list.e2e-spec.ts | 2 +- BE/test/{ => e2e}/diaries.read.e2e-spec.ts | 2 +- BE/test/{ => e2e}/diaries.update.e2e-spec.ts | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) rename BE/test/{ => e2e}/auth.signin.e2e-spec.ts (99%) rename BE/test/{ => e2e}/diaries.create.e2e-spec.ts (99%) rename BE/test/{ => e2e}/diaries.delete.e2e-spec.ts (98%) rename BE/test/{ => e2e}/diaries.read-list.e2e-spec.ts (96%) rename BE/test/{ => e2e}/diaries.read.e2e-spec.ts (98%) rename BE/test/{ => e2e}/diaries.update.e2e-spec.ts (99%) diff --git a/BE/test/auth.signin.e2e-spec.ts b/BE/test/e2e/auth.signin.e2e-spec.ts similarity index 99% rename from BE/test/auth.signin.e2e-spec.ts rename to BE/test/e2e/auth.signin.e2e-spec.ts index b15e32b..d95e07f 100644 --- a/BE/test/auth.signin.e2e-spec.ts +++ b/BE/test/e2e/auth.signin.e2e-spec.ts @@ -1,7 +1,7 @@ import { Test, TestingModule } from "@nestjs/testing"; import { INestApplication } from "@nestjs/common"; import * as request from "supertest"; -import { AppModule } from "../src/app.module"; +import { AppModule } from "../../src/app.module"; import { ValidationPipe } from "@nestjs/common"; describe("/auth/signin (e2e)", () => { diff --git a/BE/test/diaries.create.e2e-spec.ts b/BE/test/e2e/diaries.create.e2e-spec.ts similarity index 99% rename from BE/test/diaries.create.e2e-spec.ts rename to BE/test/e2e/diaries.create.e2e-spec.ts index d7a1852..0fb1c1a 100644 --- a/BE/test/diaries.create.e2e-spec.ts +++ b/BE/test/e2e/diaries.create.e2e-spec.ts @@ -1,7 +1,7 @@ import { Test, TestingModule } from "@nestjs/testing"; import { INestApplication } from "@nestjs/common"; import * as request from "supertest"; -import { AppModule } from "../src/app.module"; +import { AppModule } from "../../src/app.module"; import { ValidationPipe } from "@nestjs/common"; describe("AppController (e2e)", () => { diff --git a/BE/test/diaries.delete.e2e-spec.ts b/BE/test/e2e/diaries.delete.e2e-spec.ts similarity index 98% rename from BE/test/diaries.delete.e2e-spec.ts rename to BE/test/e2e/diaries.delete.e2e-spec.ts index d124623..3cd14cd 100644 --- a/BE/test/diaries.delete.e2e-spec.ts +++ b/BE/test/e2e/diaries.delete.e2e-spec.ts @@ -1,7 +1,7 @@ import { Test, TestingModule } from "@nestjs/testing"; import { INestApplication } from "@nestjs/common"; import * as request from "supertest"; -import { AppModule } from "../src/app.module"; +import { AppModule } from "../../src/app.module"; import { ValidationPipe } from "@nestjs/common"; describe("AppController (e2e)", () => { diff --git a/BE/test/diaries.read-list.e2e-spec.ts b/BE/test/e2e/diaries.read-list.e2e-spec.ts similarity index 96% rename from BE/test/diaries.read-list.e2e-spec.ts rename to BE/test/e2e/diaries.read-list.e2e-spec.ts index 31c24b8..f843a0b 100644 --- a/BE/test/diaries.read-list.e2e-spec.ts +++ b/BE/test/e2e/diaries.read-list.e2e-spec.ts @@ -1,7 +1,7 @@ import { Test, TestingModule } from "@nestjs/testing"; import { INestApplication } from "@nestjs/common"; import * as request from "supertest"; -import { AppModule } from "../src/app.module"; +import { AppModule } from "../../src/app.module"; import { ValidationPipe } from "@nestjs/common"; describe("AppController (e2e)", () => { diff --git a/BE/test/diaries.read.e2e-spec.ts b/BE/test/e2e/diaries.read.e2e-spec.ts similarity index 98% rename from BE/test/diaries.read.e2e-spec.ts rename to BE/test/e2e/diaries.read.e2e-spec.ts index 86c9068..f402d91 100644 --- a/BE/test/diaries.read.e2e-spec.ts +++ b/BE/test/e2e/diaries.read.e2e-spec.ts @@ -1,7 +1,7 @@ import { Test, TestingModule } from "@nestjs/testing"; import { INestApplication } from "@nestjs/common"; import * as request from "supertest"; -import { AppModule } from "../src/app.module"; +import { AppModule } from "../../src/app.module"; import { ValidationPipe } from "@nestjs/common"; import { UsersRepository } from "src/users/users.repository"; diff --git a/BE/test/diaries.update.e2e-spec.ts b/BE/test/e2e/diaries.update.e2e-spec.ts similarity index 99% rename from BE/test/diaries.update.e2e-spec.ts rename to BE/test/e2e/diaries.update.e2e-spec.ts index 5a876f8..861e040 100644 --- a/BE/test/diaries.update.e2e-spec.ts +++ b/BE/test/e2e/diaries.update.e2e-spec.ts @@ -1,7 +1,7 @@ import { Test, TestingModule } from "@nestjs/testing"; import { INestApplication } from "@nestjs/common"; import * as request from "supertest"; -import { AppModule } from "../src/app.module"; +import { AppModule } from "../../src/app.module"; import { ValidationPipe } from "@nestjs/common"; import { UsersRepository } from "src/users/users.repository";