【问题标题】:testing fetch data query into component react测试获取数据查询到组件反应
【发布时间】:2021-09-09 13:33:37
【问题描述】:

我正在尝试使用 jest 编写测试,以便我使用 fetch 从反应页面获取和发布数据。

当前的测试是这样的 - 我对如何确保正确的数据通过特定组件感到困惑。

目前测试本身是这样的,

import React from 'react';
import '@testing-library/jest-dom';
import { render } from '@testing-library/react';

import getSettings from 'components/onboarding/stages/useGetSettingsData.js'
import updateSettings from 'components/onboarding/stages/useUpdateSettings.js'
import Settings from 'components/onboarding/stages/useUpdateSettings.js'


describe('get settings', () => {
    it('should load settings with no issues', () => {
       getSettings().mockResolvedValueOnce({
        power: 'magical',
        potion: 'magilin',
        potion_times: '[]',
        potion_activity_times: '',
        gender: 'Male',
        age: '30',
      });
      const {getByText, getByLabelText,debug} = render( <Settings/> )
  
      expect(heading).toBeInTheDocument();

      expect(GetSettings)
    });
  });

测试这个获取用户数据的功能,

import { useEffect, useState } from 'react';

export default function getSettings(auth) {
  const [settings, setSettings] = useState(false);

  useEffect(() => {
    try {
      const idToken = auth.getIdToken();

      const response = fetch('/api/dashboard/get-settings', {
        method: 'GET',
        headers: new Headers({
          Authorization: `Bearer ${idToken}`,
          'Content-Type': 'application/x-www-form-urlencoded',
        }),
      });
      const jsonReponse = response.json();

      if (!jsonReponse.error) {
        setSettings(jsonReponse.settings);
      } else {
        setSettings({
          power: 'magical',
        potion: 'magilin',
        potion_times: '[]',
        potion_activity_times: '',
        gender: 'Male',
        age: '30',
        });
      }
    } catch (error) {
      console.log('Error happened in decrypting token', error);
    }
  }, [settings]);
  return settings;
};

这个用于设置设置,

import { loadingReducer } from 'components/onboarding/stages/loadingReducer';

export default function updateSettings({ newSettings, auth, initialState }) {
  const [state, dispatch] = loadingReducer(loadingReducer, initialState);

  dispatch({ type: 'LOADING' });
  try {
    const idToken = auth.getIdToken();

    const response = fetch('/api/dashboard/set-settings', {
      method: 'POST',
      headers: new Headers({
        Authorization: `Bearer ${idToken}`,
        'Content-Type': 'application/json',
      }),
      body: JSON.stringify(newSettings),
    });

    // const jsonReponse = response.json();

    // TODO: Create Notification Toast
  } catch (error) {
    console.log('Error happened in decrypting token', error);
  }
  dispatch({ type: 'FINISHED' });
  return { isLoading: state.isLoading };
}

变成这样的组件,

function SettingsDetails() {
  const auth = useAuth();
  const { register, handleSubmit, errors } = useForm();
  const initialState = {
    isLoading: false,
  };
  // const settings = false
  const settings = getSettings(auth);

  const onSubmit = (data) => {
    console.log('Submitting..');
    const isLoading =updateSettings(data,initialState);
    return isLoading
  };  
 
  
  return (

    <div className="md:grid md:grid-cols-3 md:gap-6">
  <div className="md:col-span-1">
    <h3 className="text-lg font-medium leading-6 text-gray-900">
      Preferences
    </h3>
    <p className="mt-1 text-sm leading-5 text-gray-500">
      Set your Personal Preferences
    </p>
  </div>
  <div className="mt-5 md:mt-0 md:col-span-2">
    <form onSubmit={handleSubmit(onSubmit)}>
      <Dropdown
        data-testid = "power"
        registerInput={register}
        optionLabel="power"
        selectedOption={settings.power}
        optionName="power"
        allOptions={['ice', 'fire', 'Both']}
      />
.....
  <button
            className="inline-flex items-center justify-center px-5 py-2 border border-transparent text-base leading-6 font-medium rounded-md text-indigo-700 bg-indigo-100 hover:text-indigo-600 hover:bg-indigo-50 focus:outline-none focus:shadow-outline focus:border-indigo-300 transition duration-150 ease-in-out"
            // variant={props.buttonColor}
            // size={props.inputSize}
            type="submit"
            disabled={initialState.isLoading}
          >
            {initialState.isLoading ? (
              <>
                <span>Saving</span>
                <svg
                  xmlns="http://www.w3.org/2000/svg"
                  viewBox="0 0 24 24"
                  className="animate-spin h-4 w-4 ml-3 fill-current"
                >
                  <path d="M0 11c.511-6.158 5.685-11 12-11s11.489 4.842 12 11h-2.009c-.506-5.046-4.793-9-9.991-9s-9.485 3.954-9.991 9h-2.009zm21.991 2c-.506 5.046-4.793 9-9.991 9s-9.485-3.954-9.991-9h-2.009c.511 6.158 5.685 11 12 11s11.489-4.842 12-11h-2.009z" />
                </svg>
              </>
            ) : (
              <span>Save</span>
            )}
          </button>

我对尝试模拟此获取数据功能的最佳方法有点迷茫 - 有什么最佳做法吗?

我只想确保页面呈现,它呈现来自 getdata 函数的数据,并且它在提交到表单时正确保存数据。真的很难在网上找到任何这样的资源。

目前我在运行测试时收到此错误,

   Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
    1. You might have mismatching versions of React and the renderer (such as React DOM)
    2. You might be breaking the Rules of Hooks
    3. You might have more than one copy of React in the same app
    See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.

提前致谢,

更新到当前测试出现新错误(感谢到目前为止的帮助!)。模拟这些函数的测试现在可以工作了!我希望能够自己模拟这些函数,以确保它们也能正常工作。

用于更新设置的加载减速器是这个顺便说一句,

export default function loadingReducer(state, action) {
  switch (action.type) {
    case 'LOADING':
      return { isLoading: true };
    case 'FINISHED':
      return { isLoading: false };
    default:
      return state;
  }
}

【问题讨论】:

标签: reactjs jestjs next.js enzyme react-testing-library


【解决方案1】:

我会尝试在我的测试中而不是导入getSettings,而只是模拟整个文件和钩子。 所以不是

import getSettings from 'components/onboarding/stages/useGetSettingsData.js'

做类似的事情

jest.mock('components/onboarding/stages/useGetSettingsData.js', () => {
      return {
          getSettings: jest.fn(() => {
            return {
              power: 'magical',
              potion: 'magilin',
              potion_times: '[]',
              potion_activity_times: '',
              gender: 'Male',
              age: '30',
             };
            });
          };
        });
    }

这样,您只需模拟整个 useGetSettingsData.js 文件,您就可以测试您的组件更改。

【讨论】:

  • 谢谢,这是一个很好的观点。我确实想确保我也成功地模拟了 getSettings 功能 - 确保我没有留下任何问题。是否有可能有一种简单的方法来完成这两个组件? (也许有一种模拟获取的方法?
  • 我如何将这个模拟加载到现有组件中?
  • 通过模拟整个文件,您实际上是在开玩笑说要使用模拟而不是实际代码。所以 jest 不会导入useGetSettingsData.js,而是会尝试使用模拟来运行您的组件测试。因此,从这个意义上说,您不必担心在 getSettings 中模拟 fetch 或任何其他方法,除非您想为特定测试模拟它们。
  • 您不必加载它,开玩笑会自动拾取它。
  • 我尝试的上述代码在@SakisTsalk 失败
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-08
  • 1970-01-01
  • 2017-08-03
  • 2020-02-04
相关资源
最近更新 更多