【问题标题】:Why does my Mock fetch always returns null? (Jest)为什么我的 Mock fetch 总是返回 null? (笑话)
【发布时间】:2021-09-11 01:30:39
【问题描述】:

我有一个简单的 React 组件,它调用本地 API 来获取组件挂载上的产品列表。功能本身运行良好。该应用程序由 create-react-app 创建。 但是,我也在尝试在 Jest 中测试 fetch 函数,但我的模拟全局 fetch 总是返回 null。有谁知道为什么?

这就像我的模拟函数甚至从未被调用或者不在组件逻辑的范围内?然而,原始的全局提取也不会被调用。只返回 null。

我还尝试重写我的 fetch 以使用 .then() 后续操作,并且我尝试使用 jest-fetch-mock 包,但结果是相同的。我可以从测试中调用我的(真实)获取函数,它会正确返回。只有模拟的 fetch 会导致问题。

这是我一直在关注的教程: https://www.leighhalliday.com/mock-fetch-jest

组件:

import React, { useState, useEffect } from 'react';
import Product from './Product';

import './Shop.css';


export async function fetchProducts() {
    try {
        const result = await fetch('http://localhost:8080/products', {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json'
            }
        });
        const data = await result.json();
        return data;
    } catch (e) {
        return null;
    } 
}

function Shop() {

    const [products, setProducts] = useState([])

    useEffect(async () => {
        const result = await fetchProducts();
        setProducts(result);
    }, []);

    return (
        <>
            <h2>Shop</h2>
            <ul className='list-reset products-wrapper'>
                {products.map((product) => (
                    <Product
                        key={product.id}
                        {...product} />
                ))}
            </ul>
        </>
    );
}

export default Shop;

测试:

import { render, screen } from '@testing-library/react';
import Shop, { fetchProducts } from './Shop';

// Mocking the fetch function
global.fetch = jest.fn(() => {
    return Promise.resolve({
        json: () => Promise.resolve([
            {
                id: '1',
                productName: 'Banana',
                price: 0.39,
                image: '????'
            }
        ])
    })
});

beforeEach(() => {
    fetch.mockClear();
});

test('requests the products on mount', async () => {
    const products = await fetchProducts();
    expect(products).toEqual({
        id: '1',
        productName: 'Banana',
        price: 0.39,
        image: '????'
    })
});

测试失败:

 FAIL  src/components/Shop/Shop.test.js
  ● requests the products on mount

    expect(received).toEqual(expected) // deep equality

    Expected: {"id": "1", "image": "????", "price": 0.39, "productName": "Banana"}
    Received: null

如果我在测试运行时注销模拟的 fetch 方法,它会记录 Jest 模拟:

[Function: mockConstructor] {
        _isMockFunction: true,
        getMockImplementation: [Function],
        mock: [Getter/Setter],
        mockClear: [Function],
        mockReset: [Function],
        mockRestore: [Function],
        mockReturnValueOnce: [Function],
        mockResolvedValueOnce: [Function],
        mockRejectedValueOnce: [Function],
        mockReturnValue: [Function],
        mockResolvedValue: [Function],
        mockRejectedValue: [Function],
        mockImplementationOnce: [Function],
        mockImplementation: [Function],
        mockReturnThis: [Function],
        mockName: [Function],
        getMockName: [Function]
      }

【问题讨论】:

  • 我已经通过使用global.fetch = jest.fn().mockReturnValue(Promise.resolve({//stuff})) 得到了这个工作,虽然我不完全确定有什么区别
  • 是 ///stuff 返回的对象吗?它也返回 null
  • //stuff 在这种情况下将是 json: () =&gt; Promise.resolve([//return values]} 基本上只需将 jest.fn(()=&gt;) 更改为 jest.fn().mockReturnValue()
  • global.fetch = jest.fn().mockReturnValue(Promise.resolve({ json: () =&gt; Promise.resolve([ { id: '1', productName: 'Banana', price: 0.39, image: '????' } ]) })) 也返回 null 但感谢您的建议
  • 那么在这种情况下,我会尝试更改您的 catch 语句以记录一条消息并查看它捕获的错误是什么

标签: javascript reactjs testing jestjs mocking


【解决方案1】:

要使调用生效,请像这样触发它:

useEffect((async () => {
  const result = await fetchProducts();
  setProducts(result);
})(), []);

我基本上将异步封装在 IIFE 中。

为什么需要这样做?

useEffect 需要一个清理函数作为回调。在您的示例中,async () =&gt; 这个写在 useEffect 中的异步返回一个承诺(就像所有异步函数一样),因此它不会按照您的要求触发。

【讨论】:

  • 这有一个意外的令牌。还有一个问题是关于单独测试 fetchProducts 函数。
【解决方案2】:

package.json 缺少以下配置:

  "jest": {
    "resetMocks": false
  }

【讨论】:

    猜你喜欢
    • 2011-12-08
    • 2014-09-12
    • 2019-09-18
    • 2014-09-02
    • 2015-02-27
    • 2021-01-10
    • 1970-01-01
    • 2011-04-16
    • 1970-01-01
    相关资源
    最近更新 更多