一个测试中的TestHook更新没有包装在act(...)中

时间:2020-05-04 06:30:48

标签: javascript reactjs react-hooks react-testing-library

我正在使用呈现UI组件的钩子并尝试对其进行测试。

import React, { useState, useCallback } from 'react';
import { useModal } from './useModal';
import { ConfirmationModal } from './common';

export const useConfirm = () => {
  // Manage if confirm module is open or close
  // Provide callback to set confirm state
  const { isShowing, toggle } = useModal();

  // Track confirmation module values
  const [confirmOptions, setConfirmOptions] = useState({});

  // Callback to set confirmation model properties
  const setConfirmation = useCallback(
    async (title, body, onConfirm, onCancel) => {
      await setConfirmOptions({
        title,
        body,
        onConfirm,
        onCancel
      });
      toggle();
    },
    [toggle]
  );

  const ConfirmModal = (
    <ConfirmationModal
      open={isShowing}
      toggle={toggle}
      title={confirmOptions.title}
      content={confirmOptions.body}
      onConfirm={confirmOptions.onConfirm}
      onCancel={confirmOptions.onCancel}
    />
  );

  return {
    setConfirmation,
    ConfirmModal
  };
};

测试:

import { renderHook, act } from '@testing-library/react-hooks';
import { useConfirm } from './useConfirm';

describe('useConfirm hook', () => {
  it('toggles confirm ui', () => {
    const { result } = renderHook(() => useConfirm());
    const onConfirm = jest.fn();
    const onCancel = jest.fn();
    // test confirm is called
    act(() => {
      result.current.setConfirmation(
        'Title',
        'Content Content',
        onConfirm,
        onCancel
      );

      console.log(result.current.ConfirmModal);
    });
    // test cancel is called
  });
});

我明白了:

Warning: An update to %s 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 :(得分:0)

当您尝试在组件完成更新所有状态之前进行断言时,通常会发生此错误。

请注意,在setConfirmation内部您正在呼叫toggle(),并会更新状态。

您应该使用waitFor之类的东西来等待切换值更新或已被承诺。

我对render-hooks库不熟悉,但是也许下面的示例可以为您提供帮助。我还将在底部留下一些有用的链接。

  it('toggles confirm ui', async () => {
    const { result } = renderHook(() => useConfirm());
    const onConfirm = jest.fn();
    const onCancel = jest.fn();

    // test confirm is called    
    result.current.setConfirmation(
      'Title',
      'Content Content',
      onConfirm,
      onCancel
    );

    await waitFor(() => expect(onConfirm).toHaveBeenCalled());
    // or await for something to appear on the screen
  });

React docs中的act()是什么:

编写UI测试时,可以将诸如渲染,用户事件或数据获取之类的任务视为与用户界面交互的“单元”。 React提供了一个名为act()的帮助程序,可以确保在进行任何断言之前,已经处理了与这些“单元”相关的所有更新并将其应用于DOM。

名称行为来自“排列行为声明”模式。


有用的链接: