【问题标题】:Using Jest to mock AJAX requests for React使用 Jest 模拟 React 的 AJAX 请求
【发布时间】:2020-02-11 03:39:21
【问题描述】:

我正在构建一个 React 组件,它在挂载时会通过 AJAX 从服务器获取数据。

我正在尝试(但失败)在 Jest 中模拟 AJAX 调用,我想知道我是否只是误解了 Jest 中的模拟是如何工作的?

我的文件结构是:

  • index.js
  • index.test.js
  • requests.js
  • __嘲笑__
    • requests.js

组件 (index.js) 通过 requests.js 进行调用,它使用 Axios 从服务器获取数据。 requests.js__mocks__ 文件夹中被模拟。

从下面的测试文件index.test.js 中可以看出,我使用getSpy 来检测是否调用了requests.getData 函数。从来都不是。我应该补充一点,我还尝试让组件简单地呈现来自 getData 函数响应的一些数据,然后在测试文件中运行 console.log(ListWrapper.debug()); 以查看数据是否在测试中呈现.同样,它永远不会。

只是想知道是否有人能发现我哪里出错了,或者我只是搞错了?

index.test.js

import React from 'react';
import { mount } from 'enzyme';
import List from './index';
import expect from 'expect';

import requests from './requests';

jest.mock('requests');

describe('Renders list', () => {
    const getSpy = jest.spyOn(requests, 'getData');

    const ListWrapper = mount(
        <ListWrapper />
    );

    console.log(ListWrapper.debug());

    it('should fetch currencies', () => {
        expect(getSpy).toBeCalled();   
    });
});

__mocks__/requests.js

module.exports = {
    getData: () => {
        return new Promise((resolve) => {
            resolve({
               [
                    {
                        id: 1,
                        name: 'Bob Smith',
                        age: 32
                    }
                ]
            });
        });

    }
};

index.js(缩短)

/**
 * List component
 */
import React, { useState, useEffect, useCallback } from 'react';
import * as requests from './requests’;
function List(props) {

  const [data, setData] = useState([]);

   /**
     * Get data from server
     */
   const getCurrencies = useCallback(() => {
      r4_uiTools.loadingAnimation.show();
      requests
          .getData()
          .then((response) => {
              setData(response);
          })
          .catch(error) {
              //...
          }

   /**
     * Get data when first mounting component
     */
    useEffect(() => {
        getData();
    }, [getData]);

  return(
   <>
    /* ... */
    {data[0].name}
   </>
  );

requests.js(缩短)

import axios from 'axios';

const getData = () => {
    return new Promise((resolve, reject) => {
        const url = `/MyURL/`;
        axios
            .get(url)
            .then((response) => {
                resolve(response);
            })
            .catch((error) => {
                reject(error);
            });
    });
};

export { getData };

【问题讨论】:

    标签: reactjs jestjs


    【解决方案1】:

    你的useEffect不应该是这样的吗?

    useEffect(() => {
        getCurrencies();
    }, []);
    

    另外,您的index.test.js 中的ListWrapper 是什么?是不是错字,应该是List

    【讨论】:

      【解决方案2】:

      如果您在模拟调用并返回 Promise,则必须使其阻塞异步

      另外请将 mount 放在 it 块内,否则你必须使你的描述异步

      describe('Renders list', () => {
          ...
          ...
          it('should fetch currencies', async () => {
              expect(getSpy).toBeCalled();   
          });
      });
      

      【讨论】:

        【解决方案3】:

        您的 jest.mock 请求似乎不正确。如果它不是 node_module,它应该像你的导入一样指向路径: jest.mock('./requests');

        您现在也不需要间谍了,因为 jest.mock 会通过 './request` 模拟所有导出。如果是我,我会这样写测试:

        import React from 'react';
        import { mount } from 'enzyme';
        import List from './index';
        import expect from 'expect';
        
        import requests from './requests';
        
        jest.mock('./requests', () => {    // Path instead of name when mocking own modules
            return {
                default: {
                    getData: jest.fn().mockResolvedValue('some value')    // explicit mock
                },
                // ... any other exports you'd wanna mock 
            };
        });
        
        describe('Renders list', () => {
        
            const ListWrapper = mount(
                <ListWrapper />
            );
        
            console.log(ListWrapper.debug());
        
            it('should fetch currencies', () => {
                expect(requests.getData).toBeCalled();  // Directly check on getData since it should point to a mock function   
            });
        });
        

        【讨论】:

        • 为什么我们需要在这里返回一个属性为default的对象?只有({ getData: jest.fn() }) 适合这种情况。
        • 不确定是否会。如果 getData 也作为命名导出导出,它可能会起作用,但如果它只通过默认导出导出,那么我猜它不会。如果我错了,请纠正我。
        【解决方案4】:

        如果您应该选择spyOnjest.mock 来执行此操作。 使用jest.mock,应该是:

        jest.mock('./requests', () => ({ 
                getData: jest.fn(),
            }));
        

        如果你想在调用这个时处理响应数据。您必须使用来自@testing-library/reactwait。你可以在here阅读更多内容

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-02-24
          • 1970-01-01
          • 2021-08-19
          • 2021-11-09
          • 2017-02-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多