React Testing Library์™€ ์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ

date
2025-10-18
order
4

React Testing Library์™€ ์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ

ํŠน์ • ๊ฐœ๋ฐœ(๋ฆฌ์•กํŠธ ์™ธ ๋ทฐ,์Šค๋ฒจํŠธ์—์„œ๋„), ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ์— ์ข…์†๋˜์ง€๋Š” ์•Š๋Š”๋‹ค.

Testing Library์˜ ํ•ต์‹ฌ ์ฒ ํ•™์€ UI ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉ์ž๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ํ…Œ์ŠคํŠธ ํ•˜๋Š”๊ฒƒ.

  • ์‚ฌ์šฉ์ž๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹ : DOM ๋…ธ๋“œ ์กฐํšŒ, ์‚ฌ์šฉ์ž์™€ ๋น„์Šทํ•œ ๋ฐฉ์‹์œผ๋กœ ์ด๋ฒคํŠธ ๋ฐœ์ƒ.
  • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ ์›์น™์ค‘ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ž‘์„ฑํ•ด์•ผํ•œ๋‹ค๋Š” ์›์น™๊ณผ ์ผ์น˜.
  • getBy api์ค‘ role, label-text, image-alt-text ์ฒ˜๋Ÿผ ์‚ฌ์šฉ์ž ๊ด€์ ์— ๊ฐ€๊นŒ์šด api๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

userEvent

// TextField.spec.jsx
import render from '@/utils/test/render';

it('ํ…์ŠคํŠธ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด onChange prop์œผ๋กœ ๋“ฑ๋กํ•œ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค', async () => {
  const { user } = await render(<TextField />);
  const textInput = screen.getByPlaceholderText('์ƒํ’ˆ๋ช…์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.');
  await user.type(textInput, 'test');
  ...
});

// render.jsx
import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

export default async component => {
  const user = userEvent.setup();

  return {
    user,
    ...render(component),
  };
};

userEvent.setup() ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” user๊ฐ์ฒด๋Š” ์‚ฌ์šฉ์ž์˜ ํ–‰๋™์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ํ•˜๋Š” ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

spy ํ•จ์ˆ˜

vi.fn() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ์ŠคํŒŒ์ด ํ•จ์ˆ˜๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์—์„œ ํŠน์ • ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜์—ˆ๋Š”์ง€, ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ์–ด๋–ค ๊ฒƒ์ด ๋„˜์–ด์™”๊ณ  ์–ด๋–ค ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š”์ง€ ๋“ฑ ๋‹ค์–‘ํ•œ ๊ฐ’๋“ค์„ ์ €์žฅํ•˜๊ณ  ์žˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ ์‹คํ–‰๋˜๋Š” ํ•จ์ˆ˜๋ฅผ ๊ฒ€์ฆํ•˜๊ธฐ ์œ„ํ•ด ํ•„์ˆ˜๋‹ค.

it('ํ…์ŠคํŠธ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด onChange prop์œผ๋กœ ๋“ฑ๋กํ•œ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค', async () => {
  const spy = vi.fn();

  const { user } = await render(<TextField onChange={spy} />);
  const textInput = screen.getByPlaceholderText('ํ…์ŠคํŠธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.');
  await user.type(textInput, 'test');

  expect(spy).toHaveBeenCalledWith('test');
});