
findBy,学习如何在测试代码中处理这类*异步(Asynchronous)*操作。需求
- 组件渲染时,从服务器获取用户列表。
- 获取数据期间,显示“불러오는 중...”(正在加载)。
- 成功获取数据后,在界面上显示用户名,例如 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 会变得难以管理。第 9 篇将介绍实际项目常用的网络模拟工具,讨论API 模拟策略与 MSW 的使用。