๋ฆฌ์•กํŠธ ํ›… ํ…Œ์ŠคํŠธ (act ํ•จ์ˆ˜)

date
2025-10-18
order
7

๋ฆฌ์•กํŠธ ํ›… ํ…Œ์ŠคํŠธ

๊ฐ•์˜์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์ œ์˜ ๊ตฌ์กฐ๋Š” ์ด๋ ‡๋‹ค. <NavigationBar />์•ˆ์— <ConfirmModal /> ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ๋ชจ๋‹ฌ์„ ํ‘œ์‹œํ•˜๊ณ  ์•ˆํ•˜๊ณ ๋ฅผ isModalOpened๋ผ๋Š” ์ƒํƒœ๋กœ ๊ฒฐ์ •ํ•˜๋Š”๋ฐ, ๊ทธ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ <NavigationBar />์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ useState()ํ›…์„ ์‚ฌ์šฉํ•ด ์ง์ ‘ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๊ณ , useConfirmModal()์ด๋ผ๋Š” ์ปค์Šคํ…€ ํ›…์œผ๋กœ ๋ถ„๋ฆฌ์‹œ์ผœ ๊ด€๋ฆฌํ•œ๋‹ค.

import { useState } from 'react';

const useConfirmModal = (initialValue = false) => {
  const [isModalOpened, setIsModalOpened] = useState(initialValue);

  const toggleIsModalOpened = () => {
    setIsModalOpened(!isModalOpened);
  };

  return {
    toggleIsModalOpened,
    isModalOpened,
  };
};

export default useConfirmModal;

์ด๋ ‡๊ฒŒ ์ปค์Šคํ…€ ํ›…์œผ๋กœ ๋ถ„๋ฆฌํ•ด ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋ฉด ๋˜‘๊ฐ™์€ ๊ธฐ๋Šฅ์„ ํ•„์š”๋กœ ํ•˜๋Š” ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ์ด ๋†’์•„์ง„๋‹ค๋Š” ์žฅ์  ์™ธ์—๋„ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์žฅ์ ์ด ์žˆ๋‹ค.

  • ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ๋กœ ์ธํ•œ ๊ฐ€๋…์„ฑ ํ–ฅ์ƒ
  • ๋กœ์ง ์บก์Аํ™”๋กœ ์ธํ•œ ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ ์ฆ๊ฐ€

renderHook

ํ…Œ์ŠคํŒ…๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ์ œ๊ณตํ•˜๋Š” API.

๋ฆฌ์•กํŠธ ํ›…์„ ๊ฒ€์ฆํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ํ›…์„ ํ˜ธ์ถœํ•˜๊ณ  ๋‚œ ํ›„์— ํ›…์ด ๋ฐ˜ํ™˜ํ•˜๋Š” isMOdalOpened์™€ ๊ฐ™์€ ์ƒํƒœ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋ณ€๊ฒฝ๋˜๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋ฆฌ์•กํŠธ ๊ทœ์น™์ƒ ๋ฆฌ์•กํŠธ ํ›…(๋ฆฌ์•กํŠธ ์ž์ฒด ํ›…, ์ปค์Šคํ…€ ํ›… ๋ชจ๋‘)์€ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ๋งŒ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์ง€๊ธˆ ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๊ณ ์žˆ๋Š” ํŒŒ์ผ์ธ useCOnfirmModal.spec.jsx๋Š” ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์•„๋‹ˆ๊ธฐ๋•Œ๋ฌธ์— (์ผ๋ฐ˜ jsํŒŒ์ผ) ํ›…์„ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†์ง€๋งŒ, ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด renderHook() api๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

const { result, rerender } = renderHook(useConfirmModal);
// or
const { result } = renderHook(() => useConfirmModal(true));

expect(result.current.isModalOpened).toBe(false);
// or 

result : ํ›…์„ ํ˜ธ์ถœํ•˜์—ฌ ์–ป์€ ๊ฒฐ๊ณผ ๊ฐ’. rerender : ํ›…์„ ์›ํ•˜๋Š” ์ธ์ž์™€ ํ•จ๊ป˜์ƒˆ๋กœ ํ˜ธ์ถœํ•˜์—ฌ ์ƒํƒœ๋ฅผ ๊ฐฑ์‹ . (๊ฐ•์˜์—์„œ๋Š” ๋ณด์—ฌ์ฃผ๊ธฐ๋งŒ ํ•˜๊ณ  ์‚ฌ์šฉ์€ ์•ˆํ•œ๋‹ค?)

act ํ•จ์ˆ˜

์ƒํ˜ธ ์ž‘์šฉ(๋ Œ๋”๋ง, ์ดํŽ™๋“œ ๋“ฑ)์„ ํ•จ๊ป˜ ๊ทธ๋ฃนํ™”ํ•˜๊ณ  ์‹คํ–‰ํ•ด ๋ Œ๋”๋ง๊ณผ ์—…๋ฐ์ดํŠธ๊ฐ€ ์‹ค์ œ ์•ฑ์ด ๋™์ž‘ํ•˜๋Š” ๊ฒƒ๊ณผ ์œ ์‚ฌํ•œ ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•จ.

  • ์ฆ‰ act๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์˜ ๊ฐ€์ƒ์˜ ๋”(jsdom)์— ์ œ๋Œ€๋กœ ๋ฐ˜์˜๋œ๋‹ค. ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•œ ๋’ค ์—…๋ฐ์ดํŠธ ํ•˜๋Š” ์ฝ”๋“œ์˜ ๊ฒฐ๊ณผ๋ฅผ ๊ฒ€์ฆํ•˜๊ณ  ์‹ถ์„๋•Œ ์‚ฌ์šฉ.

๊ทธ๋Ÿฐ๋ฐ ์™œ ์ด์ „ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ(UI ์ปดํฌ๋„ŒํŠธ)์—์„œ๋Š” actํ•จ์ˆ˜๊ฐ€ ์—†์ด ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์—ˆ์„๊นŒ? ์™œ๋ƒํ•˜๋ฉด, render ํ•จ์ˆ˜ ์ž์ฒด์—์„œ ๋‚ด๋ถ€์ ์œผ๋กœ act ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ.

// ์‹คํŒจ
it('ํ›…์˜ toggleIsModalOpened()๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด isModalOpened ์ƒํƒœ๊ฐ€ toggle๋œ๋‹ค.', () => {
  const { result } = renderHook(useConfirmModal);
  result.current.toggleIsModalOpened();
  expect(result.current.isModalOpened).toBe(true);
});

//์„ฑ๊ณต
it('ํ›…์˜ toggleIsModalOpened()๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด isModalOpened ์ƒํƒœ๊ฐ€ toggle๋œ๋‹ค.', () => {
  const { result } = renderHook(useConfirmModal);
  act(() => {
    result.current.toggleIsModalOpened();
  });
  expect(result.current.isModalOpened).toBe(true);
});