diff --git a/.github/workflows/install-build-test.yaml b/.github/workflows/install-build-test.yaml
index 2c75459..f651a35 100644
--- a/.github/workflows/install-build-test.yaml
+++ b/.github/workflows/install-build-test.yaml
@@ -8,6 +8,7 @@ on:
env:
GITHUB_TOKEN: ${{ secrets.DND_11_8_FRONTEND_TOKEN }}
GITHUB_ACTIONS: true
+ VITE_API_URL: ${{ secrets.VITE_API_URL }}
jobs:
build:
diff --git a/package.json b/package.json
index a1e6dd3..a9a1522 100644
--- a/package.json
+++ b/package.json
@@ -68,6 +68,7 @@
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.4.8",
"@testing-library/react": "^16.0.0",
+ "@testing-library/user-event": "^14.5.2",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@typescript-eslint/eslint-plugin": "^7.18.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 4b72990..5a8dc8e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -156,6 +156,9 @@ importers:
'@testing-library/react':
specifier: ^16.0.0
version: 16.0.0(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@testing-library/user-event':
+ specifier: ^14.5.2
+ version: 14.5.2(@testing-library/dom@10.4.0)
'@types/react':
specifier: ^18.3.3
version: 18.3.3
@@ -8392,6 +8395,10 @@ snapshots:
dependencies:
'@testing-library/dom': 10.1.0
+ '@testing-library/user-event@14.5.2(@testing-library/dom@10.4.0)':
+ dependencies:
+ '@testing-library/dom': 10.4.0
+
'@toss/async-boundary@1.5.0(react@18.3.1)':
dependencies:
'@toss/error-boundary': 1.5.0(react@18.3.1)
diff --git a/src/__test__/AddPlantPage.test.tsx b/src/__test__/AddPlantPage.test.tsx
new file mode 100644
index 0000000..e1beb8e
--- /dev/null
+++ b/src/__test__/AddPlantPage.test.tsx
@@ -0,0 +1,85 @@
+import { beforeEach, describe, expect, it, vi } from 'vitest';
+import { render, screen, waitFor } from '@testing-library/react';
+import AddPlantPage from '@/pages/AddPlantPage';
+import { Wrapper } from '@/__test__/helpers/wrapper.tsx';
+import userEvent from '@testing-library/user-event';
+
+// Mock the ResizeObserver
+const ResizeObserverMock = vi.fn(() => ({
+ observe: vi.fn(),
+ unobserve: vi.fn(),
+ disconnect: vi.fn(),
+}));
+
+// Stub the global ResizeObserver
+vi.stubGlobal('ResizeObserver', ResizeObserverMock);
+
+describe('내 식물 등록 페이지 테스트', () => {
+ const user = userEvent.setup();
+ beforeEach(() => {
+ render(, { wrapper: Wrapper });
+ });
+ it('식물 종류 입력 텍스트 필드를 클릭하면 식물 종류 검색 페이지가 나타난다.', async () => {
+ const plantTypeInput = screen.getByLabelText('식물 종류');
+
+ await user.click(plantTypeInput);
+
+ const plantTypeSearchInput = screen.getByPlaceholderText('식물 종류 검색');
+ expect(plantTypeSearchInput).toBeInTheDocument();
+ });
+
+ it('식물 종류 검색시 검색 결과가 나타난다.', async () => {
+ const plantTypeInput = screen.getByLabelText('식물 종류');
+
+ await user.click(plantTypeInput);
+
+ const plantTypeSearchInput = screen.getByPlaceholderText('식물 종류 검색') as HTMLInputElement;
+
+ await waitFor(
+ async () => {
+ await user.type(plantTypeSearchInput, '몬스테라');
+ expect(plantTypeSearchInput.value).toBe('몬스테라');
+ },
+ { timeout: 2000 },
+ );
+
+ await waitFor(
+ async () => {
+ const plantTypeSearchResult = await screen.findByText(/몬스테라/);
+ expect(plantTypeSearchResult).toBeInTheDocument();
+ },
+ { timeout: 4000 },
+ );
+ });
+
+ it('검색 결과 클릭시 화면이 사라지고 선택한 식물의 값이 텍스트 필드에 표기된다', async () => {
+ const plantTypeInput = screen.getByLabelText('식물 종류') as HTMLInputElement;
+
+ await user.click(plantTypeInput);
+
+ const plantTypeSearchInput = screen.getByPlaceholderText('식물 종류 검색') as HTMLInputElement;
+
+ await waitFor(
+ async () => {
+ await user.type(plantTypeSearchInput, '몬스테라');
+ expect(plantTypeSearchInput.value).toBe('몬스테라');
+ },
+ { timeout: 2000 },
+ );
+
+ await waitFor(
+ async () => {
+ const plantTypeAddButton = await screen.findByRole('button', {
+ name: /add-searched-result-button/,
+ });
+
+ await user.click(plantTypeAddButton);
+ },
+ { timeout: 4000 },
+ );
+
+ expect(plantTypeSearchInput).not.toBeInTheDocument();
+
+ expect(plantTypeInput.value).include('몬스테라');
+ });
+});
diff --git a/src/__test__/helpers/wrapper.tsx b/src/__test__/helpers/wrapper.tsx
new file mode 100644
index 0000000..e62fd36
--- /dev/null
+++ b/src/__test__/helpers/wrapper.tsx
@@ -0,0 +1,26 @@
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
+import { Provider as JotaiProvider } from 'jotai';
+import { GlobalPortal } from '@/providers/GlobalPortal.tsx';
+import { GlobalModalProvider } from '@/providers/GlobalModalProvider.tsx';
+import { PropsWithChildren } from 'react';
+import { MemoryRouter } from 'react-router-dom';
+
+interface WrapperProps extends PropsWithChildren {
+ initialEntries?: string[];
+}
+
+export const Wrapper = ({ children, initialEntries }: WrapperProps) => {
+ const queryClient = new QueryClient({});
+ return (
+
+
+
+
+ {children}
+
+ ;
+
+
+
+ );
+};
diff --git a/src/__test__/setup.ts b/src/__test__/setup.ts
index d13f63a..3a5ed4e 100644
--- a/src/__test__/setup.ts
+++ b/src/__test__/setup.ts
@@ -1,7 +1,15 @@
-import { afterEach } from 'vitest';
+import { afterEach, beforeEach } from 'vitest';
import { cleanup } from '@testing-library/react';
import '@testing-library/jest-dom';
+import { setupServer } from 'msw/node';
+import { handlers } from '@/mocks/handlers.ts';
+
+const server = setupServer(...handlers);
+
+beforeEach(() => {
+ server.listen();
+});
afterEach(() => {
cleanup();
diff --git a/src/components/searchPlant/SearchedPlantList.tsx b/src/components/searchPlant/SearchedPlantList.tsx
index f031c8d..78f3059 100644
--- a/src/components/searchPlant/SearchedPlantList.tsx
+++ b/src/components/searchPlant/SearchedPlantList.tsx
@@ -103,7 +103,11 @@ const SearchedPlantList = ({ query, onClose }: SearchedPlantListProps) => {
image={plant.imageUrl}
key={`SearchedPlantList-${plant.plantId}`}
trailingIcon={
-