React

toast ui RTL

Asset Type
File Type
When to use
Last edited time
2022/05/05 12:56
Created by
Reference

์™œ RTL์ธ๊ฐ€?

React ์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ์šฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‹ค.
๊ณผ๊ฑฐ์— Enzyme์„ ์‚ฌ์šฉํ–ˆ์„ ์ˆ˜ ์žˆ๋‹ค. ๋‹ค๋ฅธ ์ ์€ React ์ปดํฌ๋„ŒํŠธ์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์•„๋‹Œ ์‹ค์ œ DOM ๋…ธ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ์ ์ด๋‹ค.
์›น ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ๊ณผ ์œ ์‚ฌํ•œ ํ™˜๊ฒฝ์—์„œ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ ์‹คํ–‰๋œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค. ๋น„์Šทํ• ์ˆ˜๋ก ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋‹ค.
๋˜ ๋‹ค๋ฅธ ์ด์œ ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์•ฑ๊ณผ ์ธํ„ฐ๋ž™์…˜ํ•˜๋Š” ๋ฐฉ์‹๊ณผ ์œ ์‚ฌํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ธฐ๋ณธ์ ์ธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ฒ ํ•™ ๋•Œ๋ฌธ์ด๋‹ค.
์‚ฌ์šฉ์ž๋Š” state, props์™€ ์ธํ„ฐ๋ž™์…˜ํ•˜๋Š” ๊ฒƒ์„ ๋ชจ๋ฅธ๋‹ค.
ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ ํ›…์„ ์‚ฌ์šฉํ•˜๋Š”์ง€, ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์™€ ํ•จ๊ป˜ ๊ณ ์ฐจ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š๋Š”๋‹ค.
๊ทธ์ € ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋ณด๊ณ  ์ธํ„ฐ๋ž™์…˜ํ•œ๋‹ค.
์˜ฌ๋ฐ”๋ฅธ props, state์ธ์ง€ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ ๋Œ€์‹  ์‚ฌ์šฉ์ž๊ฐ€ ๋ณด๊ณ  ์ˆ˜ํ–‰ํ•˜๋Š” ์ž‘์—…์„ ํ…Œ์ŠคํŠธํ•˜๋„๋ก ์„ค๊ณ„๋˜์—ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ UI๋ฅผ ๊ตฌ์ถ•ํ•˜๊ณ  HTML์„ ๊ตฌ์„ฑํ•  ๋•Œ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ์ค€์ˆ˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฒ ํ•™ ์ ์šฉํ•˜๊ธฐ

ํ…Œ์ŠคํŠธ์ผ€์ด์Šค 1

์•ฑ์ด ๋กœ๋”ฉ๋˜๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ€์žฅ ๋จผ์ € ๋ณด๊ฒŒ ๋˜๋Š” ๊ฒƒ์€ ๋ฌด์—‡์ธ๊ฐ€?
์ด๋ฆ„๊ณผ ์„ฑ์„ ์ž…๋ ฅํ•˜๋Š” ์ œ๋ชฉ๊ณผ 21์„ธ ์ด์ƒ์ธ์ง€ ๋ฌป๋Š” ์ฒดํฌ ๋ฐ•์Šค์™€ ์ทจ์†Œ/์ œ์ถœ ๋ฒ„ํŠผ์ด๋‹ค.
์‚ฌ์šฉ์ž๊ฐ€ ์ฒ˜์Œ์— ๋ณด๊ฒŒ ๋  ๊ฒƒ์„ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์„ ์ข‹์•„ํ•œ๋‹ค.

ํ…Œ์ŠคํŠธ์ผ€์ด์Šค 2

