
✅React Testing Libraries란??
React Testing Library는 React 애플리케이션의 컴포넌트를 테스트하기 위한 라이브러리이다. 주로 사용자 관점에서의 컴포넌트 동작을 테스트하도록 설계되어 있으며, 컴포넌트가 실제로 어떻게 동작하는지를 검증하는 데 중점을 둔다.
※ 프론트엔드 테스트 종류
항목 | React Testing Library | Vitest | Cypress |
목적 | 단위 테스트, 통합 테스트 | 단위 테스트, 통합 테스트 | 엔드 투 엔드(E2E) 테스트, 통합 테스트 |
실행 환경 | 노드 환경에서 가상의 DOM 사용 | 노드 환경에서 Vite와 통합해 빠르게 실행 | 실제 브라우저 환경에서 테스트 |
사용 용도 | 컴포넌트의 단위 테스트 | 컴포넌트/함수의 단위 및 통합 테스트 | 전체 애플리케이션 흐름, UI 상호작용 테스트 |
비동기 작업 | 간단한 비동기 로직 테스트 가능 | 비동기 로직 테스트 가능 | 네트워크 요청, 브라우저 렌더링 테스트 가능 |
속도 | 매우 빠름 | 매우 빠름 (특히 Vite와 통합 시) | 상대적으로 느릴 수 있음 |
시각적 피드백 | 콘솔 출력 | 콘솔 출력 | 스크린샷 및 비디오 캡처 가능 |
사용자 관점에서의 컴포넌트 동작을 테스트하도록 설계되어있다는게 무슨 말일까?? Vitest 단위 테스트와 비교해서 알아보자!
React Testing Library를 사용할 때:
test('버튼 클릭 시 텍스트 변경', () => {
render(<MyComponent />);
const button = screen.getByRole('button', { name: /클릭/i });
fireEvent.click(button);
expect(screen.getByText(/변경된 텍스트/i)).toBeInTheDocument();
});
Vitest로 단위 테스트를 작성할 때:
test('함수 호출 테스트', () => {
const mockFunction = vi.fn();
myFunction(mockFunction);
expect(mockFunction).toHaveBeenCalled();
});
React Testing Library는 UI의 동작과 사용자 상호작용을 중심으로 작성된 반면, Vitest의 예시는 함수 호출 여부를 검증하는 단위 테스트이다.
React Testing Library: 사용자 중심의 UI 테스트로, 실제 사용자처럼 컴포넌트와 상호작용하며 결과를 검증한다.
Vitest: 테스트 러너로, 내부 구현 세부 사항을 검증하는 단위 테스트를 작성할 수 있지만, UI 상호작용 중심의 테스트를 원한다면 React Testing Library와 함께 사용하는 것이 좋다.
그럼 다시 React Testing Library로 돌아와서 Jest 와 React Testing Library의 역할을 살펴보면서 이해해보자!
✅Jest란 무엇일까?
React Testing Library는 DOM 상호작용을 중심으로 컴포넌트를 테스트하는 도구이지만, 테스트 환경을 구성하고 실행하는 역할은 수행하지 않는다. Jest는 React Testing Library와 함께 사용되는 테스트 러너로, 테스트를 실행하고 결과를 평가하는 중요한 역할을 한다.
※ 테스트 러너란?
✔️테스트 코드를 실행하고 결과를 보고하는 역할을 한다.
✔️테스트 코드의 실행 환경을 설정하고, 각 테스트 케이스를 실행하여 그 결과를 표시한다.
✔️테스트 러너는 테스트 스위트를 관리하고, 테스트 결과를 출력하며, 테스트 환경의 초기화와 정리를 담당한다.
✔️대표적인 테스트 러너로는 Jest, Mocha, Jasmine, Karma 등이 있다.
Jest란?
✔️ 자바스크립트 테스트 프레임워크이다.
✔️ 사용자는 Jest 를 이용하여 테스트 코드를 작성한다.
✔️ 하지만 Node.js 환경에서 실행되기 때문에 DOM이 없다.
✔️ DOM없이는 React 컴포넌트 테스트가 불가능하다. 그래서 React Testing Library에서 제공하는 가상의 DOM을 이용한다.
Jest에서 제공하는 함수
- describe() : 테스트 그룹을 정의할 때 사용
- test() : 개별 테스트 케이스를 정의
- beforeEach() : 각 테스트가 실행되기 전에 실행
- afterEach() : 각 테스트가 실행된 후에 실행
- beforeAll() : 모든 테스트가 실행되기 전에 한 번 실행
- afterAll() : 모든 테스트가 실행된 후에 한 번 실행
- expect() : 테스트에서 값이나 상태를 검증할 때 사용
- 주요 Matcher들
- toBe() : 엄격한 일치 여부를 확인, ===와 유사한 비교
- toBeInTheDocument() : 해당 요소가 문서에 존재하는지 확인
- Mock관련 함수
- jest.fn() : Jest에서 함수의 동작을 모킹하기 위해 사용되는 함수
✅간단한 실습
1. testing-library와 jest 설치하기
npm install @testing-library/react @testing-library/jest-dom
설치하고 나면 pacage.json에 관련 코드가 생성된 걸 볼 수있다.
"scripts": {
"test":"jest"
},
"devDependencies": {
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
}
2-1. 필요한 모듈 .babelrc 파일에 설정하기
{
"presets": [
[
"@babel/preset-env", //최신 JavaScript 문법(ES6 이상)을 구버전 JavaScript로 변환
{
"modules": false, // Babel이 ES6 모듈 문법(import/export)을 CommonJS로 변환하지 않게
"targets": {
"node": "16"
}
}
],
"@babel/preset-react" // React JSX 문법을 JavaScript로 변환해 주는 preset
],
"env": {
"test": {
"plugins": [
"@babel/plugin-transform-modules-commonjs", // 테스트 환경에서는 CommonJS로 변환이 필요하기 때문에
"@babel/plugin-transform-runtime"
// Babel이 코드 내에서 반복적으로 사용하는 헬퍼 함수(예: async/await, spread 문법 등)를 전역 공간에 중복 없이 공유
// 비동기 코드나 async/await 문법이 포함된 코드를 테스트할 때 중요하며, 최신 문법을 지원하지 않는 환경에서 동작하도록 폴리필을 추가
]
}
}
2-2. Jest가 브라우저 환경을 모방할 수 있도록 jest.config.cjs 파일 설정하기
module.exports = {
testEnvironment: "jsdom",
};
나와 같은 경우 그냥 .js파일로 돌리면

이런 에러가 발생해서 cjs로 변경해주었다.
cjs vs js 차이점
- .cjs: CommonJS 모듈 시스템을 사용하는 파일 확장자. CommonJS는 require()와 module.exports 문법을 사용하며, Node.js에서 오랫동안 사용되어온 모듈 시스템.
- .js: 기본적으로 ES Modules (ESM) 형식을 사용하는 파일 확장자. ESM은 import/export 문법을 사용.
왜 cjs 확장자를 사용해야 오류가 안 나는가?
Node.js는 ES Modules (ESM)과 CommonJS (CJS)를 모두 지원하지만, Jest는 기본적으로 CommonJS를 사용한다. jest.config.js 파일에서 module.exports를 사용하면 CommonJS 문법을 사용하고 있다는 의미인데, Node.js는 .js 파일을 ESM으로 처리하려고 시도할 수 있다.
3. 테스트 적용시킬 CreateSchedule 컴포넌트 준비
import React, { useState } from "react";
const CreateSchedule = ({ addResult }) => {
const [company_name, setCompanyName] = useState("");
const [deadline, setDeadline] = useState("");
const [result_date, setResultDate] = useState("");
const [result, setResult] = useState(3);
const handleSubmit = (e) => {
e.preventDefault();
const newResult = {
company_name,
deadline,
result_date,
result,
};
addResult(newResult);
clearForm();
};
const clearForm = () => {
setCompanyName("");
setDeadline("");
setResultDate("");
setResult(3);
};
const handleResultChange = (e) => {
const value = e.target.value;
if (value === "합격") {
setResult(1);
} else if (value === "불합격") {
setResult(2);
} else {
setResult(3);
}
};
return (
<form onSubmit={handleSubmit}>
<h2>스케줄 추가</h2>
<div className="form_wrap">
<div>
<label htmlFor="company_name">회사명</label>
<input
id="company_name"
type="text"
placeholder="회사명"
value={company_name}
onChange={(e) => setCompanyName(e.target.value)}
required
data-testid="company-name-input"
/>
</div>
<div>
<label htmlFor="deadline">서류지원 마감</label>
<input
id="deadline"
type="datetime-local"
value={deadline}
onChange={(e) => setDeadline(e.target.value)}
required
data-testid="deadline-input"
/>
</div>
<div>
<label htmlFor="result_date">결과 발표</label>
<input
id="result_date"
type="datetime-local"
value={result_date}
onChange={(e) => setResultDate(e.target.value)}
required
data-testid="result-date-input"
/>
</div>
<div>
<label htmlFor="result">결과</label>
<select
id="result"
value={result === 1 ? "합격" : result === 2 ? "불합격" : "진행 중"}
onChange={handleResultChange}
data-testid="result-select"
>
<option value="진행 중">진행 중</option>
<option value="합격">합격</option>
<option value="불합격">불합격</option>
</select>
</div>
<div className="button_wrap">
<button type="submit" data-testid="submit-button">
추가
</button>
</div>
</div>
</form>
);
};
export default CreateSchedule;
- data-testid: 테스트 중에 요소를 식별하기 위한 고유한 식별자로 사용. React Testing Library에서 screen.getByTestId()와 같은 함수를 통해 이 요소를 쉽게 찾아서 테스트할 수 있다.
4. CreateSchedule.test.js작성
import React from "react";
import "@testing-library/jest-dom";
import { render, screen, fireEvent } from "@testing-library/react";
import CreateSchedule from "./CreateSchedule";
describe("CreateSchedule 컴포넌트 테스트", () => {
test("폼이 올바르게 렌더링된다", () => {
render(<CreateSchedule addResult={jest.fn()} />);
expect(screen.getByTestId("company-name-input")).toBeInTheDocument();
expect(screen.getByTestId("deadline-input")).toBeInTheDocument();
expect(screen.getByTestId("result-date-input")).toBeInTheDocument();
expect(screen.getByTestId("result-select")).toBeInTheDocument();
expect(screen.getByRole("button", { name: /추가/i })).toBeInTheDocument();
});
test("입력 필드에 값을 입력하고 제출하면 addResult가 호출된다", () => {
const addResultMock = jest.fn();
render(<CreateSchedule addResult={addResultMock} />);
// 입력값 설정
fireEvent.change(screen.getByTestId("company-name-input"), {
target: { value: "회사 A" },
});
fireEvent.change(screen.getByTestId("deadline-input"), {
target: { value: "2024-10-12T12:00" },
});
fireEvent.change(screen.getByTestId("result-date-input"), {
target: { value: "2024-10-15T12:00" },
});
fireEvent.change(screen.getByTestId("result-select"), {
target: { value: "합격" },
});
// 제출 버튼 클릭
fireEvent.click(screen.getByRole("button", { name: /추가/i }));
// addResult가 호출되었는지 확인
expect(addResultMock).toHaveBeenCalledWith({
company_name: "회사 A",
deadline: "2024-10-12T12:00",
result_date: "2024-10-15T12:00",
result: 1, // "합격" 선택 시 result는 1
});
});
test("폼 제출 후 입력값이 초기화된다", () => {
const addResultMock = jest.fn();
render(<CreateSchedule addResult={addResultMock} />);
// 입력값 설정
fireEvent.change(screen.getByTestId("company-name-input"), {
target: { value: "회사 A" },
});
fireEvent.change(screen.getByTestId("deadline-input"), {
target: { value: "2024-10-12T12:00" },
});
fireEvent.change(screen.getByTestId("result-date-input"), {
target: { value: "2024-10-15T12:00" },
});
fireEvent.change(screen.getByTestId("result-select"), {
target: { value: "합격" },
});
// 제출 버튼 클릭
fireEvent.click(screen.getByRole("button", { name: /추가/i }));
// 입력 필드가 초기화되었는지 확인
expect(screen.getByTestId("company-name-input").value).toBe("");
expect(screen.getByTestId("deadline-input").value).toBe("");
expect(screen.getByTestId("result-date-input").value).toBe("");
expect(screen.getByTestId("result-select").value).toBe("진행 중");
});
});
1. 설정 및 준비
- @testing-library/jest-dom: 추가적인 Jest 매처를 사용하기 위해 임포트. 이를 통해 toBeInTheDocument()와 같은 메소드를 사용
- render, screen, fireEvent: React Testing Library의 유틸리티 함수들을 임포트
- render: 컴포넌트를 실제 DOM에 렌더링
- screen: 렌더링된 컴포넌트에서 요소를 찾기 위한 API를 제공
- fireEvent: 사용자 이벤트를 시뮬레이션하는 데 사용
2. 테스트 스위트 설명
- describe("CreateSchedule 컴포넌트 테스트", () => {...}): 이 블록 안에는 CreateSchedule 컴포넌트에 대한 여러 테스트가 포함되어 있다.
3. 테스트 케이스 분석
테스트 1: "폼이 올바르게 렌더링된다"
- 목적: CreateSchedule 컴포넌트가 올바르게 렌더링되는지 확인
- 흐름:
- render 함수를 사용하여 컴포넌트를 렌더링
- getByTestId 및 getByRole를 사용하여 입력 필드와 버튼이 DOM에 존재하는지 확인
- 모든 요소가 존재해야 하므로 각각의 expect 문이 true이면 테스트가 통과
테스트 2: "입력 필드에 값을 입력하고 제출하면 addResult가 호출된다"
- 목적: 폼에 값을 입력하고 제출할 때 addResult가 올바른 인자로 호출되는지 확인
- 흐름:
- jest.fn()을 사용하여 addResult의 모킹 함수를 생성
- 각 입력 필드에 fireEvent.change로 값을 설정
- 제출 버튼을 클릭하여 폼을 제출
- expect 문으로 addResultMock이 호출되었는지 확인하고, 올바른 인자가 전달되었는지 검사
테스트 3: "폼 제출 후 입력값이 초기화된다"
- 목적: 폼 제출 후 입력 필드가 초기화되는지 확인
- 흐름:
- 이전 테스트와 마찬가지로 입력값을 설정한 후, 제출 버튼을 클릭
- 입력 필드의 값을 검사하여 각 필드가 초기화되었는지 확인. 이때, company-name-input은 비어 있어야 하고, result-select는 기본값인 "진행 중"이 되어야 한다.
5. 테스트 실행
npm test
실행하고 나서

이러 타입에러를 마주했다. 그 이유는 Jest 매처가 확장시켜주는 라이브러리를 추가해줘야 한다. 즉, Jest에 기본적으로 포함되지 않고, 추가적인 라이브러리에서 제공되는 함수이다.
그래서CreateSchedule.test.js에 해당 라이브러리 import 해주고
import "@testing-library/jest-dom";
jest.config.cjs파일에
setupFilesAfterEnv: ["<rootDir>/jest.config.cjs"]
이 코드를 추가해줬다. setupFilesAfterEnv속성이 Jest가 각 테스트 파일을 실행하기 전에 필요한 초기 설정을 수행할 수 있게 해준다고 한다.

그리고 나면 테스트가 성공하게 된 걸 볼 수 있다!!!
참고자료
- https://www.npmjs.com/package/@testing-library/jest-dom
- https://velog.io/@wlwl99/Testing-Library-Jest
'Frontend > React' 카테고리의 다른 글
React - 비동기 통신 SWR (0) | 2024.09.08 |
---|---|
React - .env 환경 변수 사용하기 (0) | 2024.05.09 |
React - MSW2.0 업데이트 버전 (1) | 2024.04.28 |
react - Hooks(useState, useEffect, useContext) (0) | 2024.02.15 |
react - recoil이란? (0) | 2023.12.31 |

✅React Testing Libraries란??
React Testing Library는 React 애플리케이션의 컴포넌트를 테스트하기 위한 라이브러리이다. 주로 사용자 관점에서의 컴포넌트 동작을 테스트하도록 설계되어 있으며, 컴포넌트가 실제로 어떻게 동작하는지를 검증하는 데 중점을 둔다.
※ 프론트엔드 테스트 종류
항목 | React Testing Library | Vitest | Cypress |
목적 | 단위 테스트, 통합 테스트 | 단위 테스트, 통합 테스트 | 엔드 투 엔드(E2E) 테스트, 통합 테스트 |
실행 환경 | 노드 환경에서 가상의 DOM 사용 | 노드 환경에서 Vite와 통합해 빠르게 실행 | 실제 브라우저 환경에서 테스트 |
사용 용도 | 컴포넌트의 단위 테스트 | 컴포넌트/함수의 단위 및 통합 테스트 | 전체 애플리케이션 흐름, UI 상호작용 테스트 |
비동기 작업 | 간단한 비동기 로직 테스트 가능 | 비동기 로직 테스트 가능 | 네트워크 요청, 브라우저 렌더링 테스트 가능 |
속도 | 매우 빠름 | 매우 빠름 (특히 Vite와 통합 시) | 상대적으로 느릴 수 있음 |
시각적 피드백 | 콘솔 출력 | 콘솔 출력 | 스크린샷 및 비디오 캡처 가능 |
사용자 관점에서의 컴포넌트 동작을 테스트하도록 설계되어있다는게 무슨 말일까?? Vitest 단위 테스트와 비교해서 알아보자!
React Testing Library를 사용할 때:
test('버튼 클릭 시 텍스트 변경', () => {
render(<MyComponent />);
const button = screen.getByRole('button', { name: /클릭/i });
fireEvent.click(button);
expect(screen.getByText(/변경된 텍스트/i)).toBeInTheDocument();
});
Vitest로 단위 테스트를 작성할 때:
test('함수 호출 테스트', () => {
const mockFunction = vi.fn();
myFunction(mockFunction);
expect(mockFunction).toHaveBeenCalled();
});
React Testing Library는 UI의 동작과 사용자 상호작용을 중심으로 작성된 반면, Vitest의 예시는 함수 호출 여부를 검증하는 단위 테스트이다.
React Testing Library: 사용자 중심의 UI 테스트로, 실제 사용자처럼 컴포넌트와 상호작용하며 결과를 검증한다.
Vitest: 테스트 러너로, 내부 구현 세부 사항을 검증하는 단위 테스트를 작성할 수 있지만, UI 상호작용 중심의 테스트를 원한다면 React Testing Library와 함께 사용하는 것이 좋다.
그럼 다시 React Testing Library로 돌아와서 Jest 와 React Testing Library의 역할을 살펴보면서 이해해보자!
✅Jest란 무엇일까?
React Testing Library는 DOM 상호작용을 중심으로 컴포넌트를 테스트하는 도구이지만, 테스트 환경을 구성하고 실행하는 역할은 수행하지 않는다. Jest는 React Testing Library와 함께 사용되는 테스트 러너로, 테스트를 실행하고 결과를 평가하는 중요한 역할을 한다.
※ 테스트 러너란?
✔️테스트 코드를 실행하고 결과를 보고하는 역할을 한다.
✔️테스트 코드의 실행 환경을 설정하고, 각 테스트 케이스를 실행하여 그 결과를 표시한다.
✔️테스트 러너는 테스트 스위트를 관리하고, 테스트 결과를 출력하며, 테스트 환경의 초기화와 정리를 담당한다.
✔️대표적인 테스트 러너로는 Jest, Mocha, Jasmine, Karma 등이 있다.
Jest란?
✔️ 자바스크립트 테스트 프레임워크이다.
✔️ 사용자는 Jest 를 이용하여 테스트 코드를 작성한다.
✔️ 하지만 Node.js 환경에서 실행되기 때문에 DOM이 없다.
✔️ DOM없이는 React 컴포넌트 테스트가 불가능하다. 그래서 React Testing Library에서 제공하는 가상의 DOM을 이용한다.
Jest에서 제공하는 함수
- describe() : 테스트 그룹을 정의할 때 사용
- test() : 개별 테스트 케이스를 정의
- beforeEach() : 각 테스트가 실행되기 전에 실행
- afterEach() : 각 테스트가 실행된 후에 실행
- beforeAll() : 모든 테스트가 실행되기 전에 한 번 실행
- afterAll() : 모든 테스트가 실행된 후에 한 번 실행
- expect() : 테스트에서 값이나 상태를 검증할 때 사용
- 주요 Matcher들
- toBe() : 엄격한 일치 여부를 확인, ===와 유사한 비교
- toBeInTheDocument() : 해당 요소가 문서에 존재하는지 확인
- Mock관련 함수
- jest.fn() : Jest에서 함수의 동작을 모킹하기 위해 사용되는 함수
✅간단한 실습
1. testing-library와 jest 설치하기
npm install @testing-library/react @testing-library/jest-dom
설치하고 나면 pacage.json에 관련 코드가 생성된 걸 볼 수있다.
"scripts": {
"test":"jest"
},
"devDependencies": {
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
}
2-1. 필요한 모듈 .babelrc 파일에 설정하기
{
"presets": [
[
"@babel/preset-env", //최신 JavaScript 문법(ES6 이상)을 구버전 JavaScript로 변환
{
"modules": false, // Babel이 ES6 모듈 문법(import/export)을 CommonJS로 변환하지 않게
"targets": {
"node": "16"
}
}
],
"@babel/preset-react" // React JSX 문법을 JavaScript로 변환해 주는 preset
],
"env": {
"test": {
"plugins": [
"@babel/plugin-transform-modules-commonjs", // 테스트 환경에서는 CommonJS로 변환이 필요하기 때문에
"@babel/plugin-transform-runtime"
// Babel이 코드 내에서 반복적으로 사용하는 헬퍼 함수(예: async/await, spread 문법 등)를 전역 공간에 중복 없이 공유
// 비동기 코드나 async/await 문법이 포함된 코드를 테스트할 때 중요하며, 최신 문법을 지원하지 않는 환경에서 동작하도록 폴리필을 추가
]
}
}
2-2. Jest가 브라우저 환경을 모방할 수 있도록 jest.config.cjs 파일 설정하기
module.exports = {
testEnvironment: "jsdom",
};
나와 같은 경우 그냥 .js파일로 돌리면

이런 에러가 발생해서 cjs로 변경해주었다.
cjs vs js 차이점
- .cjs: CommonJS 모듈 시스템을 사용하는 파일 확장자. CommonJS는 require()와 module.exports 문법을 사용하며, Node.js에서 오랫동안 사용되어온 모듈 시스템.
- .js: 기본적으로 ES Modules (ESM) 형식을 사용하는 파일 확장자. ESM은 import/export 문법을 사용.
왜 cjs 확장자를 사용해야 오류가 안 나는가?
Node.js는 ES Modules (ESM)과 CommonJS (CJS)를 모두 지원하지만, Jest는 기본적으로 CommonJS를 사용한다. jest.config.js 파일에서 module.exports를 사용하면 CommonJS 문법을 사용하고 있다는 의미인데, Node.js는 .js 파일을 ESM으로 처리하려고 시도할 수 있다.
3. 테스트 적용시킬 CreateSchedule 컴포넌트 준비
import React, { useState } from "react";
const CreateSchedule = ({ addResult }) => {
const [company_name, setCompanyName] = useState("");
const [deadline, setDeadline] = useState("");
const [result_date, setResultDate] = useState("");
const [result, setResult] = useState(3);
const handleSubmit = (e) => {
e.preventDefault();
const newResult = {
company_name,
deadline,
result_date,
result,
};
addResult(newResult);
clearForm();
};
const clearForm = () => {
setCompanyName("");
setDeadline("");
setResultDate("");
setResult(3);
};
const handleResultChange = (e) => {
const value = e.target.value;
if (value === "합격") {
setResult(1);
} else if (value === "불합격") {
setResult(2);
} else {
setResult(3);
}
};
return (
<form onSubmit={handleSubmit}>
<h2>스케줄 추가</h2>
<div className="form_wrap">
<div>
<label htmlFor="company_name">회사명</label>
<input
id="company_name"
type="text"
placeholder="회사명"
value={company_name}
onChange={(e) => setCompanyName(e.target.value)}
required
data-testid="company-name-input"
/>
</div>
<div>
<label htmlFor="deadline">서류지원 마감</label>
<input
id="deadline"
type="datetime-local"
value={deadline}
onChange={(e) => setDeadline(e.target.value)}
required
data-testid="deadline-input"
/>
</div>
<div>
<label htmlFor="result_date">결과 발표</label>
<input
id="result_date"
type="datetime-local"
value={result_date}
onChange={(e) => setResultDate(e.target.value)}
required
data-testid="result-date-input"
/>
</div>
<div>
<label htmlFor="result">결과</label>
<select
id="result"
value={result === 1 ? "합격" : result === 2 ? "불합격" : "진행 중"}
onChange={handleResultChange}
data-testid="result-select"
>
<option value="진행 중">진행 중</option>
<option value="합격">합격</option>
<option value="불합격">불합격</option>
</select>
</div>
<div className="button_wrap">
<button type="submit" data-testid="submit-button">
추가
</button>
</div>
</div>
</form>
);
};
export default CreateSchedule;
- data-testid: 테스트 중에 요소를 식별하기 위한 고유한 식별자로 사용. React Testing Library에서 screen.getByTestId()와 같은 함수를 통해 이 요소를 쉽게 찾아서 테스트할 수 있다.
4. CreateSchedule.test.js작성
import React from "react";
import "@testing-library/jest-dom";
import { render, screen, fireEvent } from "@testing-library/react";
import CreateSchedule from "./CreateSchedule";
describe("CreateSchedule 컴포넌트 테스트", () => {
test("폼이 올바르게 렌더링된다", () => {
render(<CreateSchedule addResult={jest.fn()} />);
expect(screen.getByTestId("company-name-input")).toBeInTheDocument();
expect(screen.getByTestId("deadline-input")).toBeInTheDocument();
expect(screen.getByTestId("result-date-input")).toBeInTheDocument();
expect(screen.getByTestId("result-select")).toBeInTheDocument();
expect(screen.getByRole("button", { name: /추가/i })).toBeInTheDocument();
});
test("입력 필드에 값을 입력하고 제출하면 addResult가 호출된다", () => {
const addResultMock = jest.fn();
render(<CreateSchedule addResult={addResultMock} />);
// 입력값 설정
fireEvent.change(screen.getByTestId("company-name-input"), {
target: { value: "회사 A" },
});
fireEvent.change(screen.getByTestId("deadline-input"), {
target: { value: "2024-10-12T12:00" },
});
fireEvent.change(screen.getByTestId("result-date-input"), {
target: { value: "2024-10-15T12:00" },
});
fireEvent.change(screen.getByTestId("result-select"), {
target: { value: "합격" },
});
// 제출 버튼 클릭
fireEvent.click(screen.getByRole("button", { name: /추가/i }));
// addResult가 호출되었는지 확인
expect(addResultMock).toHaveBeenCalledWith({
company_name: "회사 A",
deadline: "2024-10-12T12:00",
result_date: "2024-10-15T12:00",
result: 1, // "합격" 선택 시 result는 1
});
});
test("폼 제출 후 입력값이 초기화된다", () => {
const addResultMock = jest.fn();
render(<CreateSchedule addResult={addResultMock} />);
// 입력값 설정
fireEvent.change(screen.getByTestId("company-name-input"), {
target: { value: "회사 A" },
});
fireEvent.change(screen.getByTestId("deadline-input"), {
target: { value: "2024-10-12T12:00" },
});
fireEvent.change(screen.getByTestId("result-date-input"), {
target: { value: "2024-10-15T12:00" },
});
fireEvent.change(screen.getByTestId("result-select"), {
target: { value: "합격" },
});
// 제출 버튼 클릭
fireEvent.click(screen.getByRole("button", { name: /추가/i }));
// 입력 필드가 초기화되었는지 확인
expect(screen.getByTestId("company-name-input").value).toBe("");
expect(screen.getByTestId("deadline-input").value).toBe("");
expect(screen.getByTestId("result-date-input").value).toBe("");
expect(screen.getByTestId("result-select").value).toBe("진행 중");
});
});
1. 설정 및 준비
- @testing-library/jest-dom: 추가적인 Jest 매처를 사용하기 위해 임포트. 이를 통해 toBeInTheDocument()와 같은 메소드를 사용
- render, screen, fireEvent: React Testing Library의 유틸리티 함수들을 임포트
- render: 컴포넌트를 실제 DOM에 렌더링
- screen: 렌더링된 컴포넌트에서 요소를 찾기 위한 API를 제공
- fireEvent: 사용자 이벤트를 시뮬레이션하는 데 사용
2. 테스트 스위트 설명
- describe("CreateSchedule 컴포넌트 테스트", () => {...}): 이 블록 안에는 CreateSchedule 컴포넌트에 대한 여러 테스트가 포함되어 있다.
3. 테스트 케이스 분석
테스트 1: "폼이 올바르게 렌더링된다"
- 목적: CreateSchedule 컴포넌트가 올바르게 렌더링되는지 확인
- 흐름:
- render 함수를 사용하여 컴포넌트를 렌더링
- getByTestId 및 getByRole를 사용하여 입력 필드와 버튼이 DOM에 존재하는지 확인
- 모든 요소가 존재해야 하므로 각각의 expect 문이 true이면 테스트가 통과
테스트 2: "입력 필드에 값을 입력하고 제출하면 addResult가 호출된다"
- 목적: 폼에 값을 입력하고 제출할 때 addResult가 올바른 인자로 호출되는지 확인
- 흐름:
- jest.fn()을 사용하여 addResult의 모킹 함수를 생성
- 각 입력 필드에 fireEvent.change로 값을 설정
- 제출 버튼을 클릭하여 폼을 제출
- expect 문으로 addResultMock이 호출되었는지 확인하고, 올바른 인자가 전달되었는지 검사
테스트 3: "폼 제출 후 입력값이 초기화된다"
- 목적: 폼 제출 후 입력 필드가 초기화되는지 확인
- 흐름:
- 이전 테스트와 마찬가지로 입력값을 설정한 후, 제출 버튼을 클릭
- 입력 필드의 값을 검사하여 각 필드가 초기화되었는지 확인. 이때, company-name-input은 비어 있어야 하고, result-select는 기본값인 "진행 중"이 되어야 한다.
5. 테스트 실행
npm test
실행하고 나서

이러 타입에러를 마주했다. 그 이유는 Jest 매처가 확장시켜주는 라이브러리를 추가해줘야 한다. 즉, Jest에 기본적으로 포함되지 않고, 추가적인 라이브러리에서 제공되는 함수이다.
그래서CreateSchedule.test.js에 해당 라이브러리 import 해주고
import "@testing-library/jest-dom";
jest.config.cjs파일에
setupFilesAfterEnv: ["<rootDir>/jest.config.cjs"]
이 코드를 추가해줬다. setupFilesAfterEnv속성이 Jest가 각 테스트 파일을 실행하기 전에 필요한 초기 설정을 수행할 수 있게 해준다고 한다.

그리고 나면 테스트가 성공하게 된 걸 볼 수 있다!!!
참고자료
- https://www.npmjs.com/package/@testing-library/jest-dom
- https://velog.io/@wlwl99/Testing-Library-Jest
'Frontend > React' 카테고리의 다른 글
React - 비동기 통신 SWR (0) | 2024.09.08 |
---|---|
React - .env 환경 변수 사용하기 (0) | 2024.05.09 |
React - MSW2.0 업데이트 버전 (1) | 2024.04.28 |
react - Hooks(useState, useEffect, useContext) (0) | 2024.02.15 |
react - recoil이란? (0) | 2023.12.31 |