React.js中使用Vitest测试API数据列表渲染问题求助
问题原因及修复方案
核心问题:模拟的Promise未正确resolve
你当前的mock实现new Promise(() => mockMedias)创建了一个永远处于pending状态的Promise,组件中await fetchAllMedias()会一直等待,永远不会执行setMedias(fetchedMedias),所以medias始终是初始空数组,列表自然不会渲染任何内容。
修复步骤
1. 修正mock函数的返回值
使用Vitest提供的mockResolvedValue方法直接返回已resolve的Promise,替代手动创建Promise的写法:
const mockFetchMedias = vi.spyOn(service, 'fetchAllMedias'); // 替换原有的mockReturnValue为mockResolvedValue mockFetchMedias.mockResolvedValue(mockMedias);
如果一定要手动写Promise,必须调用resolve:
mockFetchMedias.mockReturnValue(new Promise(resolve => resolve(mockMedias)));
2. 填充正确的模拟数据
确保mockMedias的结构完全匹配MediaResponse类型,包含测试需要的字段,比如:
const mockMedias = [ { mediaId: 1, title: 'Avengers', mediaType: 'MOVIE', // 对应你的MediaType枚举值 mediaLanguage: { mediaLanguageName: 'English' }, country: { countryName: 'USA' } } ];
3. 优化断言逻辑
- 移除
expect(mockFetchMedias).toReturnWith(...):因为每次调用mock都会生成新的Promise实例,直接比较对象会失败,这个断言没有意义。 - 用
findByText替代waitFor + getByText:findByText本身就是异步查询,无需额外包裹waitFor,代码更简洁:
test('Can render media list', async () => { const mockFetchMedias = vi.spyOn(service, 'fetchAllMedias'); mockFetchMedias.mockResolvedValue(mockMedias); render(<MediaList />); expect(mockFetchMedias).toHaveBeenCalled(); // 直接用findByText异步查询 const avengersTitle = await screen.findByText(/Avengers/); expect(avengersTitle).toBeInTheDocument(); });
4. 可选:清理mock(避免测试污染)
如果有多个测试,可以在测试结束后恢复原函数,防止影响其他测试:
afterEach(() => { vi.restoreAllMocks(); });
修复后的完整测试代码示例
import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; import * as service from '../service'; import MediaList from '.'; const mockMedias = [ { mediaId: 1, title: 'Avengers', mediaType: 'MOVIE', mediaLanguage: { mediaLanguageName: 'English' }, country: { countryName: 'USA' } } ]; test('Can render media list', async () => { const mockFetchMedias = vi.spyOn(service, 'fetchAllMedias'); mockFetchMedias.mockResolvedValue(mockMedias); render(<MediaList />); expect(mockFetchMedias).toHaveBeenCalled(); const avengersTitle = await screen.findByText(/Avengers/); expect(avengersTitle).toBeInTheDocument(); }); afterEach(() => { vi.restoreAllMocks(); });
内容的提问来源于stack exchange,提问作者user178456
相关产品推荐
相关产品推荐

