首页 > 解决方案 > 使用 renderHook 测试钩子

问题描述

我想测试一个自定义钩子,它被实现为一个帮助函数,以便与其他钩子重用代码。它正在调用useDispatchuseSelector在其实现中,以及将数据保存在会话存储中:

 export function useCustomHook(key, obj)
  {
    let myObject = {
      somefield: obj.someField
    };
    sessionStorage.setItem(key, JSON.stringify(myObject));
    const dispatch = useDispatch();
    dispatch(actionCreator.addAction(key, myObject));
  }

和测试:

it('should have data in redux and session storage', () =>
{
  const obj = { 
    somefield: 'my val', 
  };
  renderHook(() => useCustomHook('some key', obj));
  let savedObj= JSON.parse(sessionStorage.getItem('some key'));
  expect(savedObj.someField).toBe('my val');
  renderHook(() => 
  {
    console.log("INSIDE");
    let reduxObj = useSelector(state => state.vals);
    console.log("THE OBJECT: " );
    console.log(reduxObj);
    expect(reduxObj).toBe(2); //just to see if it fails the test - it's not
  });
})

无论我尝试什么,测试只到达“INSIDE”控制台日志并且不打印“THE OBJECT:”控制台日志。测试本身仍然通过,所以就像以useSelector某种方式停止了其余的 renderHook 执行。

我猜这与测试没有连接商店的事实有关......在这种情况下可以做些什么来测试redux?

标签: reactjsreact-hooksreact-hooks-testing-library

解决方案


您需要提供一个wrapper组件,将 redux 添加Providerstore连接到:

it('should have data in redux and session storage', () =>
{
  const obj = { 
    somefield: 'my val', 
  };

  const store = {} // create/mock a store
  const wrapper = ({ children }) => <Provider store={store}>{children}</Provider>

  renderHook(() => useCustomHook('some key', obj), { wrapper });
  let savedObj= JSON.parse(sessionStorage.getItem('some key'));
  expect(savedObj.someField).toBe('my val');
  renderHook(() => {
    console.log("INSIDE");
    let reduxObj = useSelector(state => state.vals);
    console.log("THE OBJECT: " );
    console.log(reduxObj);
    expect(reduxObj).toBe(2); //just to see if it fails the test - it's not
  }, { wrapper });
})

顺便说一句,renderHook正在捕获错误,这就是为什么您在测试中看不到它们的原因,如果您尝试访问result.current它会抛出,并且您可以看到它表示在 中result.error,但是这里的用法不从要断言的自定义挂钩返回值是很不寻常的。

renderHook通过在第二次调用中进行断言,这也可能会导致您出现问题。您可能希望从钩子返回值并在外部断言,或者在 redux 存储中断言更新的值。


推荐阅读