diff --git a/frontend/reply-module/src/__test__/fixture/User.ts b/frontend/reply-module/src/__test__/fixture/User.ts new file mode 100644 index 000000000..e892eaf35 --- /dev/null +++ b/frontend/reply-module/src/__test__/fixture/User.ts @@ -0,0 +1,39 @@ +import { User } from "../../types/user"; + +import defaultUserImage from "../../assets/svg/default-user-image.svg"; + +export const socialLoginUser: User = { + id: 1, + nickName: "고니", + profileImageUrl: defaultUserImage, + type: "SocialLoginUser", + createdDate: new Date().toDateString(), + modifiedDate: new Date().toDateString() +}; + +export const socialLoginUser2: User = { + id: 2, + nickName: "도비", + profileImageUrl: defaultUserImage, + type: "SocialLoginUser", + createdDate: new Date().toDateString(), + modifiedDate: new Date().toDateString() +}; + +export const guestUser: User = { + id: 3, + nickName: "고니2", + profileImageUrl: defaultUserImage, + type: "GuestUser", + createdDate: new Date().toDateString(), + modifiedDate: new Date().toDateString() +}; + +export const guestUser2: User = { + id: 4, + nickName: "도비2", + profileImageUrl: defaultUserImage, + type: "GuestUser", + createdDate: new Date().toDateString(), + modifiedDate: new Date().toDateString() +}; diff --git a/frontend/reply-module/src/__test__/fixture/comments.ts b/frontend/reply-module/src/__test__/fixture/comments.ts new file mode 100644 index 000000000..318dab6a4 --- /dev/null +++ b/frontend/reply-module/src/__test__/fixture/comments.ts @@ -0,0 +1,75 @@ +import { Comment } from "../../types"; +import { guestUser, socialLoginUser } from "./user"; + +export const comments: Comment[] = [ + { + id: 1, + content: "첫번째댓글", + user: socialLoginUser, + createdDate: new Date().toDateString(), + modifiedDate: new Date().toDateString() + }, + { + id: 2, + content: "두번째댓글", + user: socialLoginUser, + createdDate: new Date().toDateString(), + modifiedDate: new Date().toDateString() + }, + { + id: 3, + content: "세번째댓글", + user: socialLoginUser, + createdDate: new Date().toDateString(), + modifiedDate: new Date().toDateString() + }, + { + id: 4, + content: "네번째댓글", + user: socialLoginUser, + createdDate: new Date().toDateString(), + modifiedDate: new Date().toDateString() + }, + { + id: 5, + content: "다섯번째댓글", + user: socialLoginUser, + createdDate: new Date().toDateString(), + modifiedDate: new Date().toDateString() + }, + { + id: 6, + content: "여섯번째댓글", + user: guestUser, + createdDate: new Date().toDateString(), + modifiedDate: new Date().toDateString() + }, + { + id: 7, + content: "일곱번째댓글", + user: guestUser, + createdDate: new Date().toDateString(), + modifiedDate: new Date().toDateString() + }, + { + id: 8, + content: "여덟번째댓글", + user: guestUser, + createdDate: new Date().toDateString(), + modifiedDate: new Date().toDateString() + }, + { + id: 9, + content: "아홉번째댓글", + user: guestUser, + createdDate: new Date().toDateString(), + modifiedDate: new Date().toDateString() + }, + { + id: 10, + content: "열번째댓글", + user: guestUser, + createdDate: new Date().toDateString(), + modifiedDate: new Date().toDateString() + } +].sort(() => Math.random() - 0.5); diff --git a/frontend/reply-module/src/__test__/intergration/guestUserComment.test.tsx b/frontend/reply-module/src/__test__/intergration/guestUserComment.test.tsx new file mode 100644 index 000000000..ff6e5e560 --- /dev/null +++ b/frontend/reply-module/src/__test__/intergration/guestUserComment.test.tsx @@ -0,0 +1,198 @@ +import "@testing-library/jest-dom/extend-expect"; +import { fireEvent, render, waitFor } from "@testing-library/react"; +import CommentInput from "../../components/organisms/CommentInput/index"; +import CommentList from "../../components/organisms/CommentList"; +import { useCreateComment, useDeleteComment, useEditComment } from "../../hooks"; +import { Comment } from "../../types"; +import { comments } from "../fixture/comments"; + +jest.mock("../../hooks/useEditComment"); +jest.mock("../../hooks/useDeleteComment"); +jest.mock("../../hooks/useCreateComment"); + +window.alert = function (str) { + console.log(str); + return true; +}; + +window.confirm = function (str) { + console.log(str); + return true; +}; +describe("비로그인 유저 댓글 조회", () => { + beforeEach(() => { + (useEditComment as jest.Mock).mockImplementation(() => { + return { + editComment: () => {}, + isLoading: false, + error: false + }; + }); + + (useDeleteComment as jest.Mock).mockImplementation(() => { + return { + deleteComment: () => {}, + isLoading: false, + error: false + }; + }); + }); + test("비로그인 유저인 경우, 비로그인 유저가 작성한 모든 댓글들에 수정/삭제 옵션이 노출된다.", () => { + const _comments: Comment[] = JSON.parse(JSON.stringify(comments)); + const commentList = render(); + const $$comments = commentList.container.querySelectorAll("section > div:nth-child(2) > div"); + + $$comments.forEach(($comment, index) => { + if (_comments[index].user.type === "GuestUser") { + expect($comment.querySelectorAll("img")[1]).toBeVisible(); + } else { + expect($comment.querySelectorAll("img")[1]).toBe(undefined); + } + }); + }); + + test("비로그인 유저인 경우, 모든 댓글들이 왼쪽에 정렬된다", async () => { + const _comments: Comment[] = JSON.parse(JSON.stringify(comments)); + const commentList = render(); + + await waitFor(() => { + const $$comments = commentList.container.querySelectorAll("section > div:nth-child(2) > div"); + + $$comments.forEach(($comment, index) => { + if (_comments[index].user.type === "GuestUser") { + expect($comment).toHaveStyle("flex-direction: row"); + } + }); + }); + }); +}); + +describe("비로그인 유저 댓글 생성", () => { + beforeEach(() => { + (useCreateComment as jest.Mock).mockImplementation(() => { + return { + createComment: () => {} + }; + }); + }); + test("비로그인 유저인 경우, 댓글 입력에 게스트 비밀번호/이름 입력란이 노출된다.", () => { + const commentInput = render(); + const $commentInputArea = commentInput.container.querySelector("textarea"); + const [$guestNickName, $guestPassword] = Array.from(commentInput.container.querySelectorAll("form input")); + + expect($commentInputArea).toBeVisible(); + expect($guestNickName).toBeVisible(); + expect($guestPassword).toBeVisible(); + }); + + test("비로그인 유저인 경우, 댓글 생성 시 댓글 내용/작성자 이름/비밀번호를 모두 입력해야 댓글을 작성할 수 있다.", async () => { + const commentInput = render(); + const $commentInputArea = commentInput.container.querySelector("textarea") as HTMLElement; + const [$guestNickName, $guestPassword] = Array.from(commentInput.container.querySelectorAll("form input")); + const $submitButton = commentInput.container.querySelector("button") as HTMLButtonElement; + + fireEvent.change($commentInputArea, { target: { value: "댓글 내용" } }); + fireEvent.change($guestNickName, { target: { value: "게스트 이름" } }); + fireEvent.change($guestPassword, { target: { value: "게스트 비밀번호" } }); + + fireEvent.click($submitButton); + + await waitFor(() => { + expect(($commentInputArea as HTMLTextAreaElement).value).toBe(""); + expect(($guestNickName as HTMLInputElement).value).toBe(""); + expect(($guestPassword as HTMLInputElement).value).toBe(""); + }); + + fireEvent.change($commentInputArea, { target: { value: "댓글 내용" } }); + fireEvent.change($guestNickName, { target: { value: "게스트 이름" } }); + fireEvent.change($guestPassword, { target: { value: "게스트 비밀번호" } }); + + fireEvent.click($submitButton); + + await waitFor(() => { + expect(($commentInputArea as HTMLTextAreaElement).value).toBe("댓글 내용"); + expect(($guestNickName as HTMLInputElement).value).toBe("게스트 이름"); + expect(($guestPassword as HTMLInputElement).value).toBe("게스트 비밀번호"); + }); + }); +}); + +describe("비로그인 유저 댓글 수정", () => { + beforeEach(() => { + (useEditComment as jest.Mock).mockImplementation(() => { + return { + editComment: () => {}, + isLoading: false, + error: false + }; + }); + + (useDeleteComment as jest.Mock).mockImplementation(() => { + return { + deleteComment: () => {}, + isLoading: false, + error: false + }; + }); + }); + test("비로그인 유저는 댓글을 수정시, 비밀번호를 입력해야 수정내용 입력란이 활성화 된다.", async () => { + const _comments: Comment[] = JSON.parse(JSON.stringify(comments)); + const guestUserComments = _comments.filter(comment => comment.user.type === "GuestUser"); + const commentList = render(); + + const firstThreeDotButton = commentList.getAllByAltText("댓글 옵션")[0]; + + fireEvent.click(firstThreeDotButton); + + const firstDeleteButton = commentList.getByText("수정"); + fireEvent.click(firstDeleteButton); + + const firstPasswordSubmitButton = commentList.getByText("입력"); + fireEvent.click(firstPasswordSubmitButton); + + await waitFor(() => { + const editConfirmButtons = commentList.getByText("등록"); + expect(editConfirmButtons).toBeVisible(); + }); + }); +}); + +describe("비로그인 유저 댓글 삭제", () => { + beforeEach(() => { + (useEditComment as jest.Mock).mockImplementation(() => { + return { + editComment: () => {}, + isLoading: false, + error: false + }; + }); + + (useDeleteComment as jest.Mock).mockImplementation(() => { + return { + deleteComment: () => {}, + isLoading: false, + error: false + }; + }); + }); + test("비로그인 유저는 댓글을 수정시, 비밀번호를 입력해야 삭제를 할 수 있다.", async () => { + const _comments: Comment[] = JSON.parse(JSON.stringify(comments)); + const guestUserComments = _comments.filter(comment => comment.user.type === "GuestUser"); + const commentList = render(); + + const firstThreeDotButton = commentList.getAllByAltText("댓글 옵션")[0]; + + fireEvent.click(firstThreeDotButton); + + const firstEditButton = commentList.getByText("삭제"); + fireEvent.click(firstEditButton); + + const firstPasswordSubmitButton = commentList.getByText("입력"); + fireEvent.click(firstPasswordSubmitButton); + + await waitFor(() => { + const allThreeDots = commentList.getAllByAltText("댓글 옵션"); + expect(allThreeDots.length).toEqual(guestUserComments.length - 1); + }); + }); +}); diff --git a/frontend/reply-module/src/__test__/intergration/login.test.tsx b/frontend/reply-module/src/__test__/intergration/login.test.tsx index 2072812da..8073b0c3d 100644 --- a/frontend/reply-module/src/__test__/intergration/login.test.tsx +++ b/frontend/reply-module/src/__test__/intergration/login.test.tsx @@ -1,53 +1,47 @@ import "@testing-library/jest-dom/extend-expect"; -import { fireEvent, render, RenderResult, waitFor } from "@testing-library/react"; -import { JSDOM } from "jsdom"; -import CommentPage from "../../components/pages/CommentPage"; -import { useLogin } from "../../hooks"; -import { deleteCookie, getCookie, setCookie } from "../../utils/cookie"; +import { render, waitFor } from "@testing-library/react"; +import UserAvatarOption from "../../components/molecules/UserAvatarOption"; +import { useUser } from "../../hooks"; +import { User } from "../../types/user"; +import { socialLoginUser } from "../fixture/user"; jest.mock("../../hooks"); -global.document = new JSDOM().window.document; - -const login = async (page: RenderResult) => { - page.getByRole("img").click(); - await waitFor(() => { - page - .getByRole("button", { - name: /카카오로 로그인/i - }) - .click(); - }); -}; - -const logout = async (page: RenderResult) => { - page.getByRole("img").click(); - await waitFor(() => { - page - .getByRole("button", { - name: /로그아웃/i - }) - .click(); - }); -}; - describe("댓글모듈 Login 기능", () => { test("로그인이 되어있지 않다면, UserAvatarOption에 로그인 Option이 노출된다.", async () => { - (useLogin as jest.Mock).mockImplementation(() => { + let user: User | undefined = undefined; + + (useUser as jest.Mock).mockImplementation(() => { return { - user: null, - login: () => {}, - logout: () => {} + user, + login: () => { + user = { ...socialLoginUser }; + }, + logout: () => { + user = undefined; + } }; }); - const commentPage = render(); - - commentPage.getByRole("img").click(); + const userAvatarOption = render( + + {user ? ( + + ) : ( + + )} + + ); + + userAvatarOption.getByRole("img").click(); await waitFor(() => { expect( - commentPage.getByRole("button", { + userAvatarOption.getByRole("button", { name: /카카오로 로그인/i }) ).toBeInTheDocument(); @@ -55,63 +49,46 @@ describe("댓글모듈 Login 기능", () => { }); test("로그인 되어있다면, UserAvatarOption에 로그아웃 Option이 노출된다.", async () => { - (useLogin as jest.Mock).mockImplementation(() => { + let user: User | undefined = { ...socialLoginUser }; + + (useUser as jest.Mock).mockImplementation(() => { return { - user: { id: 1, imageURL: "", nickName: "", type: "" }, - login: () => {}, - logout: () => {} + user, + login: () => { + user = { ...socialLoginUser }; + }, + logout: () => { + user = undefined; + } }; }); - const commentPage = render(); - - login(commentPage); + const userAvatarOption = render( + + {user ? ( + + ) : ( + + )} + + ); + + userAvatarOption.getByRole("img").click(); await waitFor(async () => { - commentPage.getByRole("img").click(); + userAvatarOption.getByRole("img").click(); await waitFor(() => { expect( - commentPage.getByRole("button", { + userAvatarOption.getByRole("button", { name: /로그아웃/i }) ).toBeInTheDocument(); }); }); }); - - test("로그인에 성공했다면 cookie에 accessToken이 저장된다.", async () => { - (useLogin as jest.Mock).mockImplementation(() => { - return { - user: null, - login: () => { - setCookie("accessToken", "test"); - }, - logout: () => {} - }; - }); - const commentPage = render(); - - login(commentPage); - - expect(getCookie("accessToken")).toBe("test"); - }); - - test("로그아웃에 성공했다면 cookie에 accessToken이 삭제된다. ", async () => { - (useLogin as jest.Mock).mockImplementation(() => { - return { - user: { id: 1, imageURL: "", nickName: "", type: "" }, - login: () => {}, - logout: () => { - deleteCookie("accessToken"); - } - }; - }); - - const commentPage = render(); - - logout(commentPage); - - expect(getCookie("accessToken")).toBe(null); - }); }); diff --git a/frontend/reply-module/src/__test__/unit/cookie.test.tsx b/frontend/reply-module/src/__test__/unit/cookie.test.tsx deleted file mode 100644 index ef8809557..000000000 --- a/frontend/reply-module/src/__test__/unit/cookie.test.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { JSDOM } from "jsdom"; -import { deleteCookie, getCookie, setCookie } from "../../utils/cookie"; - -global.document = new JSDOM().window.document; - -describe("Cookie Util", () => { - test("쿠키를 저장하고 읽어올 수 있다.", () => { - const cookieKey = "TEST_COOKIE_KEY"; - const cookieValue = "TEST_COOKIE_VALUE"; - - setCookie(cookieKey, cookieValue); - - expect(getCookie(cookieKey)).toBe(cookieValue); - }); - - test("쿠키를 저장하고 삭제할 수 있다.", () => { - const cookieKey = "TEST_COOKIE_KEY"; - const cookieValue = "TEST_COOKIE_VALUE"; - - setCookie(cookieKey, cookieValue); - - expect(getCookie(cookieKey)).toBe(cookieValue); - - deleteCookie(cookieKey); - - expect(getCookie(cookieKey)).toBe(null); - }); -}); diff --git a/frontend/reply-module/src/components/molecules/Comment/index.tsx b/frontend/reply-module/src/components/molecules/Comment/index.tsx index 1484bb738..1092b1dd5 100644 --- a/frontend/reply-module/src/components/molecules/Comment/index.tsx +++ b/frontend/reply-module/src/components/molecules/Comment/index.tsx @@ -137,7 +137,6 @@ const Comment = ({ user, comment, align = "left", shouldShowOption }: Props) => - {console.log(submitType)} {shouldShowOption && !submitType && ( )} diff --git a/frontend/reply-module/src/types/user.ts b/frontend/reply-module/src/types/user.ts index a3bdb1b1d..e792fad50 100644 --- a/frontend/reply-module/src/types/user.ts +++ b/frontend/reply-module/src/types/user.ts @@ -2,7 +2,9 @@ export interface User { id: number; nickName: string; profileImageUrl: string; - type: string; + type: UserType; createdDate: string; modifiedDate: string; } + +export type UserType = "SocialLoginUser" | "GuestUser";