diff --git a/jest.config.js b/jest.config.js index 2d756f45..7d3102f7 100644 --- a/jest.config.js +++ b/jest.config.js @@ -11,6 +11,10 @@ const config = { coverageProvider: 'v8', testEnvironment: 'jsdom', // setupFilesAfterEnv: ['/src/setupTests.ts'], + moduleNameMapper: { + // 절대 경로 매핑 + '^@/(.*)$': '/src/$1', + }, }; // createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async diff --git a/src/features/club-create/container/FormContainer.tsx b/src/features/club-create/container/FormContainer.tsx index 681159a1..a223cac5 100644 --- a/src/features/club-create/container/FormContainer.tsx +++ b/src/features/club-create/container/FormContainer.tsx @@ -5,11 +5,11 @@ import { CreateClubFormField, InputField, } from '@/features/club-create/components'; -import ImageField from '@/features/club-create/container/ImageField'; -import RadioButtonGroup from '@/features/club-create/container/RadioButtonGroup'; +import RadioButtonGroup from '@/features/club-create/container/RadioButtonGroup/RadioButtonGroup'; import DatePickerContainer from '@/features/club-create/container/DatePickerField'; import { useBookClubForm } from '@/features/club-create/hooks'; import PopUp from '@/components/pop-up/PopUp'; +import ImageField from '@/features/club-create/container/ImageField/ImageField'; function FormContainer() { const { diff --git a/src/features/club-create/container/ImageField/ImageField.test.tsx b/src/features/club-create/container/ImageField/ImageField.test.tsx new file mode 100644 index 00000000..fe7fe395 --- /dev/null +++ b/src/features/club-create/container/ImageField/ImageField.test.tsx @@ -0,0 +1,40 @@ +import { render, screen } from '@testing-library/react'; +import ImageField from '@/features/club-create/container/ImageField/ImageField'; +import { useImageField } from '@/features/club-create/hooks'; +import '@testing-library/jest-dom'; + +jest.mock('@/features/club-create/hooks/useImageField', () => ({ + useImageField: jest.fn(() => ({ + selectedFileName: '', + handleFileChange: jest.fn(), + })), +})); + +describe('ImageField', () => { + const mockRegister = jest.fn(); + const mockSetValue = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('이미지가 선택되지 않았을 때 이미지 업로드 UI를 표시한다', () => { + render(); + + expect(screen.getByTestId('camera-icon')).toBeInTheDocument(); + expect(screen.getByTestId('file-input')).toBeInTheDocument(); + }); + + it('이미지 선택 시 파일명을 표시한다', () => { + const testFileName = 'test.jpg'; + (useImageField as jest.Mock).mockImplementationOnce(() => ({ + selectedFileName: testFileName, + handleFileChange: jest.fn(), + })); + + render(); + + expect(screen.getByTestId('image-icon')).toBeInTheDocument(); + expect(screen.getByText(testFileName)).toBeInTheDocument(); + }); +}); diff --git a/src/features/club-create/container/ImageField.tsx b/src/features/club-create/container/ImageField/ImageField.tsx similarity index 78% rename from src/features/club-create/container/ImageField.tsx rename to src/features/club-create/container/ImageField/ImageField.tsx index 64a7568a..0b471efe 100644 --- a/src/features/club-create/container/ImageField.tsx +++ b/src/features/club-create/container/ImageField/ImageField.tsx @@ -1,10 +1,10 @@ 'use client'; import { UseFormRegister, UseFormSetValue } from 'react-hook-form'; -import { BookClubForm } from '../types'; -import { CreateClubFormField } from '../components'; +import { BookClubForm } from '../../types'; +import { CreateClubFormField } from '../../components'; import { useImageField } from '@/features/club-create/hooks'; -import { CameraIcon, ImageIcon } from '../../../../public/icons'; +import { CameraIcon, ImageIcon } from '../../../../../public/icons'; interface ImageUploadContainerProps { register: UseFormRegister; @@ -24,7 +24,9 @@ function ImageField({ register, setValue, error }: ImageUploadContainerProps) { {selectedFileName ? ( <>
- +
+ +
{selectedFileName} @@ -32,7 +34,9 @@ function ImageField({ register, setValue, error }: ImageUploadContainerProps) { ) : (
- +
+ +
이미지를 첨부해 주세요 (jpg, jpeg) @@ -43,6 +47,7 @@ function ImageField({ register, setValue, error }: ImageUploadContainerProps) { accept="image/*" className="absolute inset-0 cursor-pointer opacity-0" onChange={handleFileChange} + data-testid="file-input" />
diff --git a/src/features/club-create/container/RadioButtonGroup/RadioButtonGroup.test.tsx b/src/features/club-create/container/RadioButtonGroup/RadioButtonGroup.test.tsx new file mode 100644 index 00000000..b3e33cd1 --- /dev/null +++ b/src/features/club-create/container/RadioButtonGroup/RadioButtonGroup.test.tsx @@ -0,0 +1,52 @@ +import { render, screen } from '@testing-library/react'; +import RadioButtonGroup from './RadioButtonGroup'; +import '@testing-library/jest-dom'; + +jest.mock('@/features/club-create/hooks/useSelectAddress', () => ({ + useSelectAddress: jest.fn(() => ({ + handleRadioChange: jest.fn(), + })), +})); + +describe('RadioButtonGroup', () => { + const mockRegister = jest.fn(); + const mockSetValue = jest.fn(); + const mockWatch = jest.fn(); + const mockErrors = {}; + + const options = [ + { label: '오프라인', value: 'OFFLINE' }, + { label: '온라인', value: 'ONLINE' }, + ]; + + it('OFFLINE 선택 시 주소 입력 필드가 표시된다', () => { + render( + , + ); + + expect(screen.getByTestId('address-input')).toBeInTheDocument(); + }); + + it('OFFLINE이 아닌 옵션 선택 시 주소 입력 필드가 표시되지 않는다', () => { + render( + , + ); + + expect(screen.queryByTestId('address-input')).not.toBeInTheDocument(); + }); +}); diff --git a/src/features/club-create/container/RadioButtonGroup.tsx b/src/features/club-create/container/RadioButtonGroup/RadioButtonGroup.tsx similarity index 96% rename from src/features/club-create/container/RadioButtonGroup.tsx rename to src/features/club-create/container/RadioButtonGroup/RadioButtonGroup.tsx index a52556d1..370415bd 100644 --- a/src/features/club-create/container/RadioButtonGroup.tsx +++ b/src/features/club-create/container/RadioButtonGroup/RadioButtonGroup.tsx @@ -2,8 +2,8 @@ import Card from '@/components/card/Card'; import { useSelectAddress } from '@/features/club-create/hooks'; import { BookClubForm } from '@/features/club-create/types'; import { UseFormSetValue, UseFormWatch } from 'react-hook-form'; -import InputField from '../components/InputField'; -import CreateClubFormField from '../components/CreateClubFormField'; +import InputField from '../../components/InputField'; +import CreateClubFormField from '../../components/CreateClubFormField'; interface RadioButtonGroupProps { options: { label: string; value: string; description?: string }[]; @@ -114,6 +114,7 @@ function RadioButtonGroup({