Тестирование пользовательского контекстного хука, который использует хук useEffect и apollo - PullRequest
2 голосов
/ 26 сентября 2019

Я создал контекст, который предоставляет хук для простоты использования.В этой ловушке я уже проверяю, что некоторые данные предварительно загружаются перед рендерингом страницы, например:

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 };

Я хотел бы проверить это с помощью testing-library и после прочтения некоторых статей.и проблемы с GitHub я пришел к следующему:

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");
});

Где это, к сожалению, говорит, что текущий является нулевым.Я ожидаю, что это потому, что useEffect вызывает обновление состояния и, следовательно, возвращает нулевое значение (значение по умолчанию).до обновления.Вот почему я ввел waitForNextUpdate.

Однако, с этим мне выдается следующая ошибка:

Предупреждение: обратный вызов, переданный в функцию TestRenderer.act (...), не должен ничего возвращать.

  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 */

Есть идеи, как решить эту проблему?

1 Ответ

0 голосов
/ 27 сентября 2019

После прочтения https://dev.to/theactualgivens/testing-react-hook-state-changes-2oga я решил смоделировать useReducer, поскольку отправка вызывает обновления состояния в хуке useEffect.После этого это сработало.Теперь я высмеиваю начальное состояние редуктора.

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

и мой тест выглядит как

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