简体   繁体   English

ReactJS:: 开玩笑测试::“TypeError: 无法读取未定义的属性‘then’”

[英]ReactJS :: Jest Testing :: "TypeError: Cannot read property 'then' of undefined"

I am currently having some trouble compiling a test for an online study task to see whether the fetch() function of my weather application is working correctly.我目前在为在线学习任务编译测试以查看我的天气应用程序的 fetch() function 是否正常工作时遇到了一些麻烦。

I have made use of the useEffect() hook to fetch the data from the OpenWeather API to store and render once the API's URL changes.我已经使用 useEffect() 挂钩从 OpenWeather API 获取数据,以便在 API 的 URL 更改后存储和呈现。

I am new to Jest testing and have tried a couple of things, following tutorials and other sources, but am unfortunately not having any success.我是 Jest 测试的新手,并且按照教程和其他资源尝试了一些事情,但不幸的是没有任何成功。 My current solution is returning the following error: "TypeError: Cannot read property 'then' of undefined"我当前的解决方案返回以下错误:“TypeError:无法读取未定义的属性'then'”

Please see below my code:请看下面我的代码:

App.js应用程序.js

// Imported hooks and react libraries.
import React, { useState, useEffect } from 'react';
// Imported stylesheet.
import './App.css';
// Imported components.
import Header from './components/Header';
import Footer from './components/Footer';
// Imported countries from i18n-iso-countries to get the iso code and return the country name in English.
import countries from 'i18n-iso-countries';
// Imported icons from Font Awesome.
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {
  faCloudSunRain,
  faHandHoldingWater,
  faHandSparkles,
  faMapMarkerAlt,
  faSearchLocation,
  faTemperatureHigh,
  faTemperatureLow,
  faWind
} from '@fortawesome/free-solid-svg-icons';

countries.registerLocale(require('i18n-iso-countries/langs/en.json'));

function App() {
  // Setting the initial states of the app to store the response and the locations. Using the useState hook to set the data. Showing Durban as 
  // an example.
  const [apiData, setApiData] = useState({});
  const [getState, setGetState] = useState('Durban');
  const [state, setState] = useState('Durban');

  // Constructing the API URL and accessing the key via the process.env variable.
  const apiKey = process.env.REACT_APP_API_KEY;
  const apiUrl = `https://api.openweathermap.org/data/2.5/weather?q=${state}&APPID=${apiKey}`;
  console.log (process.env.REACT_APP_API_KEY);

  // Using the useEffect hook to fetch the data from the API to store and render once the API's URL changes.
  useEffect(() => {
    fetch(apiUrl)
      .then((res) => res.json())
      .then((data) => setApiData(data));
  }, [apiUrl]);

  // Constructed an input handler to get the data once requested and to store in the getState.
  const inputHandler = (event) => {
    setGetState(event.target.value);
  };

  // Constructed a submit handler to handle the request once the search button is clicked.
  const submitHandler = () => {
    setState(getState);
  };

  // Constructed a kelvin to celsius converter to output the temperature in celsius.
  const kelvinToCelsius = (k) => {
    return (k - 273.15).toFixed(2);
  };

  // Constructed a miles to kilometers converter to output the temperature in kilometers.
  const milesToKilometers = (k) => {
    return (k * 3.6).toFixed(2);
  };

  // Created a function to capitalize the first letters of each part of the countries' names.
  function capitalizeFirstLetter(string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
  };

  // Returning the data. Included the React Bootstrap stylesheet's link and called the "Header" and "Footer" components below. I also called the
  // following from the API:

  // {apiData.weather[0].icon} - The icon displaying the current conditions.
  // {apiData.name} - The city's name.
  // {countries.getName(apiData.sys.country, 'en', { select: 'official', })} - The country's name with the first letters capitalized.
  // {kelvinToCelsius(apiData.main.temp_min)} - The minimum temperature.
  // {kelvinToCelsius(apiData.main.temp_max)} - The maximum temperature.
  // {kelvinToCelsius(apiData.main.feels_like)} - The "feels like" temperature, taking into account the temperatures and conditions.
  // {apiData.weather[0].main} - The summarized condition.
  // {capitalizeFirstLetter(apiData.weather[0].description)} - The full condition's description.
  // {apiData.main.humidity} - The humidity percentage.
  // {milesToKilometers(apiData.wind.speed)} - The wind speed.

  // Called the inputHandler (input section) and submitHandler (button) to get the current state's values and added Font Awesome icons. Also 
  // added a loading message for if the page load takes a while. Currently only shows if there is no input or upon refresh.
  return (
    <div className="App">
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css"></link>
      <Header />

      <div className="container">
        <div className="searchsection">
          <label htmlFor="location-name">Enter Location:</label>
          <input
            type="text"
            id="location-name"
            onChange={inputHandler}
            value={getState}
          />
          <button onClick={submitHandler}><FontAwesomeIcon icon={faSearchLocation} /></button>
        </div>

        <div className="mt-3 mx-auto" style={{ width: '60vw' }}>
          {apiData.main ? (
            <div id="weathercontainer">
              <div id="mainweather">
                <img
                  src={`http://openweathermap.org/img/wn/${apiData.weather[0].icon}@2x.png`}
                  alt="weather status icon"
                  className="weather-icon"
                />
                <p className="h2">{kelvinToCelsius(apiData.main.temp)}&deg;C</p>
                <h3><FontAwesomeIcon icon={faMapMarkerAlt} /> {apiData.name}</h3>
                <h3>{countries.getName(apiData.sys.country, 'en', { select: 'official', })}</h3>
              </div>

              <div className="temperatureconditions">
                <div id="temperature">
                  <h5>Temperature:</h5>
                  <p><FontAwesomeIcon icon={faTemperatureLow} /> {kelvinToCelsius(apiData.main.temp_min)}&deg;C</p>
                  <p><FontAwesomeIcon icon={faTemperatureHigh} /> {kelvinToCelsius(apiData.main.temp_max)}&deg;C</p>
                  <p><FontAwesomeIcon icon={faHandSparkles} /> Feels like: {kelvinToCelsius(apiData.main.feels_like)}&deg;C</p>
                </div>
                <div id="conditions">
                  <h5>Conditions:</h5>
                  <p><FontAwesomeIcon icon={faCloudSunRain} /> {apiData.weather[0].main}: {capitalizeFirstLetter(apiData.weather[0].description)}</p>
                  <p><FontAwesomeIcon icon={faHandHoldingWater} /> Humidity: {apiData.main.humidity}%</p>
                  <p><FontAwesomeIcon icon={faWind} /> Wind Speed: {milesToKilometers(apiData.wind.speed)} km/h</p>
                </div>
              </div>
            </div>
          ) : (
            <h1 id="loading">Weather Bot is Loading...</h1>
          )}
        </div>
      </div>
      <Footer />
    </div>
  );
}

