
findBy를 통해 알아보겠습니다.요구사항:
- 컴포넌트가 렌더링 되면 서버에서 사용자 목록을 가져온다.
- 데이터를 가져오는 동안에는 "불러오는 중..."이라는 글자를 보여준다.
- 데이터를 성공적으로 가져오면 사용자 이름(예: Leanne Graham)을 화면에 표시한다.
src/components/UserList.test.tsx 파일을 생성합니다.
이번 테스트의 핵심은 global.fetch 모킹을 사용하고, 다음 9편에서 전문적인 MSW 도구를 다룹니다.)import { render, screen } from '@testing-library/react';
import { vi, describe, test, expect, beforeEach, afterEach } from 'vitest';
// 아직 UserList 컴포넌트가 없으므로 import 에러가 날 수 있습니다.
import UserList from './UserList';
describe('UserList 컴포넌트 비동기 테스트', () => {
// [설정] 테스트 전에 가짜 fetch 함수를 만듭니다.
beforeEach(() => {
// global.fetch를 스파이(Spy)로 심어서 가로챕니다.
// 실제 서버 대신 우리가 정의한 가짜 데이터(JSON)를 반환하도록 합니다.
global.fetch = vi.fn().mockResolvedValue({
json: async () => [
{ id: 1, name: 'Leanne Graham' },
{ id: 2, name: 'Ervin Howell' },
],
});
});
// [정리] 테스트가 끝나면 가짜 함수를 초기화합니다.
afterEach(() => {
vi.restoreAllMocks();
});
test('데이터를 불러오는 동안 로딩 문구가 뜨고, 이후 데이터가 표시된다', async () => {
render(<UserList />);
console.log('[Step 1] 렌더링 직후 확인');
screen.debug();
// 1. 로딩 상태 확인 (동기)
// 렌더링 되자마자 바로 보여야 하므로 getBy를 씁니다.
expect(screen.getByText('불러오는 중...')).toBeInTheDocument();
console.log('[Step 2] 데이터 수신 대기');
// 2. 데이터 표시 확인 (비동기)
// 데이터는 나중에 뜨므로 getBy를 쓰면 에러가 납니다.
// findBy는 요소가 나타날 때까지(기본 1초) 기다려줍니다.
const userItem = await screen.findByText('Leanne Graham');
console.log('[Step 3] 데이터 수신 완료 후 디버깅');
screen.debug();
expect(userItem).toBeInTheDocument();
});
});findBy는 기다리는 함수이므로 반드시 앞에 await를 붙여야 합니다.npm test -- src/components/UserList.test.tsxUserList 컴포넌트가 없기 때문입니다.
하지만 우리는 테스트 코드를 통해 src/components/UserList.tsx를 만들고 기능을 구현합니다.
useEffect와 fetch를 사용하여 실제 데이터를 가져오는 로직을 작성합니다.import { useEffect, useState } from 'react';
// 사용자 데이터 타입 정의
interface User {
id: number;
name: string;
}
export default function UserList() {
const [users, setUsers] = useState<User[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
// 실제 API 호출 (테스트에서는 가짜 함수가 실행됨)
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => response.json())
.then((data) => {
setUsers(data);
setLoading(false); // 로딩 끝
})
.catch((error) => {
console.error('Error fetching data:', error);
setLoading(false);
});
}, []);
if (loading) {
return <p>불러오는 중...</p>;
}
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}npm test -- src/components/UserList.test.tsx
[Step 1] 렌더링 직후 확인
<body>
<div>
<p>불러오는 중...</p>
</div>
</body>
[Step 2] 데이터 수신 대기
[Step 3] 데이터 수신 완료 후 디버깅
<body>
<div>
<ul>
<li>Leanne Graham</li>
<li>Ervin Howell</li>
</ul>
</div>
</body>
PASS src/components/UserList.test.tsxloading 상태가 true이므로 "불러오는 중..."이 보입니다.await screen.findByText(...) 부분에서 테스트가 잠시 멈추고 기다립니다. 그 사이 useEffect가 실행되고 데이터가 도착합니다.li)이 나타난 것을 확인할 수 있습니다.git clone https://github.com/PROMLEE/my-tdd-app.git
cd my-tdd-app
git checkout part8await findBy...를 사용해야 합니다.global.fetch를 가짜로 대체하여 빠르고 안정적인 테스트를 만들었습니다.global.fetch를 직접 가로채는 방식은 API가 많아지면 관리가 힘들어집니다.다음 시간에는 현업에서 가장 많이 사용하는 네트워크 Mocking 도구인9편. API Mock 전략과 MSW 활용에 대해 알아보겠습니다.