๋‹ค์Œ ์ธํ„ฐ๋ž™์…˜์€ Form ์ž‘์„ฑ์„ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๋”ฐ๋ผ์„œ ์‚ฌ์šฉ์ž๊ฐ€ Form์„ ์ž‘์„ฑํ•˜๊ธฐ ์‹œ์ž‘ํ•˜๋ฉด โ€œ21์„ธ ์ด์ƒ์ž…๋‹ˆ๊นŒ?โ€๋ผ๋Š” ๋ฉ”์‹œ์ง€์™€ ์ฒดํฌ๋ฐ•์Šค๊ฐ€ ํ‘œ์‹œ๋œ๋‹ค.
์‚ฌ์šฉ์ž๊ฐ€ ์ฒดํฌ๋ฐ•์Šค๋ฅผ ํด๋ฆญํ•˜๋ฉด ์ข‹์•„ํ•˜๋Š” ์Œ๋ฃŒ๋ฅผ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๋„๋ก ์กฐ๊ฑด๋ถ€๋กœ ๋˜ ๋‹ค๋ฅธ ์ž…๋ ฅ์ด ๋‚˜ํƒ€๋‚œ๋‹ค.
์ด๊ฑด ํ…Œ์ŠคํŠธํ•ด์•ผ ํ•˜๋Š” ๋ณ„๋„์˜ ์ฝ”๋“œ ๋ถ„๊ธฐ๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค.
์ด ํ…Œ์ŠคํŠธ๊ฐ€ ์–ด๋–ป๊ฒŒ useState์˜ ์‚ฌ์šฉ์„ ์ง์ ‘์ ์œผ๋กœ ํ…Œ์ŠคํŠธํ•˜์ง€ ์•Š๋Š”์ง€ ๋ˆˆ์—ฌ๊ฒจ๋ณด๋ผ.
์šฐ๋ฆฌ๋Š” ๋‚ด๋ถ€ state๊ฐ€ true๋‚˜ false๋กœ ๋ฐ”๋€Œ๋Š” ๊ฒƒ์ด ์•„๋‹Œ ์‚ฌ์šฉ์ž๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ ์ •๋ณด๋ฅผ ๋ณด๋Š”์ง€ ํ…Œ์ŠคํŠธํ•˜๋ ค๋Š” ๊ฒƒ์ด๋‹ค.
useReducer๋‚˜ ๋‹ค๋ฅธ ์ƒํƒœ ๊ด€๋ฆฌ ์†”๋ฃจ์…˜์„ ์‚ฌ์šฉํ•˜๋„๋ก ๋ฆฌํŒฉํ„ฐ๋งํ•ด๋„ ํ…Œ์ŠคํŠธ๋Š” ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

ํ…Œ์ŠคํŠธ์ผ€์ด์Šค 3, 4

์‚ฌ์šฉ์ž๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฑด ์ทจ์†Œ/์ œ์ถœ์ด๋‹ค. ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ๋„˜๊ฒจ์ฃผ๋Š” ๋ฐฉ์‹์ด๋‹ค. ์ด์ „ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์™€ ์•ฝ๊ฐ„ ๋‹ค๋ฅด๋‹ค.
์‚ฌ์šฉ์ž๊ฐ€ ๋ณด๋Š” ๊ฒƒ์„ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ํŠน์ • ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด ์‚ฌ์šฉ์ž์˜ ์ž‘์—…์— ๋‚ด๋ถ€์ ์œผ๋กœ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋ฐ˜์‘ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธํ•œ๋‹ค.

์„ ์–ธ์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ ์ž‘์„ฑํ•˜๊ธฐ

