如何使用 React-Testing-Library (RTL) 对具有使用 ajax 和状态的内部钩子的组件进行单元测试?

问题描述 投票:0回答:1

问题是我们的 Jest 在 jsdom 中运行并且已经很旧了,但最终每当我编写如下所示的函数时,当我尝试在组件中使用它时,Jest 无法处理它。加载状态保持不变。当我将其包装在

console.logs
中时,我看到表状态从未更新,加载保持不变。

就像我必须模拟 tableState/Dispatch,但它是正在测试的组件的内部,因此无法在不被迫从视图中解除数据关联的情况下发送模拟。这对于延迟加载和道具传递问题可能会有点适得其反,所以尽量避免提起钩子。

const useTableDataBackend = (
  dataInit,
  RequestHandler = (OnSuccess, onError) => {},
  MutationHandler = (data, timezone) => {}
) => {        
  const [tableState, tableDispatch] = useReducer(dataInit)
            
  const { headers, filters, rowsPerPage, currentPage } = tableState
            
  const getPageRequestHandler = (resetPage = true) => {
    tableDispatch({ type: 'SET_LOADING', payload: true })
            
    RequestHandler(
      (data) => {
        tableDispatch({ type: 'SET_LOADING', payload: false })
      },
      () => {
        tableDispatch({ type: 'SET_LOADING', payload: false })
      }
    )

    useEffect(() => {
      tableDispatch({ type: 'SET_DATA', payload: dataInit })
      tableDispatch({ type: 'SET_DATA_PAGINATED', payload: dataInit })
    }, [dataInit])

    useEffect(() => {
      getPageRequestHandler(false)
    }, [currentPage])
  }

使用案例:

const myComponent = () => {
  const RequestHandler = () => {
    // Implementation here
  }

  const MutationHandler = () => {
    // Implementation here
  }

  const { tableState, tableDispatch } = useTableDataBackend(
    MutationHandler(RequestHandler()),
    RequestHandler,
    MutationHandler
  )

  return (
    <div>{tableState}</div>
  )
}

测试用例:

jest.mock(
  'RequestHandler',
  () => jest.fn()
)

it('should paginate correctly onClick of each control', () => {
  RequestHandler.mockImplementationOnce(
    (OnSuccess, onError) => {
      //const data = Array.from({ length: 5 }, () => EncountersGetRequestHandlerSampleData.items.data[0])
      onSuccess(data)
    }
  )

  render(<myComponent />)
  // Expect loading to stop but never does, can't test a disabled paginator
})
javascript reactjs react-hooks jestjs react-testing-library
1个回答
0
投票

您的问题在这里:

RequestHandler.mockImplementationOnce(
  (OnSuccess, onError) => {
    //const data = Array.from({ length: 5 }, () => EncountersGetRequestHandlerSampleData.items.data[0])
    onSuccess(data)
  }
)

更改为:

RequestHandler.mockImplementation(
      (OnSuccess, onError) => {
        //const data = Array.from({ length: 5 }, () => EncountersGetRequestHandlerSampleData.items.data[0])
        onSuccess(data)
      }
)

如果被模拟的函数需要多次调用才能达到预期状态,mockImplementationOnce 显然不起作用。

即使在初始化像后端自定义分页这样复杂的东西时,请求也可能会在设置过滤器变量等时发生。也许这并不理想,该函数实际上应该只被调用一次,因此测试可能在 init 上发现了一些东西,但这仍然是必要的。

学到的教训:除了对使用带有状态和ajax的自定义钩子的组件进行初始化动态测试之外,任何其他操作都需要mockImplementation,而不是mockImplementationOnce。

© www.soinside.com 2019 - 2024. All rights reserved.