首页 > 解决方案 > 在使用 React 测试库测试 React 时如何模拟 useEffect 来更新状态

问题描述

我是第一次潜入测试 React。我有一个完全构建的应用程序,现在我正在添加测试。我正在使用带有 Jest 的 React-Testing-Library。

为了测试组件是否按预期呈现,我需要更新一些状态,这通过 useEffect 挂钩中的 axios 调用发生。一旦获取了 3 组数据,另一个 useEffect 将运行并将一个称为加载的状态设置为 true,我想测试之后会发生什么。

使用 React-Testing-Library 和 Jest,我将如何模拟/模拟这些状态更新。组件示例如下。非常感谢帮助!

import { useState, useEffect } from 'react';
import axios from 'axios';

import Spinner from 'path-to-spinner';

const Example = () => {
  const [data1, setData1] = useState(null);
  const [data2, setData2] = useState(null);
  const [data3, setData3] = useState(null);
  const [loaded, setLoaded] = useState(false);

  useEffect(() => {
    if (!data1 && !data2 && !data3) {
      axios.get('apiResource1').then((res) => setData1(res.data));
      axios.get('apiResource2').then((res) => setData2(res.data));
      axios.get('apiResource3').then((res) => setData3(res.data));
    }
  }, [data1, data2, data3]);

  useEffect(() => {
    if (data1 && data2 && data3 && !loaded) {
      setLoaded(true);
    }
  }, [loaded, data1, data2, data3]);

  return !loaded ? <Spinner /> : <HTML I want rendered />
};

标签: javascriptreactjstesting

解决方案


所以你真的不需要模拟useEffect. 您真正想要模拟的是 axios 进行的 API 调用。

我建议模拟整个 axios 模块为每个 api 调用创建辅助函数,然后模拟这些函数。

例如,创建辅助函数:

async function apiCall1() {
     const res = await axios.get('apiResource1');
     return res.data;
}

然后在useEffect

useEffect(() => {
    if (!data1 && !data2 && !data3) {
      apiCall1().then(data => setData1(data));
      // etc.
    }
}, [data1, data2, data3]);

现在在您的测试中,您可以模拟辅助函数或 SpyOn 它们并模拟它们的实现。

import helperFunctions from './helperFunctions';

test("test api calls", () => {
     jest.spyOn(helperFunctions , "apiCall1").mockImplementation(jest.fn(() => Promise.resolve(123)));

    render(<MyComponent/>)

    /// other testing details .....
}

如果您想模拟,axios请参阅 Jest 关于模拟的文档:https ://jestjs.io/docs/manual-mocks

这是另一篇可能有帮助的堆栈溢出文章:如何模拟在使用 Jest 测试的 React 组件中进行的 API 调用


推荐阅读