Contents
see List작성일 2025. 11. 30.
Jest와 React Testing Library
Jest는 Facebook에서 만든 JavaScript 테스트 프레임워크이고, React Testing Library는 사용자 관점에서 React 컴포넌트를 테스트하는 라이브러리입니다. 함께 사용하면 효과적인 프론트엔드 테스트를 작성할 수 있습니다.
언제 사용하나요?
- React 컴포넌트 렌더링 및 동작 테스트
- 사용자 인터랙션 시뮬레이션
- API 호출 모킹
- CI/CD 파이프라인에서 자동화된 테스트
설치
# Create React App에는 이미 포함됨
npm install --save-dev jest @testing-library/react @testing-library/jest-dom @testing-library/user-event기본 테스트 구조
// Button.test.js
import { render, screen, fireEvent } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import Button from "./Button";
describe("Button 컴포넌트", () => {
it("버튼 텍스트가 렌더링된다", () => {
render(<Button>클릭</Button>);
expect(screen.getByText("클릭")).toBeInTheDocument();
});
it("클릭 시 onClick이 호출된다", async () => {
const handleClick = jest.fn();
render(<Button onClick={handleClick}>클릭</Button>);
await userEvent.click(screen.getByRole("button"));
expect(handleClick).toHaveBeenCalledTimes(1);
});
});쿼리 메서드
// getBy - 요소가 없으면 에러
screen.getByText("Hello");
screen.getByRole("button");
screen.getByLabelText("이메일");
screen.getByPlaceholderText("입력하세요");
screen.getByTestId("submit-btn");
// queryBy - 요소가 없으면 null (없음 확인용)
expect(screen.queryByText("에러")).not.toBeInTheDocument();
// findBy - 비동기, Promise 반환
const item = await screen.findByText("로딩 완료");
// 복수형 - 여러 요소
const buttons = screen.getAllByRole("button");사용자 이벤트 테스트
import userEvent from "@testing-library/user-event";
it("폼 입력 및 제출 테스트", async () => {
const user = userEvent.setup();
const onSubmit = jest.fn();
render(<LoginForm onSubmit={onSubmit} />);
// 입력
await user.type(screen.getByLabelText("이메일"), "[email protected]");
await user.type(screen.getByLabelText("비밀번호"), "password123");
// 체크박스
await user.click(screen.getByLabelText("자동 로그인"));
// 선택 박스
await user.selectOptions(
screen.getByRole("combobox"),
["option1"]
);
// 제출
await user.click(screen.getByRole("button", { name: "로그인" }));
expect(onSubmit).toHaveBeenCalledWith({
email: "[email protected]",
password: "password123",
});
});비동기 테스트
import { render, screen, waitFor } from "@testing-library/react";
it("데이터 로딩 후 목록이 표시된다", async () => {
render(<UserList />);
// 로딩 상태 확인
expect(screen.getByText("로딩 중...")).toBeInTheDocument();
// 데이터 로드 대기
await waitFor(() => {
expect(screen.getByText("사용자1")).toBeInTheDocument();
});
// 또는 findBy 사용
const user = await screen.findByText("사용자1");
expect(user).toBeInTheDocument();
});API 모킹
// api.js 모킹
jest.mock("./api");
import { fetchUsers } from "./api";
beforeEach(() => {
fetchUsers.mockResolvedValue([
{ id: 1, name: "홍길동" },
{ id: 2, name: "김철수" },
]);
});
it("API에서 사용자 목록을 가져온다", async () => {
render(<UserList />);
await screen.findByText("홍길동");
expect(fetchUsers).toHaveBeenCalledTimes(1);
});
// fetch 직접 모킹
global.fetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve({ data: "test" }),
})
);커스텀 훅 테스트
import { renderHook, act } from "@testing-library/react";
import useCounter from "./useCounter";
it("useCounter 훅 테스트", () => {
const { result } = renderHook(() => useCounter(0));
expect(result.current.count).toBe(0);
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
});스냅샷 테스트
it("컴포넌트 스냅샷 일치", () => {
const { container } = render(<Button>테스트</Button>);
expect(container).toMatchSnapshot();
});주요 매처
// jest-dom 매처
expect(element).toBeInTheDocument();
expect(element).toBeVisible();
expect(element).toBeDisabled();
expect(element).toHaveClass("active");
expect(element).toHaveValue("test");
expect(element).toHaveAttribute("type", "submit");
expect(element).toHaveTextContent("Hello");팁
- 구현 상세보다 사용자 행동 테스트
- getByRole을 우선 사용 (접근성 향상)
- act() 경고 시 waitFor 사용
- 테스트 간 격리 (beforeEach로 초기화)
javascript
| No | 작성일 | Title |
|---|---|---|
| 3384 | 2026. 08. 21. | Node.js API에서 요청 취소를 제대로 처리하는 방법: AbortSignal로 외부 작업 정리하기 |
| 3352 | 2026. 08. 13. | Node.js 응답이 간헐적으로 느릴 때: 이벤트 루프 지연 측정과 CPU 작업 분리 방법 |
| 3320 | 2026. 08. 04. | JavaScript fetch 요청을 안전하게 만드는 방법: timeout·재시도·오류 처리 실전 패턴 |
| 3288 | 2026. 07. 27. | Node.js 서버 무중단 배포를 위한 Graceful Shutdown 구현 가이드 |
| 3257 | 2026. 07. 19. | Node.js 대용량 파일 처리 가이드: 스트림과 backpressure로 메모리 사용량 제어하기 |
| 3232 | 2026. 07. 11. | Node.js 실무형 에러 처리: async/await에서 실패를 일관되게 분류하고 복구 속도 높이기 |
| 3174 | 2026. 07. 02. | Node.js 환경 변수 검증 가이드: process.env를 안전한 설정 객체로 바꾸기 |
| 3123 | 2026. 06. 24. | TypeScript 타입 좁히기 운영 가이드: unknown 입력을 안전한 도메인 객체로 바꾸기 |
| 3065 | 2026. 06. 16. | 브라우저 성능 병목 찾기: PerformanceObserver로 LCP·INP·긴 작업 로그 수집하기 |
| 2978 | 2026. 06. 08. | Node.js fetch 타임아웃과 재시도 설계: 외부 API 장애 전파 줄이기 |