简体   繁体   English

如何使用 Jest 在 React 组件中测试/模拟 fetch api?

[英]How to test/mock a fetch api in a React Component using Jest?

I'm a newbie on test driven development, and I came across a section regarding testing/mocking a fetch api.我是测试驱动开发的新手,我遇到了关于测试/模拟获取 api 的部分。 But I'm struggling to write my own test.但我正在努力编写自己的测试。 I built a simple weather app just to test/mock the fetch using jest.我构建了一个简单的天气应用程序,只是为了使用 jest 测试/模拟获取。 But the test keeps failing.但是测试一直失败。 I keep getting errors like:我不断收到以下错误:

Invalid hook call.无效的挂钩调用。 Hooks can only be called inside of the body of a function component.钩子只能在 function 组件的主体内部调用。 This could happen for one of the following reasons: And not just that, I do not know where I am going wrong, so I came here to ask for tips on how I could mock/improve my test so that it can be successful.这可能是由于以下原因之一发生的:不仅如此,我不知道我哪里出错了,所以我来这里询问有关如何模拟/改进我的测试以使其成功的提示。 H H

Here's my React code: (App.js)这是我的反应代码:(App.js)

  const [search, setSearch] = useState('');
  const [weather, setWeather] = useState({}); 
  
  const handleChange = (e) => {
    setSearch(e.target.value)
  }

 //function returns a promise
  const WeatherData = async (e) => {
    if (e.key === "Enter") {
      await fetch(`${api.baseURL}weather?q=${search}&appid=${api.key}`)
        .then(data => data.json())
        .then(city => {
          //console.log(city)
          setSearch('')
          setWeather(city)
        })
    }
  }

  const currentDate = (d) => {
    let months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
    let days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];

    let day = days[d.getDay()];
    let month = months[d.getMonth()];
    let year = d.getFullYear();
    let date = d.getDate();

    return `${day} ${date} ${month} ${year}`

  }

  return (
    <div className="App">
      <h2>International Weather</h2>
      <div className="wrapper">
        <input type="text" id="search-field" placeholder='Search...' onChange={handleChange} onKeyPress={WeatherData} />

        {(typeof weather.main != "undefined") ? (

          <div className='weather-box'>
            <h2>{weather.name}, {weather.sys.country}</h2>
            <h2> {currentDate(new Date())} </h2>

            <div id="weather">

              <div className="details" id="degrees">{(weather.main.temp - 273.15).toFixed(2)}°C</div>
              <div className="details" id="clouds">{weather.weather[0].main}</div>

            </div>
          </div>

        ) : (" ")}

      </div>
    </div>
  );
}

And my App.js code:还有我的 App.js 代码:

import { render, screen } from "@testing-library/react";
import App from "./App";

//creating a snapshot test to test if the rendered component is the same as the snapshot app
test("snapshot is correct", () => {
  const tree = render(<App />);
  expect(tree).toMatchSnapshot();
});

//test whether the function works
test("fetch works correctly", async () => {
  App(
    JSON.stringify({
      results: [{ user: "mandla", age: 43 }],
    })
  ).then((data) => {
    expect(data).toBe();
  });
});

Would appreciate if anyone can help me understand the problem and why my solution is not working.如果有人可以帮助我理解问题以及为什么我的解决方案不起作用,我将不胜感激。

You can test the fetch API by any of the below methods.您可以通过以下任何方法测试获取 API。

  1. mocked fetch模拟获取
// This is the function we'll be testing
async function withFetch() {
  const res = await fetch('https://jsonplaceholder.typicode.com/posts')
  const json = await res.json()

  return json
}

// This is the section where we mock `fetch`
const unmockedFetch = global.fetch

beforeAll(() => {
  global.fetch = () =>
    Promise.resolve({
      json: () => Promise.resolve([]),
    })
})

afterAll(() => {
  global.fetch = unmockedFetch
})

// This is actual testing suite
describe('withFetch', () => {
  test('works', async () => {
    const json = await withFetch()
    expect(Array.isArray(json)).toEqual(true)
    expect(json.length).toEqual(0)
  })
})
  1. jest.spyOn jest.spyOn
const fetchMock = jest
  .spyOn(global, 'fetch')
  .mockImplementation(() =>
    Promise.resolve({ json: () => Promise.resolve([]) })
  )

describe('withFetch', () => {
  test('works', async () => {
    const json = await withFetch()

    // highlight-start
    expect(fetchMock).toHaveBeenCalledWith(
      'https://jsonplaceholder.typicode.com/posts'
    )
    // highlight-end

    expect(Array.isArray(json)).toEqual(true)
    expect(json.length).toEqual(0)
  })
})

Please have a look at the below link请看下面的链接

https://benjaminjohnson.me/mocking-fetch https://benjaminjohnson.me/mocking-fetch

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM