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

如何使用Jest测试含嵌套组件与异步调用的React组件?

测试React天气仪表盘组件的Jest方案

针对你的天气仪表盘组件,完全可以用Jest结合React Testing Library完成测试,包括模拟数据请求、验证状态更新和组件渲染逻辑。下面分两种常见方案详细说明:

一、模拟全局fetch请求(直接适配组件现有代码)

你的组件直接使用了原生fetch,可以在测试文件中全局模拟这个API,无需修改原组件代码。

1. 准备测试依赖

确保已安装@testing-library/react和@testing-library/jest-dom(通常创建React项目时已自带)。

2. 编写测试用例(Dashboard.test.js)

import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import Dashboard from './Dashboard';

// 模拟测试用的天气数据
const mockWeatherData = [
  { timestamp: '2024-05-01 10:00', temperature: 25, dewPoint: 18, visibility: 10 },
  { timestamp: '2024-05-01 11:00', temperature: 27, dewPoint: 19, visibility: 9 },
  { timestamp: '2024-05-01 12:00', temperature: 29, dewPoint: 20, visibility: 8 },
];

// 全局模拟fetch
beforeEach(() => {
  global.fetch = jest.fn(() =>
    Promise.resolve({
      ok: true,
      json: () => Promise.resolve(mockWeatherData),
    })
  );
});

// 重置mock
afterEach(() => {
  jest.clearAllMocks();
});

test('初始渲染显示无数据提示,不渲染图表', () => {
  render(<Dashboard />);
  
  // 验证无数据提示存在
  expect(screen.getByTestId('no-charts')).toBeInTheDocument();
  // 验证图表容器不存在
  expect(screen.queryByTestId('charts')).not.toBeInTheDocument();
});

test('选择下拉选项后,触发请求、更新状态并渲染图表', async () => {
  render(<Dashboard />);
  
  // 找到下拉框容器并触发选择操作
  const selectContainer = screen.getByTestId('Select');
  fireEvent.change(selectContainer, { target: { value: 'temperature' } });
  
  // 验证fetch被正确调用
  expect(fetch).toHaveBeenCalledTimes(1);
  expect(fetch).toHaveBeenCalledWith('http://localhost:3000/getData');
  
  // 等待异步操作完成和组件重新渲染
  await waitFor(() => {
    // 验证无数据提示消失
    expect(screen.queryByTestId('no-charts')).not.toBeInTheDocument();
    // 验证图表容器存在
    expect(screen.getByTestId('charts')).toBeInTheDocument();
    // 验证BarChart接收了正确的props
    const barChart = screen.getByTestId('BarChart');
    expect(barChart).toHaveAttribute('label', 'temperature');
    expect(barChart).toHaveAttribute('labels', JSON.stringify(mockWeatherData.map(item => item.timestamp)));
    expect(barChart).toHaveAttribute('selectedData', JSON.stringify(mockWeatherData.map(item => item.temperature)));
  });
});

test('请求失败时抛出对应错误', async () => {
  // 重写fetch模拟,返回失败响应
  global.fetch = jest.fn(() =>
    Promise.resolve({
      ok: false,
      status: 500,
    })
  );
  
  render(<Dashboard />);
  const selectContainer = screen.getByTestId('Select');
  
  // 触发选择并捕获错误
  await expect(fireEvent.change(selectContainer, { target: { value: 'temperature' } })).rejects.toThrow('An error has occured: 500');
});

二、使用jest.mock()模拟独立数据请求模块(推荐架构优化)

如果把数据请求逻辑抽离到单独的模块,用jest.mock()可以更灵活地模拟该模块,便于后续测试维护。

1. 重构原组件的请求逻辑

创建api.js:

export const fetchWeatherData = async () => {
  const response = await fetch('http://localhost:3000/getData');
  if (!response.ok) {
    const message = `An error has occured: ${response.status}`;
    throw new Error(message);
  }
  return response.json();
};

修改Dashboard.js中的handleChange:

import { fetchWeatherData } from './api';

// ...

const handleChange = async (selectedOption: any) => {
  const jsonData = await fetchWeatherData();
  setLabel(selectedOption.value);
  setLabels(jsonData.map((item: { timestamp: any; }) => item.timestamp));
  // 其余状态更新逻辑保持不变
};

2. 编写测试用例

import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import Dashboard from './Dashboard';
import { fetchWeatherData } from './api';

// 模拟api模块
jest.mock('./api');

const mockWeatherData = [
  { timestamp: '2024-05-01 10:00', temperature: 25, dewPoint: 18, visibility: 10 },
];

test('选择选项后调用模拟API并渲染对应图表', async () => {
  // 设置mock返回值
  (fetchWeatherData as jest.Mock).mockResolvedValue(mockWeatherData);
  
  render(<Dashboard />);
  
  fireEvent.change(screen.getByTestId('Select'), { target: { value: 'dewPoint' } });
  
  await waitFor(() => {
    expect(fetchWeatherData).toHaveBeenCalled();
    const radarChart = screen.getByTestId('RadarChart');
    expect(radarChart).toHaveAttribute('selectedData', JSON.stringify(mockWeatherData.map(item => item.dewPoint)));
  });
});

关键注意事项

  • 使用waitFor等待异步操作完成(状态更新、组件重新渲染),避免测试因时序问题失败。
  • 利用组件中的data-testid快速定位元素,这是测试React组件的最佳实践之一。
  • 每次测试后用jest.clearAllMocks()重置mock,避免测试用例之间的干扰。

内容的提问来源于stack exchange,提问作者Roh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 21:55:34