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

React+TypeScript中Axios模拟测试失败,组件无法渲染数据

React+TypeScript模拟Axios测试Products组件数据渲染失败问题解决

问题描述

在React+TypeScript项目中测试Products组件的数据渲染时,组件始终处于loading状态,无法渲染出数据。已为fetchData端点编写测试用例fetchData.test.ts,并尝试在Products.test.tsx中mock该端点,但测试始终失败,组件状态始终为空数组。

原测试代码及报错

Products.test.tsx(原测试代码)

import '@testing-library/jest-dom';
import '@testing-library/jest-dom/extend-expect';
import React from 'react';

import Products from '../components/Products';
import { cleanup, render, fireEvent, waitFor, screen } from '@testing-library/react';
import {fetchData} from '../endpoints/fetchData'

import axios from 'axios';

import { data } from '../temp/data';

jest.mock('../endpoints/fetchData');

it('should show render data', async () => {
    const mockReults = data;

     await (fetchData as jest.Mock).mockResolvedValue({
         mockReults
    })
    const { getByLabelText, getByText } = render(<Products />);

    
    await waitFor(() =>   expect(getByText('5-Minute Stories: In the Wild')).toBeInTheDocument() )

});

测试报错信息

● should show render data

    Unable to find an element with the text: 5-Minute Stories: In the Wild. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

    Ignored nodes: comments, script, style
    <body>
      <div>
        <div>
          loading...
        </div>
      </div>
    </body>

相关代码参考

fetchData.test.ts

import axios from 'axios';
import {fetchData} from '../endpoints/fetchData'
import { data } from '../temp/data';

jest.mock('axios');

it('should show render data', async () => {
    const setProducts = jest.fn()

    const mockResponse = {
        data
    }
    
    axios.get = jest.fn().mockResolvedValue(mockResponse)

    const productsData = await fetchData(setProducts)

    expect(mockResponse.data).toEqual(productsData)
});

Products组件核心代码

import React, { useState, useEffect } from 'react';
// ... 其他导入

function App() {
  const [products, setProducts] = useState<Products[]>([]);
  // ... 其他状态

  useEffect(() => {
    fetchData(setProducts);
    setSearchValue('');
  }, []);

  if(products.length === 0) {
    return <div>loading...</div>
  }

  // ... 其他逻辑

  return (
    <header className="App-header">
      <div className="container">{mapProducts()}</div>
    </header>
  );
}

export default App;

fetchData端点代码

export const fetchData = async (setter: (arg0: any) => any) => {
  try {
    const res = await axios.get('http://localhost:3030/products');
    setter(res?.data);
  } catch (error) {
    console.log(error);
  }
};

模拟数据示例

export const data = [
  {
    id: 0,
    price: '9.99',
    productType: 'single-card',
    runtime: 1800,
    title: '5-Minute Stories: In the Wild',
    // ... 其他字段
  },
];

问题原因分析

  1. fetchData的mock方式错误:fetchData的核心逻辑是接收setter函数并调用它传入接口数据,而非返回数据。原测试中使用mockResolvedValue返回数据,但组件依赖的是fetchData调用setProducts来更新状态,因此mock未生效,products状态始终为空,组件显示loading。
  2. 测试文本匹配错误:组件中标题的实际渲染文本是Name: 5-Minute Stories: In the Wild,但测试中直接查找单独的标题文本,导致无法匹配到元素。

修复方案

修改Products.test.tsx,正确mockfetchData的行为,并修正文本匹配逻辑:

import '@testing-library/jest-dom';
import React from 'react';
import Products from '../components/Products';
import { render, waitFor, screen } from '@testing-library/react';
import { fetchData } from '../endpoints/fetchData';
import { data } from '../temp/data';

jest.mock('../endpoints/fetchData');

it('should render product data', async () => {
    // 模拟fetchData调用传入的setter函数,传入mock数据
    (fetchData as jest.Mock).mockImplementation(async (setter) => {
        setter(data);
    });

    render(<Products />);

    // 等待组件渲染完成,匹配包含目标标题的文本
    await waitFor(() => {
        expect(screen.getByText(/5-Minute Stories: In the Wild/)).toBeInTheDocument();
        // 或者匹配完整文本:
        // expect(screen.getByText('Name: 5-Minute Stories: In the Wild')).toBeInTheDocument();
    });
});

修复说明

  • mock逻辑修正:使用mockImplementation模拟fetchData的实际行为,调用传入的setter函数并传入mock数据,确保组件的products状态被正确更新。
  • 文本匹配修正:使用正则表达式匹配标题文本,避免因前缀(Name: )导致的匹配失败;也可以直接匹配完整的渲染文本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 21:59:55