You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何测试被setTimeout包裹的showUpdate方法调用情况?

测试被setTimeout包裹的showUpdate方法调用问题

我在测试一个被setTimeout包裹的方法时遇到问题,目标是验证showUpdate方法是否以false为参数被调用。

组件代码

const UpdateContainer: FunctionComponent<UpdateProps> = ({
  showUpdate,
  showError,
  dateOfBirth,
}) => {
  
  const [isEditable, setIsEditable] = useState<boolean>(true);
  const [isEditing, setIsEditing] = useState<boolean>(true);
 
  const onCancel = async function() {
    setIsEditable(false);
    setIsEditing(false);
    setTimeout(()=> {
      /* 需要验证此方法是否以false为参数被调用 */
      showUpdate(false);
    },600);
  };

  const initialValues: UpdateValues = {
    birth_date: dateOfBirth,
  };

  const formik = useFormik({
    initialValues: initialValues,
    
  });

  return (
    <Card
      cancelText={t('cancel')}
      confirmText={t('confirm')}
      isEditable={isEditable}
      isEditing={isEditing}
      setIsEditable={setIsEditable}
      setIsEditing={setIsEditing}
      onCancel={() => onCancel()}
    >
      <CardItem
        body={
          <Input
            disabled
            id="dateOfBirthUpdate"
            textTransform="none"
            type="text"
            value={moment(new Date(formik.values.birth_date ? formik.values.birth_date : '')).format('ll')}
          />
        }
      />
    </Card>
  );
};

export default Card;

当前测试代码

it('点击提示框内的取消按钮时将showUpdate设为false', async () => {
  tree(props)
  jest.useFakeTimers()
  act(()=>{
    jest.runAllTimers()
  })
  const cancelButton = screen.getByText('common:cancel');
  expect(cancelButton).not.toBeNull();
  userEvent.click(cancelButton);
  const toolTipCancel= screen.getByText('common:cancelEditTooltip.cancelButtonText')
  userEvent.click(toolTipCancel);
  await expect(props.showUpdate).toBeCalledWith(false)  
});

问题解决步骤

1. 调整Fake Timers的执行时机

你当前在组件渲染后立刻执行jest.runAllTimers(),但此时setTimeout还未被创建(还未触发onCancel方法)。正确逻辑是:先触发按钮点击生成定时器,再执行定时器回调。

2. 规范act的使用范围

React测试中,状态更新、定时器回调这类副作用操作需要包裹在act中,确保组件渲染和状态同步完成。

3. 修正断言方式

toBeCalledWith是同步断言,无需await;同时要确保props.showUpdate是Jest mock函数(测试前需定义const props = { showUpdate: jest.fn() })。

修改后的测试代码

it('点击提示框内的取消按钮时将showUpdate设为false', () => {
  // 初始化组件,确保showUpdate是mock函数
  const props = { showUpdate: jest.fn() };
  tree(props);
  
  // 启用Fake Timers
  jest.useFakeTimers();

  // 点击外层取消按钮
  const cancelButton = screen.getByText('common:cancel');
  userEvent.click(cancelButton);

  // 点击提示框内的取消按钮,触发onCancel生成定时器
  const toolTipCancel = screen.getByText('common:cancelEditTooltip.cancelButtonText');
  userEvent.click(toolTipCancel);

  // 执行所有待处理的定时器回调
  act(() => {
    jest.runAllTimers();
  });

  // 断言showUpdate被正确调用
  expect(props.showUpdate).toHaveBeenCalledWith(false);

  // 清理Fake Timers,避免影响其他测试
  jest.useRealTimers();
});

额外兼容处理

如果Card组件的onCancel存在异步逻辑,可使用waitFor包裹断言确保状态更新完成:

import { waitFor } from '@testing-library/react';

// ...

act(() => {
  jest.runAllTimers();
});

await waitFor(() => {
  expect(props.showUpdate).toHaveBeenCalledWith(false);
});

内容的提问来源于stack exchange,提问作者SilverRetriever

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 18:07:47