简体   繁体   English

测试使用 useEffect 钩子和 apollo 的自定义上下文钩子

[英]Testing a custom context hook that uses a useEffect hook and apollo

I have created a context that exposes a hook for ease of use.我创建了一个上下文,该上下文公开了一个易于使用的钩子。 Within this hook i already make sure that some data is preloaded before rendering the page, like this:在这个钩子中,我已经确保在呈现页面之前预加载了一些数据,如下所示:

export const MyContext = React.createContext({} as any);

function useMyContext() {
  const context = React.useContext(MyContext);
  if (context === undefined) {
    throw new Error('useMyContext must be used within a MyContext');
  }
  return context;
}

function MyContextProvider(props: any) {
  const client = useApolloClient();
  const { user } = React.useContext(UserContext);
  const [data, setData ] = React.useState({});

  const findSomethingFromUser = () => {
    return client.query({
      query: FIND_SOMETHING_FROM_USER,
      variables: { userId: user.id },
    });
  };

  const load = () => {
    findSomethingFromUser()
      .then(({ data, errors }) => {
          setData(data);
      });
  };

  // Load user test
  React.useEffect(load, []);

  return (
    <MyContext.Provider value={{ data }}>
        {children}
    </MyContext.Provider>
  );
}

export { MyContextProvider, useMyContext };

I would like to test this using testing-library and after reading some articles and github issues i came to the following:我想使用测试库对此进行测试,在阅读了一些文章和 github 问题后,我得出以下结论:

const wrapper = ({ children }) => ( {children} ); const wrapper = ({ children }) => ( {children} );

it('should fetch the special user value', async () => {
    const { result, waitForNextUpdate } = renderHook(useMyContext, { wrapper });

    await waitForNextUpdate();

    // await act(async () => {
    //     await waitForNextUpdate();
    //   });

    expect(result.current.mySpecialUserValue).toEqual("something");
});

Where it sadly says that the current is null.可悲的是,电流是 null。 I expect this is because the useEffect causes a state update and thus returns a null (default value) first.我预计这是因为useEffect导致 state 更新,因此首先返回 null (默认值)。 before updating.更新前。 That's why i introduced the waitForNextUpdate .这就是我介绍waitForNextUpdate的原因。

However with this it gives me the following error:但是,它给了我以下错误:

Warning: The callback passed to TestRenderer.act(...) function must not return anything.警告:传递给 TestRenderer.act(...) function 的回调不得返回任何内容。

  It looks like you wrote TestRenderer.act(async () => ...) or returned a Promise from it's callback. Putting asynchronous logic inside TestRenderer.act(...) is not supported.

console.error node_modules/react-test-renderer/cjs/react-test-renderer.development.js:102
  Warning: Do not await the result of calling TestRenderer.act(...), it is not a Promise.
console.error node_modules/react-test-renderer/cjs/react-test-renderer.development.js:102
  Warning: An update to MyContextProvider inside a test was not wrapped in act(...).

  When testing, code that causes React state updates should be wrapped into act(...):

  act(() => {
    /* fire events that update state */
  });
  /* assert on the output */

Any ideas on how to resolve this?关于如何解决这个问题的任何想法?

After reading https://dev.to/theactualgivens/testing-react-hook-state-changes-2oga I decided to mock the useReducer as the dispatches cause state updates in the useEffect hook.在阅读https://dev.to/theactualgivens/testing-react-hook-state-changes-2oga之后,我决定模拟useReducer ,因为调度导致 state 在useEffect挂钩中更新。 After that it worked.之后它起作用了。 I now mock the reducer initial state.我现在模拟减速器的初始 state。

const dispatch = jest.fn();
const useReducerSpy = jest.spyOn(React, 'useReducer');
useReducerSpy.mockImplementation((init: any) => [MY_CONTEXT_MOCK, dispatch]);

and my test looks like我的测试看起来像

it('should render', async () => {
  const { result } = renderHook(useMyContext, { wrapper: bySlugWrapper });
  expect(result.current.somevar).toEqual(MY_CONTEXT.somevar);
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM