diff --git a/src/app/mocks/handler/feed.ts b/src/app/mocks/handler/feed.ts
index d583e85..2a72386 100644
--- a/src/app/mocks/handler/feed.ts
+++ b/src/app/mocks/handler/feed.ts
@@ -187,6 +187,6 @@ export const feedHandlers = [
hiddens[formattedFeedId] = true;
}
- return createHttpSuccessResponse({});
+ return createHttpSuccessResponse({ isReported: true });
}),
];
diff --git a/src/features/feed-bookmark/api/useBookmarks.tsx b/src/features/feed-bookmark/api/useBookmarks.tsx
index e18ac4e..72c88f1 100644
--- a/src/features/feed-bookmark/api/useBookmarks.tsx
+++ b/src/features/feed-bookmark/api/useBookmarks.tsx
@@ -10,7 +10,11 @@ import { updateBookmarkStatusInFeeds } from '../lib';
export const useBookmarks = (feedId: number, isBookmarked: boolean) => {
const queryClient = useQueryClient();
- const { mutate: handleBookmarkFeed, isPending } = useMutation({
+ const {
+ data,
+ mutate: handleBookmarkFeed,
+ isPending,
+ } = useMutation({
mutationFn: () =>
isBookmarked
? requestUnbookmarkFeed(feedId)
@@ -51,5 +55,5 @@ export const useBookmarks = (feedId: number, isBookmarked: boolean) => {
},
});
- return { handleBookmarkFeed, isPending };
+ return { data, handleBookmarkFeed, isPending };
};
diff --git a/src/features/feed-bookmark/test/useBookmarks.test.tsx b/src/features/feed-bookmark/test/useBookmarks.test.tsx
deleted file mode 100644
index 7da5b97..0000000
--- a/src/features/feed-bookmark/test/useBookmarks.test.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-import { renderHook, act, waitFor } from '@testing-library/react';
-import { expect, test, vi } from 'vitest';
-
-import * as bookmarkModule from '@/shared/axios';
-import { createQueryClientWrapper } from '@/shared/tests';
-
-import { useBookmarks } from '../api';
-
-test('북마크 상태가 아닐 때, 북마크 버튼을 클릭하면 북마크 요청이 발생한다.', async () => {
- // given
- // requestBookmarkFeed 함수를 스파이한다.
- const spy = vi.spyOn(bookmarkModule, 'requestBookmarkFeed');
- const { result } = renderHook(() => useBookmarks(1, false), {
- wrapper: createQueryClientWrapper(),
- });
-
- // requestBookmarkFeed가 호출되지 않았는지 확인
- await waitFor(() => expect(spy).not.toHaveBeenCalled());
-
- // when
- // 좋아요 버튼 클릭
- await act(async () => result.current.handleBookmarkFeed());
-
- // then
- // requestBookmarkFeed가 호출되었는지 확인
- await waitFor(() => expect(spy).toHaveBeenCalled());
-});
-
-test('북마크 상태일 때, 북마크 버튼을 클릭하면 북마크 취소 요청이 발생한다.', async () => {
- // given
- const spy = vi.spyOn(bookmarkModule, 'requestUnbookmarkFeed');
- const { result } = renderHook(() => useBookmarks(1, true), {
- wrapper: createQueryClientWrapper(),
- });
-
- await waitFor(() => expect(spy).not.toHaveBeenCalled());
-
- // when
- await act(async () => result.current.handleBookmarkFeed());
-
- // then
- await waitFor(() => expect(spy).toHaveBeenCalled());
-});
diff --git a/src/features/feed-bookmark/test/useBookmarks.unit.test.tsx b/src/features/feed-bookmark/test/useBookmarks.unit.test.tsx
new file mode 100644
index 0000000..48a17a2
--- /dev/null
+++ b/src/features/feed-bookmark/test/useBookmarks.unit.test.tsx
@@ -0,0 +1,44 @@
+import { renderHook, act, waitFor } from '@testing-library/react';
+import { describe, expect, it } from 'vitest';
+
+import { createQueryClientWrapper } from '@/shared/tests';
+
+import { useBookmarks } from '../api';
+
+describe('북마크 기능 테스트', () => {
+ it('북마크 상태가 아닐 때, 북마크 버튼을 클릭하면 북마크 된다', async () => {
+ // given
+ const { result } = renderHook(() => useBookmarks(1, false), {
+ wrapper: createQueryClientWrapper(),
+ });
+
+ // when
+ act(() => result.current.handleBookmarkFeed());
+
+ // then
+ await waitFor(() => {
+ const {
+ data: { isBookmarked },
+ } = result.current.data;
+ expect(isBookmarked).toBeTruthy();
+ });
+ });
+
+ it('북마크 상태일 때, 북마크 버튼을 클릭하면 북마크가 취소된다', async () => {
+ // given
+ const { result } = renderHook(() => useBookmarks(1, true), {
+ wrapper: createQueryClientWrapper(),
+ });
+
+ // when
+ act(() => result.current.handleBookmarkFeed());
+
+ // then
+ await waitFor(() => {
+ const {
+ data: { isBookmarked },
+ } = result.current.data;
+ expect(isBookmarked).toBeFalsy();
+ });
+ });
+});
diff --git a/src/features/feed-hides/api/useHideCancle.tsx b/src/features/feed-hides/api/useHideCancle.tsx
index 38044fc..bd4cc32 100644
--- a/src/features/feed-hides/api/useHideCancle.tsx
+++ b/src/features/feed-hides/api/useHideCancle.tsx
@@ -10,10 +10,14 @@ async function requestHideCancelFeed(feedId: number) {
}
export const useHideCancel = (feedId: number) => {
- const { mutate: hideCancelFeed, isPending } = useMutation({
+ const {
+ data,
+ mutate: hideCancelFeed,
+ isPending,
+ } = useMutation({
mutationFn: () => requestHideCancelFeed(feedId),
onMutate: () => cancleHiddenFeed(feedId),
});
- return { hideCancelFeed, isPending };
+ return { data, hideCancelFeed, isPending };
};
diff --git a/src/features/feed-hides/api/useHides.tsx b/src/features/feed-hides/api/useHides.tsx
index 65267cb..8ea3e79 100644
--- a/src/features/feed-hides/api/useHides.tsx
+++ b/src/features/feed-hides/api/useHides.tsx
@@ -10,10 +10,14 @@ async function requestHideFeed(feedId: number) {
}
export const useHides = (feedId: number) => {
- const { mutate: hideFeed, isPending } = useMutation({
+ const {
+ data,
+ mutate: hideFeed,
+ isPending,
+ } = useMutation({
mutationFn: () => requestHideFeed(feedId),
onMutate: () => addHiddenFeed(feedId, 'hidden'),
});
- return { hideFeed, isPending };
+ return { data, hideFeed, isPending };
};
diff --git a/src/features/feed-hides/test/useHide.unit.test.tsx b/src/features/feed-hides/test/useHide.unit.test.tsx
new file mode 100644
index 0000000..10e1a4e
--- /dev/null
+++ b/src/features/feed-hides/test/useHide.unit.test.tsx
@@ -0,0 +1,46 @@
+import { renderHook, act, waitFor } from '@testing-library/react';
+import { describe, expect, it } from 'vitest';
+
+import { createQueryClientWrapper } from '@/shared/tests';
+
+import { useHideCancel, useHides } from '../api';
+
+describe('숨기기 기능 테스트', () => {
+ it('숨기기 상태가 아닐 때, 숨기기 버튼을 클릭하면 게시물이 숨겨진다.', async () => {
+ // given
+ const { result } = renderHook(() => useHides(1), {
+ wrapper: createQueryClientWrapper(),
+ });
+
+ // when
+ act(() => result.current.hideFeed());
+
+ // then
+ await waitFor(() => {
+ const {
+ data: { isHidden },
+ } = result.current.data;
+
+ expect(isHidden).toBeTruthy();
+ });
+ });
+
+ it('숨기기 상태일 때, 취소 버튼을 클릭하면 숨기기가 취소된다.', async () => {
+ // given
+ const { result } = renderHook(() => useHideCancel(1), {
+ wrapper: createQueryClientWrapper(),
+ });
+
+ // when
+ act(() => result.current.hideCancelFeed());
+
+ // then
+ await waitFor(() => {
+ const {
+ data: { isHidden },
+ } = result.current.data;
+
+ expect(isHidden).toBeFalsy();
+ });
+ });
+});
diff --git a/src/features/feed-main-like/api/useLikes.tsx b/src/features/feed-main-like/api/useLikes.tsx
index e0d4e2d..5dd373c 100644
--- a/src/features/feed-main-like/api/useLikes.tsx
+++ b/src/features/feed-main-like/api/useLikes.tsx
@@ -10,7 +10,11 @@ import { updateLikeStatusInFeeds } from '../lib';
export const useLikes = (feedId: number, isLiked: boolean) => {
const queryClient = useQueryClient();
- const { mutate: handleLikeFeed, isPending } = useMutation({
+ const {
+ data,
+ mutate: handleLikeFeed,
+ isPending,
+ } = useMutation({
mutationFn: () =>
isLiked ? requestUnlikeFeed(feedId) : requestLikeFeed(feedId),
// mutate가 호출되면 ✨낙관적 업데이트를 위해 onMutate를 실행
@@ -53,5 +57,5 @@ export const useLikes = (feedId: number, isLiked: boolean) => {
},
});
- return { handleLikeFeed, isPending };
+ return { data, handleLikeFeed, isPending };
};
diff --git a/src/features/feed-main-like/test/useLikes.test.tsx b/src/features/feed-main-like/test/useLikes.test.tsx
deleted file mode 100644
index 73ce59d..0000000
--- a/src/features/feed-main-like/test/useLikes.test.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-import { renderHook, act, waitFor } from '@testing-library/react';
-import { expect, test, vi } from 'vitest';
-
-import * as likeModule from '@/shared/axios/like';
-import { createQueryClientWrapper } from '@/shared/tests';
-
-import { useLikes } from '../api';
-
-test('좋아요 상태가 아닐 때, 좋아요 버튼을 클릭하면 좋아요 요청이 발생한다.', async () => {
- // given
- // requestLikeFeed 함수를 스파이한다.
- const spy = vi.spyOn(likeModule, 'requestLikeFeed');
- const { result } = renderHook(() => useLikes(1, false), {
- wrapper: createQueryClientWrapper(),
- });
-
- // requestLikeFeed가 호출되지 않았는지 확인
- await waitFor(() => expect(spy).not.toHaveBeenCalled());
-
- // when
- // 좋아요 버튼 클릭
- await act(async () => result.current.handleLikeFeed());
-
- // then
- // requestLikeFeed가 호출되었는지 확인
- await waitFor(() => expect(spy).toHaveBeenCalled());
-});
-
-test('좋아요 상태일 때, 좋아요 버튼을 클릭하면 좋아요 취소 요청이 발생한다.', async () => {
- // given
- const spy = vi.spyOn(likeModule, 'requestUnlikeFeed');
- const { result } = renderHook(() => useLikes(1, true), {
- wrapper: createQueryClientWrapper(),
- });
-
- await waitFor(() => expect(spy).not.toHaveBeenCalled());
-
- // when
- await act(async () => result.current.handleLikeFeed());
-
- // then
- await waitFor(() => expect(spy).toHaveBeenCalled());
-});
diff --git a/src/features/feed-main-like/test/useLikes.unit.test.tsx b/src/features/feed-main-like/test/useLikes.unit.test.tsx
new file mode 100644
index 0000000..9b556e0
--- /dev/null
+++ b/src/features/feed-main-like/test/useLikes.unit.test.tsx
@@ -0,0 +1,46 @@
+import { renderHook, act, waitFor } from '@testing-library/react';
+import { describe, expect, it } from 'vitest';
+
+import { createQueryClientWrapper } from '@/shared/tests';
+
+import { useLikes } from '../api';
+
+describe('좋아요 기능 테스트', () => {
+ it('좋아요 상태가 아닐 때, 좋아요 버튼을 클릭하면 좋아요 상태가 변경된다.', async () => {
+ // given
+ const { result } = renderHook(() => useLikes(1, false), {
+ wrapper: createQueryClientWrapper(),
+ });
+
+ // when
+ act(() => result.current.handleLikeFeed());
+
+ // then
+ await waitFor(() => {
+ const {
+ data: { isLiked },
+ } = result.current.data;
+
+ expect(isLiked).toBeTruthy();
+ });
+ });
+
+ it('좋아요 상태일 때, 좋아요 버튼을 클릭하면 좋아요가 취소된다.', async () => {
+ // given
+ const { result } = renderHook(() => useLikes(1, true), {
+ wrapper: createQueryClientWrapper(),
+ });
+
+ // when
+ act(() => result.current.handleLikeFeed());
+
+ // then
+ await waitFor(() => {
+ const {
+ data: { isLiked },
+ } = result.current.data;
+
+ expect(isLiked).toBeFalsy();
+ });
+ });
+});
diff --git a/src/features/feed-reports/api/useSubmitReports.tsx b/src/features/feed-reports/api/useSubmitReports.tsx
index c67ab45..abd88b9 100644
--- a/src/features/feed-reports/api/useSubmitReports.tsx
+++ b/src/features/feed-reports/api/useSubmitReports.tsx
@@ -13,7 +13,11 @@ async function requestFeedReports(feedId: number, body: FeedReportForm) {
}
export const useSubmitReports = (feedId: number) => {
- const { mutate: reportFeed, isPending } = useMutation({
+ const {
+ data,
+ mutate: reportFeed,
+ isPending,
+ } = useMutation({
mutationKey: ['feed-report'],
mutationFn: (body: FeedReportForm) => requestFeedReports(feedId, body),
onError: (_, body) => saveFeedReportForm(feedId, body),
@@ -29,5 +33,5 @@ export const useSubmitReports = (feedId: number) => {
},
});
- return { reportFeed, isPending };
+ return { data, reportFeed, isPending };
};
diff --git a/src/features/feed-reports/test/FeedReports.integration.test.tsx b/src/features/feed-reports/test/FeedReports.integration.test.tsx
new file mode 100644
index 0000000..19b05d8
--- /dev/null
+++ b/src/features/feed-reports/test/FeedReports.integration.test.tsx
@@ -0,0 +1,44 @@
+import { expect, test, vi } from 'vitest';
+
+import { fireEvent, render, screen } from '@/shared/tests';
+import { Toast } from '@/shared/toast';
+
+import { FeedReportsForm } from '../ui';
+
+vi.mock('@/shared/ui/modal/ModalOverlay', () => ({
+ ModalOverlay: ({ children }: { children: JSX.Element }) => (
+
+ ),
+}));
+
+vi.mock('@/features/feed-reports/model', () => ({
+ useReportForm: () => ({
+ content: '',
+ isBlind: false,
+ isDisabledReportForm: false,
+ createReportBody: () => ({
+ category: '상업적/홍보성',
+ content: '',
+ isBlind: false,
+ }),
+ }),
+}));
+
+test('신고하기 버튼을 클릭하면, 신고 접수 토스트 메시지가 표시된다', async () => {
+ // given
+ render(
+ <>
+ {}} />
+
+ >,
+ );
+
+ const reportBtn = screen.getByRole('button', { name: '신고하기' });
+
+ // when
+ fireEvent.click(reportBtn);
+
+ // then
+ const reportAcceptMsg = await screen.findByText('신고가 접수되었어요');
+ expect(reportAcceptMsg).toBeInTheDocument();
+});
diff --git a/src/features/feed-reports/test/useSubmitReports.unit.test.tsx b/src/features/feed-reports/test/useSubmitReports.unit.test.tsx
new file mode 100644
index 0000000..d6df516
--- /dev/null
+++ b/src/features/feed-reports/test/useSubmitReports.unit.test.tsx
@@ -0,0 +1,30 @@
+import { act, renderHook, waitFor } from '@testing-library/react';
+import { expect, test } from 'vitest';
+
+import { createQueryClientWrapper } from '@/shared/tests';
+
+import { useSubmitReports } from '../api';
+
+test('신고 기능 테스트', async () => {
+ // given
+ const { result } = renderHook(() => useSubmitReports(1), {
+ wrapper: createQueryClientWrapper(),
+ });
+ const body = {
+ category: '상업적/홍보성',
+ content: '',
+ isBlind: false,
+ };
+
+ // when
+ act(() => result.current.reportFeed(body));
+
+ // then
+ await waitFor(() => {
+ const {
+ data: { isReported },
+ } = result.current.data;
+
+ expect(isReported).toBeTruthy();
+ });
+});
diff --git a/src/setupTest.ts b/src/setupTest.ts
index 0aaa4f0..e1bea44 100644
--- a/src/setupTest.ts
+++ b/src/setupTest.ts
@@ -4,7 +4,11 @@ import * as matchers from '@testing-library/jest-dom/matchers';
import { setupServer } from 'msw/node';
import { beforeAll, afterAll, afterEach, expect } from 'vitest';
+import { bookmarkHandlers } from './app/mocks/handler/bookmark';
+import { commentHandlers } from './app/mocks/handler/comment';
+import { feedHandlers } from './app/mocks/handler/feed';
import { followHandler } from './app/mocks/handler/follow';
+import { feedHidesHandlers } from './app/mocks/handler/hide';
import { likeHandlers } from './app/mocks/handler/like';
import { searchHandler } from './app/mocks/handler/search';
import { userHandler } from './app/mocks/handler/user';
@@ -12,12 +16,16 @@ import { userHandler } from './app/mocks/handler/user';
expect.extend(matchers);
export const server = setupServer(
+ ...commentHandlers,
+ ...feedHandlers,
+ ...feedHidesHandlers,
+ ...bookmarkHandlers,
...likeHandlers,
...followHandler,
...searchHandler,
...userHandler,
);
-beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
+beforeAll(() => server.listen({ onUnhandledRequest: 'bypass' }));
afterAll(() => server.close());
afterEach(() => server.resetHandlers());
diff --git a/src/shared/tests/setup.tsx b/src/shared/tests/setup.tsx
index 09449d0..9f8a1b3 100644
--- a/src/shared/tests/setup.tsx
+++ b/src/shared/tests/setup.tsx
@@ -1,24 +1,13 @@
-import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
+import { QueryClientProvider } from '@tanstack/react-query';
import { render as testRender } from '@testing-library/react';
import { PropsWithChildren, ReactElement } from 'react';
import { MemoryRouter } from 'react-router-dom';
-const generateQueryClient = () => {
- const queryClientOptions = {
- defaultOptions: {
- queries: {
- retry: false,
- },
- },
- };
-
- return new QueryClient(queryClientOptions);
-};
+import { queryClient } from '../react-query';
// hooks를 사용하는 컴포넌트를 테스트할 때 필요한 wrapper를 생성하는 함수
// from https://tkdodo.eu/blog/testing-react-query#for-custom-hooks
export const createQueryClientWrapper = () => {
- const queryClient = generateQueryClient();
return ({ children }: PropsWithChildren) => (
{children}
);
@@ -27,8 +16,6 @@ export const createQueryClientWrapper = () => {
// custom render 함수
// reference: https://testing-library.com/docs/react-testing-library/setup#custom-render
const customRender = (children: ReactElement, baseEntries?: string[]) => {
- const queryClient = generateQueryClient();
-
return testRender(
{children}
diff --git a/src/widgets/feed-main-list/test/FeedMainList.test.tsx b/src/widgets/feed-main-list/test/FeedMainList.integration.test.tsx
similarity index 100%
rename from src/widgets/feed-main-list/test/FeedMainList.test.tsx
rename to src/widgets/feed-main-list/test/FeedMainList.integration.test.tsx
diff --git a/src/widgets/feed-main-list/test/FeedMainList.error.test.tsx b/src/widgets/feed-main-list/test/FeedMainList.intergration.error.test.tsx
similarity index 100%
rename from src/widgets/feed-main-list/test/FeedMainList.error.test.tsx
rename to src/widgets/feed-main-list/test/FeedMainList.intergration.error.test.tsx
diff --git a/src/widgets/feed-main-list/test/useInfinityFeeds.unit.test.tsx b/src/widgets/feed-main-list/test/useInfinityFeeds.unit.test.tsx
new file mode 100644
index 0000000..eedb277
--- /dev/null
+++ b/src/widgets/feed-main-list/test/useInfinityFeeds.unit.test.tsx
@@ -0,0 +1,18 @@
+import { renderHook, waitFor } from '@testing-library/react';
+import { expect, test } from 'vitest';
+
+import { createQueryClientWrapper } from '@/shared/tests';
+
+import { useInfinityFeeds } from '../api';
+
+test('무한 스크롤 테스트', async () => {
+ const { result } = renderHook(() => useInfinityFeeds(), {
+ wrapper: createQueryClientWrapper(),
+ });
+
+ await waitFor(() => expect(result.current.feeds?.pageParams).toEqual([1]));
+
+ result.current.fetchNextFeeds();
+
+ await waitFor(() => expect(result.current.feeds?.pageParams).toEqual([1, 2]));
+});