【问题标题】:How to test custom useFetch hook with enzyme如何使用酶测试自定义 useFetch 钩子
【发布时间】:2020-01-18 16:29:18
【问题描述】:

那里!

我这里有一个useFetch,它会用useReducer触发两次组件的状态变化

type AsyncType = 'INIT' | 'PENDING' | 'RESOLVED' | 'REJECTED' | 'REDIRECTED'

type AsyncAction =
  | { type: 'PENDING' }
  | { type: 'RESOLVED'; data: any }
  | { type: 'REJECTED'; error: Error }
  | { type: 'REDIRECTED' }

interface AsyncState {
  data?: any
  error?: Error
  type: AsyncType
}

const dataFetchReducer = (
  state: AsyncState,
  action: AsyncAction
): AsyncState => {
  switch (action.type) {
    case 'PENDING':
      return {
        ...state,
        type: 'PENDING',
      }
    case 'RESOLVED':
      return {
        ...state,
        type: 'RESOLVED',
        data: action.data,
      }
    // We can choose to ignore it, retry it or throw it to let the error boundary to catch it.
    case 'REJECTED':
      return {
        ...state,
        type: 'REJECTED',
        error: action.error,
      }
    case 'REDIRECTED':
      return {
        ...state,
        type: 'REDIRECTED',
      }
    default:
      throw new Error()
  }
}

// We can ignore the input if we don't want it to fetch new data when the component just mounted
export const useFetch = (
  initialRequestConfig?: AxiosRequestConfig,
  initialData?: any
): [AsyncState, Dispatch<AxiosRequestConfig>] => {
  const [requestConfig, setRequestConfig] = useState(initialRequestConfig)

  const [state, dispatch] = useReducer<typeof dataFetchReducer>(
    dataFetchReducer,
    {
      type: 'INIT',
      data: initialData,
    }
  )

  useEffect(() => {
    if (!requestConfig) return
    let didCancel = false
    const fetchData = async () => {
      dispatch({ type: 'PENDING' })
      try {
        const result = await axios(requestConfig)
        if (!didCancel) {
          dispatch({ type: 'RESOLVED', data: result.data })
        }
      } catch (error) {
        if (!didCancel) {
          if (
            error.response &&
            error.response.data &&
            error.response.data.redirect
          ) {
            dispatch({ type: 'REDIRECTED' })
          } else {
            dispatch({ type: 'REJECTED', error })
          }
        }
      }
    }
    fetchData()
    return () => {
      didCancel = true
    }
  }, [requestConfig])
  return [state, setRequestConfig]
}

但是,我发现为任何使用它的组件编写单元测试非常困难。比如我们有一个这样的组件

export const PrivateRoute: FC<RouteProps> = ({
  component: Component,
  ...rest
}) => {
  const [state] = useFetch(api.getUser()) // the api with only return the axios config, like this: { method: "GET", url: '/user' }
  if (!Component) return null
  console.log(state)
  return (
    <Route
      {...rest}
      render={props =>
        state.type === 'PENDING' ? (
          <p>Loading</p>
        ) : state.type === 'RESOLVED' ? (
          <Component {...props} />
        ) : state.type === 'REJECTED' ? (
          <Error err={state.error} />
        ) : null
      }
    />
  )
}

当我尝试测试它时。不管我做什么。我不能让它呈现&lt;Component /&gt; 而不是&lt;div&gt;Loading&lt;/div&gt;

我只是像这样嘲笑 axios

import axios, { AxiosStatic } from 'axios'

interface AxiosMock extends AxiosStatic {
  mockResolvedValue: Function
  mockRejectedValue: Function
}

jest.mock('axios')
const mockedAxios = axios as AxiosMock

我尝试像这样测试我的组件

it('renders without crashing', async () => {
    const MockComp = () => <p>Test</p>
    mockedAxios.mockResolvedValue({ data: { user: 'caso' } })
    let wrapper
    await act(() => {
      wrapper = mount(
        <MemoryRouter initialEntries={['/random']}>
          <PrivateRoute path="/" component={MockComp} />
        </MemoryRouter>
      )
      wrapper.update() // wherever I put the update, the wrapper is always loading
    })
    console.log(wrapper.debug()) // this line will always be loading
    expect(wrapper.find(Route).prop('path')).toBe('/')
  })

总是有这样的警告 Warning: An update to PrivateRoute inside a test was not wrapped in act(...).

我不知道测试它的正确方法是什么。我花了2天时间。任何人都知道测试它的正确方法是什么?我已经升级到 react 16.9

【问题讨论】:

    标签: reactjs unit-testing jestjs enzyme react-hooks


    【解决方案1】:

    我刚刚找到了最好的解决方案,我们可以使用 jest 来模拟useFetch,我们可以简单地返回模拟状态并测试渲染结果。

    【讨论】:

      猜你喜欢
      • 2020-09-20
      • 1970-01-01
      • 2020-06-01
      • 2021-12-26
      • 2022-01-13
      • 1970-01-01
      • 1970-01-01
      • 2021-07-27
      • 2021-03-10
      相关资源
      最近更新 更多