it("๋ญ”๊ฐ€ ์ˆ˜ํ–‰ํ•œ๋‹ค.", async () => { const onSubmit = jest.fn(); const onCancel = jest.fn(); const result = render(<ComplexForm onSubmit={onSubmit} onCancel={onCancel} />); expect(result.getByLabelText('First Name')).toBeInTheDocument(); expect(result.getByLabelText('Last Name')).toBeInTheDocument(); await act(async () => { userEvent.click(result.getByLabelText('Over 21?')); }); expect(result.getByLabelText('Favorite Drink?')).toBeInTheDocument(); });
TypeScript
๋ณต์‚ฌ
๊ฐ„๋‹จํ•œ ์ปดํฌ๋„ŒํŠธ, 1~2๊ฐœ ํ…Œ์ŠคํŠธ๋ฉด ๊ดœ์ฐฎ๋‹ค.
์ด๋Ÿฐ ํ…Œ์ŠคํŠธ๋Š” ํŒŒ์ผ์ด ํฌ๊ณ  ๋น ๋ฅด๊ฒŒ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ต๋‹ค. ์ง„ํ–‰์ƒํ™ฉ์„ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ์ฝ”๋“œ ๋ผ์ธ์„ ์ฃผ์˜๊นŠ๊ฒŒ ์ฝ์–ด์•ผ ํ•œ๋‹ค.
ํ•˜๋Š” ์ผ์„ ๋ณด์—ฌ์ฃผ๋Š” ํ…Œ์ŠคํŠธ ๋Œ€์‹  ์‚ฌ์šฉ์ž์˜ ์˜๋„๋ฅผ ์„ค๋ช…ํ•˜๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜์ž.
it("๋ญ”๊ฐ€ ์ˆ˜ํ–‰ํ•œ๋‹ค.", async () => { const { FirstNameInput, LastNameInput, clickIsOver21, FavoriteDrinkInput } = renderComplexForm(); // ์ด๋ฆ„ ์ž…๋ ฅ, ์„ฑ ์ž…๋ ฅ, 21์ด์ƒ์ธ์ง€ ์ฒดํฌ๋ฐ•์Šค, ์ฆ๊ฒจ ์ฐพ๋Š” ์Œ๋ฃŒ ์ž…๋ ฅ expect(FirstNameInput()).toBeInTheDocument(); expect(LastNameInput()).toBeInTheDocument(); // ์ž…๋ ฅ 2๊ฐœ ์ž˜ ๋“ค์–ด์˜ค๋‚˜? await clickIsOver21(); // ํด๋ฆญ์„ ๋น„๋™๊ธฐ๋กœ ๊ธฐ๋‹ค๋ฆผ expect(FavoriteDrinkInput()).toBeInTheDocument(); // ์ž…๋ ฅ ์ž˜ ๋“ค์–ด์˜ค๋‚˜? });
TypeScript
๋ณต์‚ฌ
ํ•จ์ˆ˜๋งŒ ์ฝ์–ด๋„ ํ˜„์žฌ ์ƒํ™ฉ์„ ์ฆ‰์‹œ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋‹ค.
์ด๋ฆ„๊ณผ ์„ฑ ์ž…๋ ฅ์ด doc์— ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. ๊ทธ ๋‹ค์Œ โ€˜21์„ธ ์ด์ƒ์ž…๋‹ˆ๊นŒ?โ€™ ์ฒดํฌ๋ฐ•์Šค๋ฅผ ํด๋ฆญํ•œ ๋‹ค์Œ ์ฆ๊ฒจ ์ฐพ๋Š” ์Œ๋ฃŒ ์ž…๋ ฅ์ด doc์— ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.
์ฝ๊ธฐ ์‰ฝ๊ณ  renderComplexForm ํ•จ์ˆ˜์—์„œ ๋‚ด๋ณด๋‚ธ ํ…Œ์ŠคํŠธ ํ—ฌํผ๋ฅผ ๋‹ค๋ฅธ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์—์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
์ฝ”๋“œ ์ค‘๋ณต์„ ์ค„์ด๊ณ  ๊ฐ€๋…์„ฑ์„ ํฌ๊ฒŒ ๋†’์—ฌ์•ผ ํ•œ๋‹ค. ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ์—…๋ฐ์ดํŠธํ•  ๋•Œ ํ›จ์”ฌ ์‰ฝ๋‹ค.
๋Œ€๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ์—์„œ ๋งค์šฐ ์›ํ™œํ•˜๊ฒŒ ํ™•์žฅํ•˜๊ณ  ๋ณต์žกํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‰ฝ๊ฒŒ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋‹ค.

ComplexForm ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ

import React from "react"; import userEvent from "@testing-library/user-event"; import { act, render } from "@testing-library/react"; import ComplexForm, { ComplexFormProps } from "./ComplexForm"; /** * ์ด๊ฑด ๋ชจ๋“  ํ…Œ์ŠคํŠธ์—์„œ ํ˜ธ์ถœ๋˜๋Š” ํ…Œ์ŠคํŠธ ์„ค์ •์ด๋‹ค. * * ํ…Œ์ŠคํŠธ ์„ค์ • ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค๋ฉด ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์— ๋Œ€ํ•ด ์ž‘์„ฑํ•ด์•ผ ํ•˜๋Š” ๋ฐ˜๋ณต ์ฝ”๋“œ์˜ ์–‘์ด * ์ค„์–ด๋“ค๊ณ  ํ…Œ์ŠคํŠธ์ค‘์ธ ์ปดํฌ๋„ŒํŠธ์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๊ธฐ ์œ„ํ•œ ์„ ์–ธ์  ํ…Œ์ŠคํŠธ ํ—ฌํผ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. */ function renderComplexForm(props?: Partial<ComplexFormProps>) { /* ์ œ์ถœ๊ณผ ์ทจ์†Œ ๋ฒ„ํŠผ์„ ์œ„ํ•œ mock ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์„ค์ •ํ•œ๋‹ค. */ const onSubmit = jest.fn(); const onCancel = jest.fn(); /* React Testing Library๋ฅผ ์‚ฌ์šฉํ•ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•œ๋‹ค. */ const result = render(<ComplexForm onSubmit={onSubmit} onCancel={onCancel} {...props} />); /* ๋‹ค์Œ 7๊ฐœ์˜ ํ•จ์ˆ˜๋Š” ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ณตํ†ต DOM ์š”์†Œ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•œ ํ—ฌํผ ํ•จ์ˆ˜์ด๋‹ค. */ const Heading = () => result.getByText("Welcome, Zerry"); const FirstNameInput = () => result.getByLabelText("First Name"); const LastNameInput = () => result.getByLabelText("Last Name"); const IsOver21Input = () => result.getByLabelText("Are you at least 21 years old?"); const FavoriteDrinkInput = () => result.queryByLabelText("What's your favorite drink?"); const CancelButton = () => result.getByText("Cancel"); const SubmitButton = () => result.getByText("Apply"); /* ๋‹ค์Œ 6๊ฐœ์˜ ํ•จ์ˆ˜๋Š” DOM ์š”์†Œ์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๊ธฐ ์œ„ํ•œ ํ—ฌํผ ํ•จ์ˆ˜์ด๋‹ค. */ function changeFirstName(name: string) { userEvent.type(FirstNameInput(), name); } function changeLastName(name: string) { userEvent.type(LastNameInput(), name); } function changeFavoriteDrinkInput(name: string) { userEvent.type(FavoriteDrinkInput() as HTMLElement, name); } async function clickIsOver21() { await act(async () => { userEvent.click(IsOver21Input()); }); } function clickSubmit() { userEvent.click(SubmitButton()); } function clickCancel() { userEvent.click(CancelButton()); } /* ๋งˆ์ง€๋ง‰์œผ๋กœ ์ด ์œ ํ‹ธ๋ฆฌํ‹ฐ ๋ Œ๋” ํ•จ์ˆ˜์—์„œ ๋ชจ๋“  ํ•จ์ˆ˜์™€ ์ƒ์ˆ˜๋ฅผ ๋‚ด๋ณด๋‚ธ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ชจ๋“  ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์—์„œ ํ•„์š”ํ•œ ๊ฒƒ์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. */ return { result, onSubmit, changeFirstName, changeLastName, clickIsOver21, clickSubmit, clickCancel, FirstNameInput, LastNameInput, IsOver21Input, SubmitButton, CancelButton, Heading, FavoriteDrinkInput, changeFavoriteDrinkInput, onCancel, }; } describe("<ComplexForm />", () => { it("๊ธฐ๋ณธ ํ•„๋“œ๋ฅผ ๋ Œ๋”๋งํ•ด์•ผ ํ•œ๋‹ค.", async () => { const { FirstNameInput, LastNameInput, IsOver21Input, SubmitButton, Heading, FavoriteDrinkInput, CancelButton } = renderComplexForm(); // ํ—ค๋” expect(Heading()).toBeInTheDocument(); // ์ž…๋ ฅ expect(FirstNameInput()).toBeInTheDocument(); expect(LastNameInput()).toBeInTheDocument(); expect(IsOver21Input()).toBeInTheDocument(); expect(FavoriteDrinkInput()).not.toBeInTheDocument(); // ๋ฒ„ํŠผ๋“ค expect(CancelButton()).toBeInTheDocument(); expect(SubmitButton()).toBeInTheDocument(); }); it("21์„ธ ์ด์ƒ ์ฒดํฌ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ์ข‹์•„ํ•˜๋Š” ์Œ๋ฃŒ ์ž…๋ ฅ์„ ํ† ๊ธ€ํ•ด์•ผํ•œ๋‹ค.", async () => { const { clickIsOver21, FavoriteDrinkInput } = renderComplexForm(); expect(FavoriteDrinkInput()).not.toBeInTheDocument(); await clickIsOver21(); expect(FavoriteDrinkInput()).toBeInTheDocument(); }); it("์ทจ์†Œ ๋ฒ„ํŠผ์ด ํด๋ฆญ๋˜๋ฉด onCancel ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜์•ผ ํ•œ๋‹ค.", async () => { const { clickCancel, onCancel } = renderComplexForm(); clickCancel(); expect(onCancel).toHaveBeenCalled(); }); it("form ๊ฐ’์œผ๋กœ onSubmit์„ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค.", async () => { const { changeFirstName, changeLastName, clickIsOver21, changeFavoriteDrinkInput, clickSubmit, onSubmit } = renderComplexForm(); changeFirstName('Zerry'); changeLastName('Hogan'); await clickIsOver21(); changeFavoriteDrinkInput('Bourbon'); clickSubmit(); expect(onSubmit).toHaveBeenCalledWith({ first_name: 'Zerry', last_name: 'Hogan', is_over_21: true, favorite_drink: 'Bourbon', }); }); });
TypeScript
๋ณต์‚ฌ
๋‚˜๋ˆ ์„œ ์„ค๋ช…ํ•˜๊ฒ ๋‹ค.
1.
๋จผ์ € ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ ๋ Œ๋”๋ง ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ ๋‹ค. render ํ•จ์ˆ˜๋Š” React Testing Library๋ฅผ ์‚ฌ์šฉํ•ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๊ณ  ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ์œ„ํ•œ ํ—ฌํผ ํ•จ์ˆ˜๋ฅผ ๋‚ด๋ณด๋‚ด๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. ๋ Œ๋”๋ง ๊ธฐ๋Šฅ์„ ์œ„ํ•œ ๋ณ„๋„์˜ ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด ํ…Œ์ŠคํŠธ๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜๋„ ์žˆ๋‹ค.
2.
๊ฐ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋Š”ย renderComplexForm์„ ํ˜ธ์ถœํ•ด ํŠน์ • ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์— ํ•„์š”ํ•œ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.
3.
์ž…๋ ฅ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ดย changeFirstnameย ํ…Œ์ŠคํŠธ ํ—ฌํผ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š” ๋ฐฉ์‹์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜๊ณ  ํ…Œ์ŠคํŠธ์—์„œ ์–ด๋–ค ์ผ์ด ์ผ์–ด๋‚˜๋Š”์ง€ ๋ช…๋ฐฑํžˆ ๋ณด์—ฌ์ค€๋‹ค.
4.
renderComplexFormย ํ•จ์ˆ˜๋Š”ย propsย ์ธ์ˆ˜๋ฅผ ๋ฐ›๋Š”๋‹ค. ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ปดํฌ๋„ŒํŠธ์˜ UI ๋˜๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋ณด๋Š” ๊ฒƒ์„ ๋ณ€๊ฒฝํ•˜๋Š” props๋ฅผ ๋ฐ›๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค. ๊ฐ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๊ฐ€ย props๋ฅผ ๋„˜๊ธฐ๋„๋ก ํ—ˆ์šฉํ•ด ์„œ๋กœ ๋‹ค๋ฅธ ์ƒํ˜ธ์ž‘์šฉ์„ ํ…Œ์ŠคํŠธํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
5.
onSubmit๊ณผย onCancelย props๋ฅผ ์œ„ํ•ด jest mock ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค. jest mock ํ•จ์ˆ˜๋Š” ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜์—ˆ๋Š”์ง€, ๋ช‡ ๋ฒˆ์ด๋‚˜ ํ˜ธ์ถœ๋˜์—ˆ๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์–ด๋–ค ์ธ์ˆ˜๋กœ ํ˜ธ์ถœ๋˜์—ˆ๋Š”์ง€ ํ…Œ์ŠคํŠธํ•˜๋Š” ๋ฐ ์œ ์šฉํ•˜๋‹ค. ๋งˆ์ง€๋ง‰ ๋‘ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์—์„œ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ์ ์ ˆํ•œ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ–ˆ๋Š”์ง€ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด jest mock ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.
๊ฒฐ๊ณผ์ ์œผ๋กœ ๋”์šฑ ์ฝ๊ธฐ ์‰ฝ๊ณ  ํ™•์žฅ ๊ฐ€๋Šฅํ•˜๋ฉฐ ์˜ค๋ž˜ ์ง€์†๋  ์ˆ˜ ์žˆ๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค๊ณ  ๋ฏฟ๋Š”๋‹ค. ์ด ํ…Œ์ŠคํŠธ๋กœ ๋Œ์•„์™€์„œ ์ž…๋ ฅ์„ ์ถ”๊ฐ€ํ•˜๊ณ  ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๊ตฌ๋ฌธ ๋ถ„์„ํ•˜์—ฌ ์ƒˆ ํ…Œ์ŠคํŠธ ์ ์šฉ ๋ฒ”์œ„๋ฅผ ์ถ”๊ฐ€ํ•  ์œ„์น˜๋ฅผ ์•Œ ํ•„์š” ์—†์ด ๋ช‡ ๋ถ„ ์•ˆ์— ํ…Œ์ŠคํŠธ๋ฅผ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ๋‹ค.