From 190d610e0567266b8fc967446f558fcbc3e86344 Mon Sep 17 00:00:00 2001 From: leegwae Date: Thu, 14 Sep 2023 21:18:05 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20id=20=EB=AA=A8=ED=82=B9=EC=9D=80=20?= =?UTF-8?q?id=20=EC=83=9D=EC=84=B1=20=ED=95=A8=EC=88=98=EC=9D=98=20?= =?UTF-8?q?=EB=B0=98=ED=99=98=EA=B0=92=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=ED=95=9C=EB=8B=A4=20(#413)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../home/__tests__/AccountActionMenu.test.tsx | 92 ++++++----- .../home/__tests__/DeletePanelModal.test.tsx | 53 +++---- .../home/__tests__/PanelItem.test.tsx | 66 ++++---- .../home/__tests__/UpdatePanelModal.test.tsx | 97 ++++++------ .../__tests__/InfiniteQuestionList.test.tsx | 74 +++++---- .../panel/__tests__/PanelHeader.test.tsx | 53 ++++--- .../panel/__tests__/QAModal.test.tsx | 146 ++++++++++++------ src/hooks/queries/__tests__/answer.test.ts | 13 +- src/hooks/queries/__tests__/auth.test.ts | 18 +-- src/hooks/queries/__tests__/panel.test.ts | 4 +- src/hooks/queries/__tests__/question.test.tsx | 40 +++-- .../stores/__test__/useUserStore.test.tsx | 5 +- src/lib/api/__tests__/active-info.test.ts | 6 +- src/lib/api/__tests__/answer.test.ts | 7 +- src/lib/api/__tests__/auth.test.ts | 4 + src/lib/api/__tests__/panel.test.ts | 13 +- src/lib/api/__tests__/question.test.ts | 13 +- src/pages/__tests__/Panel.test.tsx | 37 ++--- src/pages/__tests__/panel-route.test.tsx | 12 +- 19 files changed, 414 insertions(+), 339 deletions(-) diff --git a/src/components/home/__tests__/AccountActionMenu.test.tsx b/src/components/home/__tests__/AccountActionMenu.test.tsx index f20a94ef..9f06bdc4 100644 --- a/src/components/home/__tests__/AccountActionMenu.test.tsx +++ b/src/components/home/__tests__/AccountActionMenu.test.tsx @@ -1,3 +1,5 @@ +import type { UserState } from '@/store/user-store'; + import React from 'react'; import { screen, waitFor } from '@testing-library/react'; @@ -8,33 +10,74 @@ import { MemoryRouter } from 'react-router-dom'; import { AccountActionMenu } from '@/components/home/AccountActionMenu'; import * as authApis from '@/lib/api/auth'; import { renderWithQueryClient } from '@/lib/test-utils'; +import { createMockUser, createMockUserId } from '@/mocks/data/auth'; import { setUserState } from '@/store/user-store'; -const handleClose = vi.fn(); - const navigateMockFn = vi.fn(); vi.mock('react-router-dom', async (importOriginal) => { const router = (await importOriginal()) ?? {}; return { ...router, useNavigate: vi.fn(() => navigateMockFn) }; }); +const handleClose = vi.fn(); +function setup({ user }: { user: UserState }): { + panelButton: HTMLButtonElement; + accountButton: HTMLButtonElement; + logoutButton: HTMLButtonElement; +} { + act(() => { + setUserState(user); + }); + + renderWithQueryClient( + + + , + ); + + const panelButton = screen.getByRole('button', { + name: /내 패널 모아보기/, + }); + const accountButton = screen.getByRole('button', { + name: /내 계정 관리/, + }); + const logoutButton = screen.getByRole('button', { + name: /로그아웃/, + }); + + return { panelButton, accountButton, logoutButton }; +} + describe('AccountActionMenu', () => { it('사용자 이메일과 닉네임을 보여준다', () => { - setup(); + setup({ + user: { + id: createMockUserId(), + email: '이메일', + nickname: '닉네임', + provider: 'LOCAL', + createdAt: new Date().toString(), + updatedAt: new Date().toString(), + }, + }); expect(screen.getByText(/이메일/)).toBeInTheDocument(); expect(screen.getByText(/닉네임/)).toBeInTheDocument(); }); it('내 패널 모아보기 버튼을 누르면 홈 페이지로 이동한다', async () => { - const { panelButton } = setup(); + const { panelButton } = setup({ + user: createMockUser(), + }); await userEvent.click(panelButton); expect(navigateMockFn).toHaveBeenCalledWith('/home'); }); it('내 계정 관리 버튼을 누르면 내 계정 관리 페이지로 이동한다', async () => { - const { accountButton } = setup(); + const { accountButton } = setup({ + user: createMockUser(), + }); await userEvent.click(accountButton); expect(navigateMockFn).toHaveBeenCalledWith('/account'); @@ -44,7 +87,9 @@ describe('AccountActionMenu', () => { const spyOnLogout = vi.spyOn(authApis, 'logout'); it('성공하면 로그인 페이지로 이동한다', async () => { - const { logoutButton } = setup(); + const { logoutButton } = setup({ + user: createMockUser(), + }); await userEvent.click(logoutButton); expect(spyOnLogout).toHaveBeenCalled(); @@ -54,38 +99,3 @@ describe('AccountActionMenu', () => { }); }); }); - -function setup(): { - panelButton: HTMLElement; - accountButton: HTMLElement; - logoutButton: HTMLElement; -} { - act(() => { - setUserState({ - id: -1, - email: '이메일', - nickname: '닉네임', - provider: 'LOCAL', - createdAt: new Date().toString(), - updatedAt: new Date().toString(), - }); - }); - - renderWithQueryClient( - - - , - ); - - const panelButton = screen.getByRole('button', { - name: /내 패널 모아보기/, - }); - const accountButton = screen.getByRole('button', { - name: /내 계정 관리/, - }); - const logoutButton = screen.getByRole('button', { - name: /로그아웃/, - }); - - return { panelButton, accountButton, logoutButton }; -} diff --git a/src/components/home/__tests__/DeletePanelModal.test.tsx b/src/components/home/__tests__/DeletePanelModal.test.tsx index dd8586dd..c4d366d5 100644 --- a/src/components/home/__tests__/DeletePanelModal.test.tsx +++ b/src/components/home/__tests__/DeletePanelModal.test.tsx @@ -2,31 +2,34 @@ import type { Panel } from '@/lib/api/panel'; import React from 'react'; -import { faker } from '@faker-js/faker'; import { screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import * as panelApis from '@/lib/api/panel'; import { renderWithQueryClient } from '@/lib/test-utils'; +import { createMockPanel } from '@/mocks/data/panel'; import { DeletePanelModal } from '../DeletePanelModal'; const handleClose = vi.fn(); -const panel: Panel = { - sid: faker.datatype.uuid(), - title: '테스트 패널 제목', - description: '테스트 패널 설명', - author: { - id: -1, - nickname: '테스트 닉네임', - }, - createdAt: new Date().toDateString(), - updatedAt: new Date().toDateString(), -}; +function setup({ panel }: { panel: Panel }): { + closeButton: HTMLButtonElement; + deleteButton: HTMLButtonElement; +} { + renderWithQueryClient(); + + const closeButton = screen.getByRole('button', { + name: /취소/, + }); + const deleteButton = screen.getByRole('button', { + name: /패널 삭제/, + }); + return { closeButton, deleteButton }; +} describe('DeletePanelModal', () => { it('패널 삭제하기 헤딩을 보여준다', () => { - setup(); + setup({ panel: createMockPanel() }); expect(screen.getByRole('heading')).toHaveTextContent(/패널 삭제하기/); }); @@ -34,7 +37,8 @@ describe('DeletePanelModal', () => { describe('패널 삭제 버튼을 누르면', () => { it('패널 삭제 API를 호출한다', async () => { const spyOnDeletePanel = vi.spyOn(panelApis, 'deletePanel'); - const { deleteButton } = setup(); + const { deleteButton } = setup({ panel: createMockPanel() }); + await userEvent.click(deleteButton); expect(spyOnDeletePanel).toHaveBeenCalled(); @@ -42,7 +46,8 @@ describe('DeletePanelModal', () => { it('패널 삭제 API가 성공 응답 시 close 함수를 호출한다', async () => { const spyOnDeletePanel = vi.spyOn(panelApis, 'deletePanel'); - const { deleteButton } = setup(); + const { deleteButton } = setup({ panel: createMockPanel() }); + await userEvent.click(deleteButton); expect(spyOnDeletePanel).toHaveBeenCalled(); @@ -54,24 +59,10 @@ describe('DeletePanelModal', () => { }); it('취소 버튼을 누르면 close 함수가 호출된다', async () => { - const { closeButton } = setup(); + const { closeButton } = setup({ panel: createMockPanel() }); + await userEvent.click(closeButton); expect(handleClose).toHaveBeenCalled(); }); }); - -function setup(): { - closeButton: HTMLButtonElement; - deleteButton: HTMLButtonElement; -} { - renderWithQueryClient(); - - const closeButton = screen.getByRole('button', { - name: /취소/, - }); - const deleteButton = screen.getByRole('button', { - name: /패널 삭제/, - }); - return { closeButton, deleteButton }; -} diff --git a/src/components/home/__tests__/PanelItem.test.tsx b/src/components/home/__tests__/PanelItem.test.tsx index a486e62c..0e697d24 100644 --- a/src/components/home/__tests__/PanelItem.test.tsx +++ b/src/components/home/__tests__/PanelItem.test.tsx @@ -2,49 +2,15 @@ import type { Panel } from '@/lib/api/panel'; import React from 'react'; -import { faker } from '@faker-js/faker'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { PanelItem } from '@/components/home/PanelItem'; +import { createMockPanel } from '@/mocks/data/panel'; -const panel: Panel = { - sid: faker.datatype.uuid(), - title: '테스트 패널 제목', - description: '테스트 패널 설명', - author: { - id: -1, - nickname: '테스트 닉네임', - }, - createdAt: new Date().toDateString(), - updatedAt: new Date().toDateString(), -}; const handleOpenActionMenu = vi.fn(); const handleTitleClick = vi.fn(); - -describe('PanelItem', () => { - it('패널 제목과 설명을 렌더링한다', () => { - setup(); - expect(screen.getByText(/패널 제목/)).toBeInTheDocument(); - expect(screen.getByText(/패널 설명/)).toBeInTheDocument(); - }); - - it('더보기 아이콘을 누르면 openActionMenu 함수를 호출한다', async () => { - const { moreButton } = setup(); - await userEvent.click(moreButton); - - expect(handleOpenActionMenu).toHaveBeenCalled(); - }); - - it('패널 제목을 누르면 onPanelTitleClick 함수를 호출한다', async () => { - const { titleButton } = setup(); - await userEvent.click(titleButton); - - expect(handleTitleClick).toHaveBeenCalled(); - }); -}); - -function setup(): { +function setup({ panel }: { panel: Panel }): { moreButton: HTMLButtonElement; titleButton: HTMLButtonElement; } { @@ -65,3 +31,31 @@ function setup(): { return { moreButton, titleButton }; } + +describe('PanelItem', () => { + it('패널 제목과 설명을 렌더링한다', () => { + setup({ + panel: { + ...createMockPanel(), + title: '테스트 패널 제목', + description: '테스트 패널 설명', + }, + }); + expect(screen.getByText(/테스트 패널 제목/)).toBeInTheDocument(); + expect(screen.getByText(/테스트 패널 설명/)).toBeInTheDocument(); + }); + + it('더보기 아이콘을 누르면 openActionMenu 함수를 호출한다', async () => { + const { moreButton } = setup({ panel: createMockPanel() }); + await userEvent.click(moreButton); + + expect(handleOpenActionMenu).toHaveBeenCalled(); + }); + + it('패널 제목을 누르면 onPanelTitleClick 함수를 호출한다', async () => { + const { titleButton } = setup({ panel: createMockPanel() }); + await userEvent.click(titleButton); + + expect(handleTitleClick).toHaveBeenCalled(); + }); +}); diff --git a/src/components/home/__tests__/UpdatePanelModal.test.tsx b/src/components/home/__tests__/UpdatePanelModal.test.tsx index 3a9ed42d..1506dd0a 100644 --- a/src/components/home/__tests__/UpdatePanelModal.test.tsx +++ b/src/components/home/__tests__/UpdatePanelModal.test.tsx @@ -3,7 +3,6 @@ import type * as Vi from 'vitest'; import React from 'react'; -import { faker } from '@faker-js/faker'; import { fireEvent, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; @@ -11,6 +10,7 @@ import { UpdatePanelModal } from '@/components/home/UpdatePanelModal'; import * as panelApis from '@/lib/api/panel'; import { renderWithQueryClient } from '@/lib/test-utils'; import { isPanelDescription, isPanelTitle } from '@/lib/validator'; +import { createMockPanel } from '@/mocks/data/panel'; vi.mock('@/lib/validator', () => ({ isPanelTitle: vi.fn(), @@ -18,37 +18,53 @@ vi.mock('@/lib/validator', () => ({ })); const handleClose = vi.fn(); +function setup({ panel }: { panel: Panel }): { + titleInput: HTMLInputElement; + descInput: HTMLInputElement; + closeButton: HTMLButtonElement; + submitButton: HTMLButtonElement; +} { + renderWithQueryClient(); -const panel: Panel = { - sid: faker.datatype.uuid(), - title: '테스트 패널 제목', - description: '테스트 패널 설명', - author: { - id: -1, - nickname: '테스트 닉네임', - }, - createdAt: new Date().toDateString(), - updatedAt: new Date().toDateString(), -}; + const titleInput = screen.getByRole('textbox', { + name: /패널 제목/, + }); + const descInput = screen.getByRole('textbox', { + name: /패널 설명/, + }); + const closeButton = screen.getByRole('button', { + name: /취소/, + }); + const submitButton = screen.getByRole('button', { + name: /패널 수정/, + }); + + return { titleInput, descInput, closeButton, submitButton }; +} describe('UpdatePanelModal', () => { it('패널 수정하기 헤딩을 보여준다', () => { - renderWithQueryClient( - , - ); + setup({ panel: createMockPanel() }); expect(screen.getByRole('heading')).toHaveTextContent(/패널 수정하기/); }); it('패널 수정하기 폼이 초기값을 보여준다', () => { - const { titleInput, descInput } = setup(); + const { titleInput, descInput } = setup({ + panel: { + ...createMockPanel(), + title: '테스트 패널 제목', + description: '테스트 패널 설명', + }, + }); expect(titleInput.value).toBe('테스트 패널 제목'); expect(descInput.value).toBe('테스트 패널 설명'); }); it('취소 버튼을 누르면 close 함수가 호출된다', async () => { - const { closeButton } = setup(); + const { closeButton } = setup({ panel: createMockPanel() }); + await userEvent.click(closeButton); expect(handleClose).toBeCalled(); @@ -56,7 +72,8 @@ describe('UpdatePanelModal', () => { it('유효하지 않은 필드값을 입력하면 에러 메시지를 보여준다', () => { (isPanelTitle as Vi.Mock).mockImplementation(() => false); - const { titleInput } = setup(); + const { titleInput } = setup({ panel: createMockPanel() }); + fireEvent.change(titleInput, { target: { value: '유효하지 않은 패널 제목' }, }); @@ -71,7 +88,9 @@ describe('UpdatePanelModal', () => { (isPanelDescription as Vi.Mock).mockImplementation(() => true); const spyOnUpdatePanel = vi.spyOn(panelApis, 'updatePanel'); - const { titleInput, descInput, submitButton } = setup(); + const panel = createMockPanel(); + const { titleInput, descInput, submitButton } = setup({ panel }); + fireEvent.change(titleInput, { target: { value: '유효한 패널 제목' }, }); @@ -95,40 +114,24 @@ describe('UpdatePanelModal', () => { (isPanelTitle as Vi.Mock).mockImplementation(() => true); (isPanelDescription as Vi.Mock).mockImplementation(() => true); const spyOnUpdatePanel = vi.spyOn(panelApis, 'updatePanel'); - const { titleInput, descInput, submitButton } = setup(); + + const { titleInput, descInput, submitButton } = setup({ + panel: { + ...createMockPanel(), + title: '테스트 패널 제목', + description: '테스트 패널 설명', + }, + }); + fireEvent.change(titleInput, { - target: { value: panel.title }, + target: { value: '테스트 패널 제목' }, }); fireEvent.change(descInput, { - target: { value: panel.description }, + target: { value: '테스트 패널 설명' }, }); - await userEvent.click(submitButton); + expect(spyOnUpdatePanel).not.toHaveBeenCalled(); expect(screen.getByText(/수정된 값을 입력해주세요/)).toBeInTheDocument(); }); }); - -function setup(): { - titleInput: HTMLInputElement; - descInput: HTMLInputElement; - closeButton: HTMLButtonElement; - submitButton: HTMLButtonElement; -} { - renderWithQueryClient(); - - const titleInput = screen.getByRole('textbox', { - name: /패널 제목/, - }); - const descInput = screen.getByRole('textbox', { - name: /패널 설명/, - }); - const closeButton = screen.getByRole('button', { - name: /취소/, - }); - const submitButton = screen.getByRole('button', { - name: /패널 수정/, - }); - - return { titleInput, descInput, closeButton, submitButton }; -} diff --git a/src/components/panel/__tests__/InfiniteQuestionList.test.tsx b/src/components/panel/__tests__/InfiniteQuestionList.test.tsx index d9a78f12..42db66ed 100644 --- a/src/components/panel/__tests__/InfiniteQuestionList.test.tsx +++ b/src/components/panel/__tests__/InfiniteQuestionList.test.tsx @@ -4,7 +4,6 @@ import type { QueryClient } from '@tanstack/react-query'; import React from 'react'; -import { faker } from '@faker-js/faker'; import { fireEvent, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { rest } from 'msw'; @@ -14,19 +13,28 @@ import { apiUrl } from '@/lib/api/apiUrl'; import * as questionApis from '@/lib/api/question'; import { renderWithQueryClient } from '@/lib/test-utils'; import { delay } from '@/lib/test-utils/delay'; +import { createMockPanelId } from '@/mocks/data/panel'; import { createMockQuestion } from '@/mocks/data/question'; import { server } from '@/mocks/server'; vi.mock('@/hooks/useOverlay', () => ({ useOverlay: vi.fn() })); -const panelId: Panel['sid'] = faker.datatype.uuid(); +function setup({ panelId }: { panelId: Panel['sid'] }): { + queryClient: QueryClient; +} { + const { queryClient } = renderWithQueryClient( + , + ); + + return { queryClient }; +} describe('InfiniteQuestionList', () => { describe('질문 목록 렌더링', () => { it('질문 목록 가져오기 API를 호출하고 성공 시 질문 목록을 렌더링한다', async () => { const { questions } = overrideGetQuestionsWithSingleQuestion(); const spyOnGetQuestions = vi.spyOn(questionApis, 'getQuestions'); - setup(); + setup({ panelId: createMockPanelId() }); expect(spyOnGetQuestions).toHaveBeenCalled(); await waitFor(() => { @@ -35,8 +43,10 @@ describe('InfiniteQuestionList', () => { }); it('사용자가 스크롤하면 getQuestions를 호출한다', async () => { - const { waitForFinish } = setup(); - await waitForFinish(); + const { queryClient } = setup({ panelId: createMockPanelId() }); + await waitFor(() => { + expect(queryClient.isFetching()).toBe(0); + }); const spyOnGetQuestions = vi.spyOn(questionApis, 'getQuestions'); fireEvent.scroll(window); @@ -47,8 +57,11 @@ describe('InfiniteQuestionList', () => { describe('질문 목록 정렬', () => { it('최신순 버튼을 누르면 최신순으로 질문 목록 API 호출한다', async () => { - const { waitForFinish } = setup(); - await waitForFinish(); + const panelId: Panel['sid'] = createMockPanelId(); + const { queryClient } = setup({ panelId }); + await waitFor(() => { + expect(queryClient.isFetching()).toBe(0); + }); const spyOnGetQuestions = vi.spyOn(questionApis, 'getQuestions'); const recentButton = screen.getByRole('button', { name: '최신순' }); @@ -61,8 +74,11 @@ describe('InfiniteQuestionList', () => { }); it('좋아요순 버튼 누르면 좋아요순으로 질문 목록 API 호출한다', async () => { - const { waitForFinish } = setup(); - await waitForFinish(); + const panelId: Panel['sid'] = createMockPanelId(); + const { queryClient } = setup({ panelId }); + await waitFor(() => { + expect(queryClient.isFetching()).toBe(0); + }); const spyOnGetQuestions = vi.spyOn(questionApis, 'getQuestions'); const recentButton = screen.getByRole('button', { name: '최신순' }); @@ -78,8 +94,10 @@ describe('InfiniteQuestionList', () => { describe('좋아요 버튼', () => { it('좋아요 버튼을 누르면 질문 좋아요 API 요청한다', async () => { - const { waitForFinish } = setup(); - await waitForFinish(); + const { queryClient } = setup({ panelId: createMockPanelId() }); + await waitFor(() => { + expect(queryClient.isFetching()).toBe(0); + }); const spyOnLikeQuestion = vi.spyOn(questionApis, 'likeQuestion'); const likeButton = screen.getAllByRole('button', { name: /좋아요 / })[0]; @@ -89,8 +107,10 @@ describe('InfiniteQuestionList', () => { }); it('이때 좋아요 API 응답을 기다리지 않고 화면에 토글 결과를 보여준다', async () => { - const { waitForFinish } = setup(); - await waitForFinish(); + const { queryClient } = setup({ panelId: createMockPanelId() }); + await waitFor(() => { + expect(queryClient.isFetching()).toBe(0); + }); const spyOnLikeQuestion = vi.spyOn(questionApis, 'likeQuestion'); const likeButton = screen.getAllByRole('button', { name: /좋아요 / })[0]; @@ -109,8 +129,10 @@ describe('InfiniteQuestionList', () => { statusCode: 400, message: '유효하지 않은 좋아요 활성화 요청입니다.', }); - const { waitForFinish } = setup(); - await waitForFinish(); + const { queryClient } = setup({ panelId: createMockPanelId() }); + await waitFor(() => { + expect(queryClient.isFetching()).toBe(0); + }); const likeButton = screen.getByRole('button', { name: /좋아요 / }); const prevLikeNum = Number(likeButton.textContent); @@ -139,8 +161,10 @@ describe('InfiniteQuestionList', () => { ); }), ); - const { waitForFinish } = setup(); - await waitForFinish(); + const { queryClient } = setup({ panelId: createMockPanelId() }); + await waitFor(() => { + expect(queryClient.isFetching()).toBe(0); + }); const likeButton = screen.getByRole('button', { name: /좋아요 / }); await userEvent.click(likeButton); @@ -151,22 +175,6 @@ describe('InfiniteQuestionList', () => { }); }); -function setup(): { - queryClient: QueryClient; - waitForFinish: () => Promise; -} { - const { queryClient } = renderWithQueryClient( - , - ); - - const waitForFinish = async (): Promise => - waitFor(() => { - expect(queryClient.isFetching()).toBe(0); - }); - - return { queryClient, waitForFinish }; -} - export function overrideLikeQuestionWithError(data: ErrorResponse): void { server.use( rest.post(apiUrl.question.like(':questionId'), async (_, res, ctx) => diff --git a/src/components/panel/__tests__/PanelHeader.test.tsx b/src/components/panel/__tests__/PanelHeader.test.tsx index f6d7e680..79f4cb0a 100644 --- a/src/components/panel/__tests__/PanelHeader.test.tsx +++ b/src/components/panel/__tests__/PanelHeader.test.tsx @@ -11,33 +11,7 @@ import { OverlayProvider } from '@/contexts/OverlayContext'; import { renderWithQueryClient } from '@/lib/test-utils'; import { createMockPanel } from '@/mocks/data/panel'; -const panel: PanelData = createMockPanel(); - -describe('패널 페이지 헤더', () => { - it('패널 이름을 보여준다', () => { - const { title } = setup(); - - expect(title).toHaveTextContent(panel.title); - }); - - it('내 계정 아이콘을 누르면 계정 액션 메뉴를 보여준다', async () => { - const { accountButton } = setup(); - await userEvent.click(accountButton); - - expect(screen.getByRole('dialog', { name: /내 계정 액션 메뉴/ })); - }); - - it('메뉴 아이콘을 누르면 사이드시트를 보여준다', async () => { - const { menuButton } = setup(); - await userEvent.click(menuButton); - - expect( - screen.getByRole('complementary', { name: /메뉴/ }), - ).toBeInTheDocument(); - }); -}); - -function setup(): { +function setup({ panel }: { panel: PanelData }): { title: HTMLHeadingElement; menuButton: HTMLButtonElement; accountButton: HTMLButtonElement; @@ -60,3 +34,28 @@ function setup(): { return { title, menuButton, accountButton }; } + +describe('패널 페이지 헤더', () => { + it('패널 이름을 보여준다', () => { + const panel = createMockPanel(); + const { title } = setup({ panel }); + + expect(title).toHaveTextContent(panel.title); + }); + + it('내 계정 아이콘을 누르면 계정 액션 메뉴를 보여준다', async () => { + const { accountButton } = setup({ panel: createMockPanel() }); + await userEvent.click(accountButton); + + expect(screen.getByRole('dialog', { name: /내 계정 액션 메뉴/ })); + }); + + it('메뉴 아이콘을 누르면 사이드시트를 보여준다', async () => { + const { menuButton } = setup({ panel: createMockPanel() }); + await userEvent.click(menuButton); + + expect( + screen.getByRole('complementary', { name: /메뉴/ }), + ).toBeInTheDocument(); + }); +}); diff --git a/src/components/panel/__tests__/QAModal.test.tsx b/src/components/panel/__tests__/QAModal.test.tsx index 04f20b83..b000951d 100644 --- a/src/components/panel/__tests__/QAModal.test.tsx +++ b/src/components/panel/__tests__/QAModal.test.tsx @@ -7,6 +7,7 @@ import type { GetAnswersResponse, } from '@/lib/api/answer'; import type { Question } from '@/lib/api/question'; +import type { QueryClient } from '@tanstack/react-query'; import type * as Vi from 'vitest'; import React from 'react'; @@ -24,7 +25,10 @@ import { renderWithQueryClient } from '@/lib/test-utils'; import { createMockAnswer } from '@/mocks/data/answer'; import { createMockUser } from '@/mocks/data/auth'; import { createMockPanel } from '@/mocks/data/panel'; -import { createMockQuestion } from '@/mocks/data/question'; +import { + createMockQuestion, + createMockQuestionId, +} from '@/mocks/data/question'; import { server } from '@/mocks/server'; vi.mock('react-router-dom', async (importOriginal) => { @@ -37,14 +41,36 @@ vi.mock('@/hooks/stores/useUserStore', () => ({ })); const handleClose = vi.fn(); -const isActived = true; const handleLikeButtonClick = vi.fn(); +function setup({ + questionId, + isActived, +}: { + questionId: Question['id']; + isActived: boolean; +}): { + queryClient: QueryClient; +} { + const { queryClient } = renderWithQueryClient( + , + ); -const questionId: Question['id'] = -1; + return { queryClient }; +} describe('QAModal', () => { it('<- 아이콘을 누르면 close 함수가 호출된다', async () => { - const { waitForFetching } = setup(); - await waitForFetching(); + const { queryClient } = setup({ + questionId: createMockQuestionId(), + isActived: true, + }); + await waitFor(() => { + expect(queryClient.isFetching()).toBe(0); + }); const goBackButton = screen.getByRole('button', { name: /뒤로 가기/ }); await userEvent.click(goBackButton); @@ -83,9 +109,14 @@ describe('QAModal', () => { ), ); - const { waitForFetching } = setup(); + const { queryClient } = setup({ + questionId: createMockQuestionId(), + isActived: true, + }); expect(spyOnGetAnswers).toHaveBeenCalled(); - await waitForFetching(); + await waitFor(() => { + expect(queryClient.isFetching()).toBe(0); + }); expect(screen.getByText('질문이다')).toBeInTheDocument(); expect(screen.getByText('답변이다')).toBeInTheDocument(); @@ -96,8 +127,13 @@ describe('QAModal', () => { const panel = createMockPanel(); (useRouteLoaderData as Vi.Mock).mockImplementation(() => panel); (useUserStore as Vi.Mock).mockImplementation(() => panel.author.id); - const { waitForFetching } = setup(); - await waitForFetching(); + const { queryClient } = setup({ + questionId: createMockQuestionId(), + isActived: true, + }); + await waitFor(() => { + expect(queryClient.isFetching()).toBe(0); + }); const expandFormButton = screen.getByRole('button', { name: /답변 생성 폼/, @@ -110,8 +146,13 @@ describe('QAModal', () => { const panel = createMockPanel(); (useRouteLoaderData as Vi.Mock).mockImplementation(() => panel); (useUserStore as Vi.Mock).mockImplementation(() => panel.author.id + 1); - const { waitForFetching } = setup(); - await waitForFetching(); + const { queryClient } = setup({ + questionId: createMockQuestionId(), + isActived: true, + }); + await waitFor(() => { + expect(queryClient.isFetching()).toBe(0); + }); expect( screen.queryByRole('button', { @@ -124,8 +165,13 @@ describe('QAModal', () => { const panel = createMockPanel(); (useRouteLoaderData as Vi.Mock).mockImplementation(() => panel); (useUserStore as Vi.Mock).mockImplementation(() => panel.author.id); - const { waitForFetching } = setup(); - await waitForFetching(); + const { queryClient } = setup({ + questionId: createMockQuestionId(), + isActived: true, + }); + await waitFor(() => { + expect(queryClient.isFetching()).toBe(0); + }); const formContainer = screen.getByRole('button', { name: /답변 생성 폼 열기/, @@ -141,8 +187,13 @@ describe('QAModal', () => { const panel = createMockPanel(); (useRouteLoaderData as Vi.Mock).mockImplementation(() => panel); (useUserStore as Vi.Mock).mockImplementation(() => panel.author.id); - const { waitForFetching } = setup(); - await waitForFetching(); + const { queryClient } = setup({ + questionId: createMockQuestionId(), + isActived: true, + }); + await waitFor(() => { + expect(queryClient.isFetching()).toBe(0); + }); const formContainer = screen.getByRole('button', { name: /답변 생성 폼 열기/, @@ -159,8 +210,13 @@ describe('QAModal', () => { const panel = createMockPanel(); (useRouteLoaderData as Vi.Mock).mockImplementation(() => panel); (useUserStore as Vi.Mock).mockImplementation(() => panel.author.id); - const { waitForFetching } = setup(); - await waitForFetching(); + const { queryClient } = setup({ + questionId: createMockQuestionId(), + isActived: true, + }); + await waitFor(() => { + expect(queryClient.isFetching()).toBe(0); + }); const formContainer = screen.getByRole('button', { name: /답변 생성 폼 열기/, @@ -176,8 +232,13 @@ describe('QAModal', () => { const panel = createMockPanel(); (useRouteLoaderData as Vi.Mock).mockImplementation(() => panel); (useUserStore as Vi.Mock).mockImplementation(() => panel.author.id); - const { waitForFetching } = setup(); - await waitForFetching(); + const { queryClient } = setup({ + questionId: createMockQuestionId(), + isActived: true, + }); + await waitFor(() => { + expect(queryClient.isFetching()).toBe(0); + }); const formContainer = screen.getByRole('button', { name: /답변 생성 폼 열기/, @@ -196,8 +257,13 @@ describe('QAModal', () => { const panel = createMockPanel(); (useRouteLoaderData as Vi.Mock).mockImplementation(() => panel); (useUserStore as Vi.Mock).mockImplementation(() => panel.author.id); - const { waitForFetching } = setup(); - await waitForFetching(); + const { queryClient } = setup({ + questionId: createMockQuestionId(), + isActived: true, + }); + await waitFor(() => { + expect(queryClient.isFetching()).toBe(0); + }); const formContainer = screen.getByRole('button', { name: /답변 생성 폼 열기/, @@ -210,6 +276,7 @@ describe('QAModal', () => { }); it('답변 제출하면 일단 화면에 보여준다', async () => { + const questionId = createMockQuestionId(); const answers: Answer[] = []; server.use( rest.get( @@ -256,8 +323,13 @@ describe('QAModal', () => { (useRouteLoaderData as Vi.Mock).mockImplementation(() => panel); (useUserStore as Vi.Mock).mockImplementation(() => panel.author.id); - const { waitForFetching } = setup(); - await waitForFetching(); + const { queryClient } = setup({ + questionId, + isActived: true, + }); + await waitFor(() => { + expect(queryClient.isFetching()).toBe(0); + }); const formContainer = screen.getByRole('button', { name: /답변 생성 폼 열기/, }); @@ -279,8 +351,13 @@ describe('QAModal', () => { (useRouteLoaderData as Vi.Mock).mockImplementation(() => panel); (useUserStore as Vi.Mock).mockImplementation(() => panel.author.id); - const { waitForFetching } = setup(); - await waitForFetching(); + const { queryClient } = setup({ + questionId: createMockQuestionId(), + isActived: true, + }); + await waitFor(() => { + expect(queryClient.isFetching()).toBe(0); + }); const formContainer = screen.getByRole('button', { name: /답변 생성 폼 열기/, }); @@ -299,22 +376,3 @@ describe('QAModal', () => { }); }); }); - -function setup(): { - waitForFetching: () => Promise; -} { - const { queryClient } = renderWithQueryClient( - , - ); - - const waitForFetching = async (): Promise => - waitFor(() => { - expect(queryClient.isFetching()).toBe(0); - }); - return { waitForFetching }; -} diff --git a/src/hooks/queries/__tests__/answer.test.ts b/src/hooks/queries/__tests__/answer.test.ts index 146d4e5e..44155456 100644 --- a/src/hooks/queries/__tests__/answer.test.ts +++ b/src/hooks/queries/__tests__/answer.test.ts @@ -8,10 +8,11 @@ import { } from '@/hooks/queries/answer'; import * as answerApis from '@/lib/api/answer'; import { createQueryClientWrapper } from '@/lib/test-utils'; +import { createMockQuestionId } from '@/mocks/data/question'; -const questionId: Question['id'] = -1; describe('answer API queries', () => { it('useAnswersQuery를 호출하면 getAnswers가 호출된다', async () => { + const questionId: Question['id'] = createMockQuestionId(); const { result } = renderHook(() => useAnswersQuery(questionId), { wrapper: createQueryClientWrapper(), }); @@ -25,18 +26,22 @@ describe('answer API queries', () => { describe('useCreateAnswerMutation', () => { it('mutate를 호출하면 createAnswer가 호출된다', async () => { - const spyOnCreateAnswer = vi.spyOn(answerApis, 'createAnswer'); - const content = '안녕하세요'; + const questionId: Question['id'] = createMockQuestionId(); + const { result } = renderHook(() => useCreateAnswerMutation(questionId), { wrapper: createQueryClientWrapper(), }); + const spyOnCreateAnswer = vi.spyOn(answerApis, 'createAnswer'); act(() => { result.current.mutate('안녕하세요'); }); await waitFor(() => { - expect(spyOnCreateAnswer).toHaveBeenCalledWith(questionId, content); + expect(spyOnCreateAnswer).toHaveBeenCalledWith( + questionId, + '안녕하세요', + ); }); }); }); diff --git a/src/hooks/queries/__tests__/auth.test.ts b/src/hooks/queries/__tests__/auth.test.ts index 908bb0e5..e08b7651 100644 --- a/src/hooks/queries/__tests__/auth.test.ts +++ b/src/hooks/queries/__tests__/auth.test.ts @@ -1,5 +1,3 @@ -import type { UpdateMyInfoBody, ResignBody } from '@/lib/api/auth'; - import { act, renderHook, waitFor } from '@testing-library/react'; import * as authApis from '@/lib/api/auth'; @@ -10,20 +8,17 @@ import { useResignMutation, useUpdateMyInfoMutation } from '../auth'; describe('auth queries', () => { describe('useUpdateMyInfoMutation', () => { it('mutate를 호출하면 updateMyInfo를 호출한다', async () => { - const body: UpdateMyInfoBody = { - nickname: '닉네임', - }; - const spyOnUpdateMyInfo = vi.spyOn(authApis, 'updateMyInfo'); const { result } = renderHook(() => useUpdateMyInfoMutation(), { wrapper: createQueryClientWrapper(), }); + const spyOnUpdateMyInfo = vi.spyOn(authApis, 'updateMyInfo'); act(() => { - result.current.mutate(body); + result.current.mutate({ nickname: '닉네임' }); }); await waitFor(() => { - expect(spyOnUpdateMyInfo).toHaveBeenCalledWith(body); + expect(spyOnUpdateMyInfo).toHaveBeenCalledWith({ nickname: '닉네임' }); }); }); }); @@ -31,19 +26,16 @@ describe('auth queries', () => { describe('useResignMutation', () => { it('mutate를 호출하면 resign을 호출한다', async () => { const spyOnResign = vi.spyOn(authApis, 'resign'); - const body: ResignBody = { - password: '비밀번호', - }; const { result } = renderHook(() => useResignMutation(), { wrapper: createQueryClientWrapper(), }); act(() => { - result.current.mutate(body); + result.current.mutate({ password: '비밀번호' }); }); await waitFor(() => { - expect(spyOnResign).toHaveBeenCalledWith(body); + expect(spyOnResign).toHaveBeenCalledWith({ password: '비밀번호' }); }); }); }); diff --git a/src/hooks/queries/__tests__/panel.test.ts b/src/hooks/queries/__tests__/panel.test.ts index e622edc1..ebfb6be7 100644 --- a/src/hooks/queries/__tests__/panel.test.ts +++ b/src/hooks/queries/__tests__/panel.test.ts @@ -1,15 +1,15 @@ import type { Panel } from '@/lib/api/panel'; -import { faker } from '@faker-js/faker'; import { renderHook, waitFor } from '@testing-library/react'; import { createQueryClientWrapper } from '@/lib/test-utils'; +import { createMockPanelId } from '@/mocks/data/panel'; import { usePanelDetailQuery } from '../panel'; describe('panel queries', () => { it('usePanelDetailQuery를 호출하면 getPanel이 호출된다', async () => { - const panelId: Panel['sid'] = faker.datatype.uuid(); + const panelId: Panel['sid'] = createMockPanelId(); const { result } = renderHook(() => usePanelDetailQuery(panelId), { wrapper: createQueryClientWrapper(), }); diff --git a/src/hooks/queries/__tests__/question.test.tsx b/src/hooks/queries/__tests__/question.test.tsx index c9718ccd..c62909aa 100644 --- a/src/hooks/queries/__tests__/question.test.tsx +++ b/src/hooks/queries/__tests__/question.test.tsx @@ -3,9 +3,9 @@ import type { GetQuestionsPathParams, GetQuestionsResponse, GetQuestionsResult, + Question, } from '@/lib/api/question'; -import { faker } from '@faker-js/faker'; import { act, renderHook, waitFor } from '@testing-library/react'; import { rest } from 'msw'; @@ -17,15 +17,16 @@ import { import { apiUrl } from '@/lib/api/apiUrl'; import * as questionApis from '@/lib/api/question'; import { createQueryClientWrapper } from '@/lib/test-utils'; +import { createMockPanelId } from '@/mocks/data/panel'; +import { createMockQuestionId } from '@/mocks/data/question'; import { server } from '@/mocks/server'; describe('question API queries', () => { describe('useQuestionsInfiniteQuery', () => { - const panelId: Panel['sid'] = faker.datatype.uuid(); - it('getQuestions가 nextPage를 -1로 반환하면 hasNextPage는 false이다', async () => { - overrideGetQuestionsWith200({ questions: [], nextPage: -1 }); + overrideGetQuestionsWithSuccess({ questions: [], nextPage: -1 }); + const panelId: Panel['sid'] = createMockPanelId(); const { result } = renderHook(() => useQuestionsInfiniteQuery(panelId), { wrapper: createQueryClientWrapper(), }); @@ -38,8 +39,9 @@ describe('question API queries', () => { }); it('getQuestions가 nextPage를 -1 이외의 값을 반환하면 hasNextPage는 true이다', async () => { - overrideGetQuestionsWith200({ questions: [], nextPage: 1 }); + overrideGetQuestionsWithSuccess({ questions: [], nextPage: 1 }); + const panelId: Panel['sid'] = createMockPanelId(); const { result } = renderHook(() => useQuestionsInfiniteQuery(panelId), { wrapper: createQueryClientWrapper(), }); @@ -53,9 +55,12 @@ describe('question API queries', () => { it('매개변수 sort에 createdDate,DESC을 전달하면 getQuestions가 createdDate,DESC로 호출된다', () => { const spyOnGetQuestions = vi.spyOn(questionApis, 'getQuestions'); + + const panelId: Panel['sid'] = createMockPanelId(); renderHook(() => useQuestionsInfiniteQuery(panelId, 'createdDate,DESC'), { wrapper: createQueryClientWrapper(), }); + expect(spyOnGetQuestions).toBeCalledWith(panelId, { page: 0, sort: 'createdDate,DESC', @@ -65,47 +70,48 @@ describe('question API queries', () => { describe('createQuestionMutation', () => { it('mutate를 호출하면 createQuestion 함수를 호출한다', async () => { - const panelId: Panel['sid'] = faker.datatype.uuid(); - const body: questionApis.CreateQuestionBody = { - content: '안녕하세요', - }; const spyOnCreateQuestion = vi.spyOn(questionApis, 'createQuestion'); + + const panelId: Panel['sid'] = createMockPanelId(); const { result } = renderHook(() => useCreateQuestionMutation(panelId), { wrapper: createQueryClientWrapper(), }); act(() => { - result.current.mutate(body); + result.current.mutate({ content: '안녕하세요' }); }); await waitFor(() => { - expect(spyOnCreateQuestion).toHaveBeenCalledWith(panelId, body); + expect(spyOnCreateQuestion).toHaveBeenCalledWith(panelId, { + content: '안녕하세요', + }); }); }); }); describe('likeQuestionMutation', () => { it('mutate를 호출하면 likeQuestion 함수를 호출한다', async () => { - const questionId: questionApis.Question['id'] = 0; - const active: questionApis.LikeQuestionParams['active'] = true; - const spyOnLikeQuestion = vi.spyOn(questionApis, 'likeQuestion'); + + const questionId: Question['id'] = createMockQuestionId(); const { result } = renderHook(() => useLikeQuestionMutation(), { wrapper: createQueryClientWrapper(), }); act(() => { - result.current.mutate({ id: questionId, active }); + result.current.mutate({ id: questionId, active: true }); }); await waitFor(() => { - expect(spyOnLikeQuestion).toHaveBeenCalledWith(questionId, { active }); + expect(spyOnLikeQuestion).toHaveBeenCalledWith(questionId, { + active: true, + }); }); }); }); }); -export function overrideGetQuestionsWith200(result: GetQuestionsResult): void { +function overrideGetQuestionsWithSuccess(result: GetQuestionsResult): void { server.use( rest.get( `${apiUrl.question.getQuestions(':panelId')}`, diff --git a/src/hooks/stores/__test__/useUserStore.test.tsx b/src/hooks/stores/__test__/useUserStore.test.tsx index bfb43099..d4ebd407 100644 --- a/src/hooks/stores/__test__/useUserStore.test.tsx +++ b/src/hooks/stores/__test__/useUserStore.test.tsx @@ -1,6 +1,7 @@ import { act, renderHook } from '@testing-library/react'; import { useUserStore } from '@/hooks/stores/useUserStore'; +import { createMockUserId } from '@/mocks/data/auth'; import { initialUserState, type UserState } from '@/store/user-store'; describe('useUserStore', () => { @@ -32,7 +33,7 @@ describe('useUserStore', () => { ); const newUser: UserState = { - id: -1, + id: createMockUserId(), email: 'test@email.com', nickname: 'testnickname', provider: 'TEST', @@ -85,7 +86,7 @@ describe('useUserStore', () => { ); const newUser: UserState = { - id: -1, + id: createMockUserId(), email: 'test@email.com', nickname: 'testnickname', provider: 'TEST', diff --git a/src/lib/api/__tests__/active-info.test.ts b/src/lib/api/__tests__/active-info.test.ts index a3d71a62..ee5662b5 100644 --- a/src/lib/api/__tests__/active-info.test.ts +++ b/src/lib/api/__tests__/active-info.test.ts @@ -1,17 +1,17 @@ import type { Panel } from '@/lib/api/panel'; -import { faker } from '@faker-js/faker'; - import { getMyActiveInfo } from '@/lib/api/active-Info'; import { apiUrl } from '@/lib/api/apiUrl'; import { mockMyActiveInfo } from '@/mocks/data/active-info'; +import { createMockPanelId } from '@/mocks/data/panel'; describe('activeInfo api', () => { it(`getMyActiveInfo를 호출하면 내 활동 정보 가져오기 API(${apiUrl.activeInfo.get( ':panelId', )})`, async () => { - const panelId: Panel['sid'] = faker.datatype.uuid(); + const panelId: Panel['sid'] = createMockPanelId(); const res = await getMyActiveInfo(panelId); + expect(res.result).toEqual(mockMyActiveInfo); }); }); diff --git a/src/lib/api/__tests__/answer.test.ts b/src/lib/api/__tests__/answer.test.ts index e9b8a56e..4f578b19 100644 --- a/src/lib/api/__tests__/answer.test.ts +++ b/src/lib/api/__tests__/answer.test.ts @@ -1,13 +1,15 @@ +import type { Question } from '@/lib/api/question'; + import { apiUrl } from '@/lib/api/apiUrl'; +import { createMockQuestionId } from '@/mocks/data/question'; import { createAnswer, getAnswers } from '../answer'; -const questionId = -1; - describe('answer api', () => { it(`getAnswers를 호출하면 ${apiUrl.answer.getAnswers( ':questionId', )}로 요청한다`, async () => { + const questionId: Question['id'] = createMockQuestionId(); const { result } = await getAnswers(questionId); expect(result.id).toBe(questionId); @@ -16,6 +18,7 @@ describe('answer api', () => { it(`createAnswer를 호출하면 ${apiUrl.answer.create( ':questionId', )}로 요청한다`, async () => { + const questionId: Question['id'] = createMockQuestionId(); const content = '안녕하세요'; const { result } = await createAnswer(questionId, content); diff --git a/src/lib/api/__tests__/auth.test.ts b/src/lib/api/__tests__/auth.test.ts index 12a68ee7..f5db4eaf 100644 --- a/src/lib/api/__tests__/auth.test.ts +++ b/src/lib/api/__tests__/auth.test.ts @@ -9,7 +9,9 @@ describe('auth api', () => { const body: UpdateMyInfoBody = { nickname: '닉네임', }; + const { result } = await updateMyInfo(body); + expect(result.nickname).toBe(body.nickname); }); @@ -17,7 +19,9 @@ describe('auth api', () => { const body = { password: '비밀번호', }; + const { message } = await resign(body); + expect(message).toBe('회원탈퇴에 성공하였습니다.'); }); }); diff --git a/src/lib/api/__tests__/panel.test.ts b/src/lib/api/__tests__/panel.test.ts index 02e71d48..8641687a 100644 --- a/src/lib/api/__tests__/panel.test.ts +++ b/src/lib/api/__tests__/panel.test.ts @@ -1,7 +1,5 @@ import type { UpdatePanelBody, CreatePanelBody, Panel } from '@/lib/api/panel'; -import { faker } from '@faker-js/faker'; - import { apiUrl } from '@/lib/api/apiUrl'; import { createPanel, @@ -9,6 +7,7 @@ import { deletePanel, getPanel, } from '@/lib/api/panel'; +import { createMockPanelId } from '@/mocks/data/panel'; describe('panel api', () => { it(`createPanel을 호출하면 패널 생성 API(${apiUrl.panel.create()})로 요청한다`, async () => { @@ -18,6 +17,7 @@ describe('panel api', () => { }; const res = await createPanel(body); + expect(res.title).toBe(body.title); expect(res.description).toBe(body.description); }); @@ -25,13 +25,14 @@ describe('panel api', () => { it(`updatePanel을 호출하면 패널 생성 API(${apiUrl.panel.update( ':panelId', )})로 요청한다`, async () => { - const panelId: Panel['sid'] = faker.datatype.uuid(); + const panelId: Panel['sid'] = createMockPanelId(); const body: UpdatePanelBody = { title: '새로운 패널 이름', description: '새로운 패널 설명', }; const res = await updatePanel(panelId, body); + expect(res.title).toBe(body.title); expect(res.description).toBe(body.description); expect(res.sid).toBe(panelId); @@ -40,18 +41,20 @@ describe('panel api', () => { it(`deletePanel을 호출하면 패널 삭제 API(${apiUrl.panel.delete( ':panelId', )})로 요청한다`, async () => { - const panelId: Panel['sid'] = faker.datatype.uuid(); + const panelId = createMockPanelId(); const res = await deletePanel(panelId); + expect(res.message).toBe('패널 삭제에 성공하였습니다.'); }); it(`getPanel을 호출하면 패널 가져오기 API(${apiUrl.panel.get( ':panelId', )})로 요청한다`, async () => { - const panelId: Panel['sid'] = faker.datatype.uuid(); + const panelId = createMockPanelId(); const res = await getPanel(panelId); + expect(res.result.sid).toBe(panelId); }); }); diff --git a/src/lib/api/__tests__/question.test.ts b/src/lib/api/__tests__/question.test.ts index 1d07a811..1402fd32 100644 --- a/src/lib/api/__tests__/question.test.ts +++ b/src/lib/api/__tests__/question.test.ts @@ -1,38 +1,39 @@ import type { Panel } from '@/lib/api/panel'; import type { Question } from '@/lib/api/question'; -import { faker } from '@faker-js/faker'; - import { apiUrl } from '@/lib/api/apiUrl'; import { createQuestion, getQuestions, likeQuestion } from '@/lib/api/question'; -import { mockQuestionList } from '@/mocks/data/question'; +import { createMockPanelId } from '@/mocks/data/panel'; +import { createMockQuestionId, mockQuestionList } from '@/mocks/data/question'; describe('question api', () => { it(`getQuestions를 호출하면 질문 목록 가져오기 API(${apiUrl.question.getQuestions( ':panelId', )})로 요청한다`, async () => { - const panelId: Panel['sid'] = faker.datatype.uuid(); + const panelId: Panel['sid'] = createMockPanelId(); const res = await getQuestions(panelId, { page: 0, }); + expect(mockQuestionList).toContainEqual(res.result.questions[0]); }); it(`createQuestion을 호출하면 질문 생성 API (${apiUrl.question.create( ':panelId', )})로 요청한다`, async () => { - const panelId: Panel['sid'] = faker.datatype.uuid(); + const panelId: Panel['sid'] = createMockPanelId(); const content: Question['content'] = '안녕하세요'; const res = await createQuestion(panelId, { content }); + expect(res.result.content).toBe(content); }); it(`likeQuestion을 호출하면 질문 좋아요 API(${apiUrl.question.like( ':questionId', )})로 요청한다)`, async () => { - const questionId: Question['id'] = 0; + const questionId: Question['id'] = createMockQuestionId(); const active = true; const res = await likeQuestion(questionId, { active }); diff --git a/src/pages/__tests__/Panel.test.tsx b/src/pages/__tests__/Panel.test.tsx index 3e36e214..bafad975 100644 --- a/src/pages/__tests__/Panel.test.tsx +++ b/src/pages/__tests__/Panel.test.tsx @@ -3,12 +3,14 @@ import type { GetQuestionsPathParams, GetQuestionsResponse, } from '@/lib/api/question'; +import type * as Vi from 'vitest'; import React from 'react'; import { screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { rest } from 'msw'; +import { useLoaderData } from 'react-router-dom'; import { OverlayProvider } from '@/contexts/OverlayContext'; import { apiUrl } from '@/lib/api/apiUrl'; @@ -19,38 +21,37 @@ import { createMockQuestion } from '@/mocks/data/question'; import { server } from '@/mocks/server'; import { Panel } from '@/pages/Panel'; -const panel: PanelData = createMockPanel(); - vi.mock('react-router-dom', async (importOriginal) => { const router = (await importOriginal()) ?? {}; - return { ...router, useLoaderData: vi.fn(() => panel) }; + return { ...router, useLoaderData: vi.fn() }; }); +function setup({ panel }: { panel: PanelData }): void { + (useLoaderData as Vi.Mock).mockImplementation(() => panel); + renderWithQueryClient( + + + , + ); +} + describe('패널 페이지', () => { it('헤더를 보여준다', () => { - renderWithQueryClient( - - - , - ); + setup({ panel: createMockPanel() }); expect(screen.getByRole('banner')).toBeInTheDocument(); }); it('질문 목록을 렌더링한다', async () => { - const question = createMockQuestion(); overrideGetQuestionsWithSuccess({ statusCode: 200, result: { - questions: [{ ...question, content: '안녕하세요' }], + questions: [{ ...createMockQuestion(), content: '안녕하세요' }], nextPage: -1, }, }); - renderWithQueryClient( - - - , - ); + + setup({ panel: createMockPanel() }); await waitFor(() => { expect(screen.getAllByText(/안녕하세요/)[0]).toBeInTheDocument(); @@ -58,11 +59,7 @@ describe('패널 페이지', () => { }); it('질문 생성 모달 열기 버튼을 누르면 질문 생성 모달을 보여준다', async () => { - renderWithQueryClient( - - - , - ); + setup({ panel: createMockPanel() }); const openButton = screen.getByRole('button', { name: /질문 생성 모달 열기/, diff --git a/src/pages/__tests__/panel-route.test.tsx b/src/pages/__tests__/panel-route.test.tsx index 0c6805a6..6f067eb3 100644 --- a/src/pages/__tests__/panel-route.test.tsx +++ b/src/pages/__tests__/panel-route.test.tsx @@ -4,7 +4,6 @@ import type { RouteObject } from 'react-router-dom'; import React from 'react'; -import { faker } from '@faker-js/faker'; import { QueryClientProvider, type QueryClient } from '@tanstack/react-query'; import { render, screen, waitFor } from '@testing-library/react'; import { rest } from 'msw'; @@ -17,16 +16,15 @@ import { apiUrl } from '@/lib/api/apiUrl'; import * as panelApis from '@/lib/api/panel'; import { createQueryClient } from '@/lib/test-utils'; import { mockMyActiveInfo } from '@/mocks/data/active-info'; +import { createMockPanelId } from '@/mocks/data/panel'; import { server } from '@/mocks/server'; import { Panel, panelLoader, PanelErrorBoundary } from '@/pages/Panel'; -const panelId: PanelData['sid'] = faker.datatype.uuid(); - describe('/panel/:id route', () => { it('로더에서 패널 정보 가져오기 API와 내 활동 정보 가져오기 API를 호출한다', async () => { const spyOnGetPanel = vi.spyOn(panelApis, 'getPanel'); const spyOnGetMyActiveInfo = vi.spyOn(activeInfoApis, 'getMyActiveInfo'); - setup(); + const { panelId } = setup(); expect(spyOnGetPanel).toBeCalledWith(panelId); await waitFor(() => { @@ -35,7 +33,7 @@ describe('/panel/:id route', () => { }); it('내 활동 정보 가져오기 API가 성공 응답을 반환하면 캐시에 저장된다', async () => { - const { queryClient } = setup(); + const { queryClient, panelId } = setup(); await waitFor(() => { expect( @@ -76,7 +74,9 @@ function overrideGetPanelResponseWithError(data: ErrorResponse): void { function setup(): { queryClient: QueryClient; + panelId: PanelData['sid']; } { + const panelId: PanelData['sid'] = createMockPanelId(); const queryClient = createQueryClient(); const routes: RouteObject[] = [ { @@ -107,5 +107,5 @@ function setup(): { ), }); - return { queryClient }; + return { queryClient, panelId }; }