You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 22:42:40