// Exported App to Index.js.
export default App;

App.Fetch.React.test.js App.Fetch.React.test.js

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

global.fetch = jest.fn(() =>
    Promise.resolve({
        json: () =>
            Promise.resolve({
                value: "Durban"
            }),
    })
);

describe("App", () => {
    it("loads Durban city name", async () => {
        await act(async () => render(<App />));
        expect(screen.getByText("Durban")).toBeInTheDocument();
    });
});

Does anyone mind helping?有人介意帮忙吗?

I have managed to find a solution to run the test successfully.我设法找到了成功运行测试的解决方案。

The test's code is as follows (with notes for referencing):测试代码如下(附注解供参考):

/* Storing a reference to the global.fetch function so that we can use it to cleanup the mock after we're done testing. */
const unmockedFetch = global.fetch

/* Fetching the Promise with the JSON method, which also returns the Promise with the data. */
beforeAll(() => {
    global.fetch = () =>
        Promise.resolve({
            json: () => Promise.resolve([]),
        })
})

/* Using the afterAll() jest hook and calling the global.fetch function to cleanup mock test. */
afterAll(() => {
    global.fetch = unmockedFetch
})

/* Adding a description of what should be executed and describing the test that will determine whether it is executed successfully or not. 
Utilizing the async function due to the await keyword being used to invoke asynchronous code. Using the expect() and toHaveProperty() functions 
to see whether the fetched data from JSON matches the keys stipulated. */
describe('Displaying the temperature and the wind speed', () => {
    test('Is it working?', async () => {
        const json = await withFetch()
        expect(json).toHaveProperty(['main', 'temp']);
        expect(json).toHaveProperty(['wind', 'speed']);
    })
})

I hope that all is in order and that it will help someone else in future.我希望一切都井井有条,并且将来会对其他人有所帮助。

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

相关问题 类型错误:无法读取 ReactJS Jest 测试中未定义的属性“标题” - TypeError: Cannot read property 'title' of undefined in ReactJS Jest Test React - 使用 Jest 进行测试 - TypeError:无法读取未定义的属性“销毁” - React - Testing w/ Jest - TypeError: Cannot read property 'destroy' of undefined 使用Jest进行测试 - TypeError:无法读取未定义的属性&#39;forEach&#39; - Testing with Jest - TypeError: cannot read property 'forEach' of undefined 开玩笑:TypeError:无法读取未定义的属性“长度” - Jest : TypeError: Cannot read property 'length' of undefined TypeError:无法读取未定义的 Jest 和 Nest 的属性“then” - TypeError: Cannot read property 'then' of undefined Jest and Nest JEST - TypeError:无法读取未定义的属性“then” - JEST - TypeError: Cannot read property 'then' of undefined Jest - TypeError:无法读取未定义的属性“fn” - Jest - TypeError: Cannot read property 'fn' of undefined Jest TypeError:无法读取未定义的属性“id” - Jest TypeError: Cannot read property 'id' of undefined JEST TypeError:无法读取未定义的属性“json” - JEST TypeError: Cannot read property 'json' of undefined 开玩笑-TypeError:无法读取未定义的属性“项目” - Jest - TypeError: Cannot read property 'projects' of undefined
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM