模拟TDD(笑话)反应挂钩的最佳方法是什么?

时间:2020-03-17 00:29:23

标签: javascript reactjs jestjs tdd react-hooks

嗨,我不确定模拟反应钩子的最佳方法是什么。 我想测试具有输入的Page.js,然后通过POST请求将输入的数据发送到服务器。 请求成功后,就会出现另一种形式。

我要测试成功案例。

我使用自定义钩子调用api,其名称为useApi。 因此,我嘲笑useApi返回成功状态。 我有2个useAPI挂钩,并且每次重新渲染都会调用该挂钩。

由于useState的setState导致重新呈现,因此在调用它时,将再次调用每个useApi。 因此应该有许多useApi.mockReturnValueOnce()。

如果有更多useApi,将有太多useApi.mockReturnValueOnce()。 这将非常烦人,所以我正在寻找是否有更好的方法。

你有什么主意吗?

// Page.js
const Page = () => {
  const [api, requestApi] = useApi(
    '/v1/users/me/marketing_agreement',
    {
      method: 'post',
      manual: true,
    }
  )
  const [verifyApi, requestVerifyApi] = useApi(
    '/v1/users/me/verify_password',
    {
      method: 'post',
      manual: true,
    }
  )
  ...
  return (
    <div>
      {api.status === 'success' ? <p>success</p> : null}
      <form
        onSubmit={e => {
          requestApi();
        }}
      >
        <input name="a" /> 
        ...
      </form>
    </div>
  )
}

// Page.test.js

test('test', async () => {
  // api
  useApi.mockReturnValueOnce([{ status: 'init' }, requestApi]);
  // verifyApi
  useApi.mockReturnValueOnce([{ status: 'init' }, requestApi]);

  // api
  useApi.mockReturnValueOnce([{ status: 'success' }, requestApi]);
  // verifyApi
  useApi.mockReturnValueOnce([{ status: 'init' }, requestApi]);

  // api
  useApi.mockReturnValueOnce([{ status: 'success' }, requestApi]);
  // verifyApi
  useApi.mockReturnValueOnce([{ status: 'init' }, requestApi]);

  ...some tests changing state of Page (and the page call useApi again because of rerendering)
})

// useApi.js

import { useReducer, useEffect } from 'react';
import request from 'libs/request';

const initialState = { status: 'init', data: null, error: null };
function reducer(_, action) {
  switch (action.type) {
    case 'request':
      return { status: 'loading' };
    case 'success':
      return { status: 'success', data: action.data };
    case 'failure':
      return { status: 'failure', error: action.error };
    default:
      throw new Error();
  }
}

export default (url, options = { method: 'get', manual: false }) => {
  const [state, dispatch] = useReducer(reducer, initialState);
  useEffect(() => {
    let cancelled = false;
    if (!options.manual) {
      dispatch({ type: 'request' });
      const { manual, ...others } = options;
      request({ url, ...others })
        .then(result => {
          if (!cancelled) {
            dispatch({ type: 'success', data: result.data });
          }
        })
        .catch(e => {
          if (!cancelled) {
            dispatch({ type: 'success', error: e });
          }
        });
    }
    return () => {
      cancelled = true;
    };
  }, [options, url]);
  if (options.manual) {
    const requestApi = async props => {
      dispatch({ type: 'request' });
      try {
        const { manual, ...others } = options;

        const result = await request({
          url,
          method: options.method,
          ...others,
          ...props,
        });
        dispatch({ type: 'success', data: result.data });
        return result;
      } catch (e) {
        dispatch({ type: 'failure', error: e });
        return null;
      }
    };
    return [state, requestApi];
  }
  return [state];
};

0 个答案:

没有答案
相关问题