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

Vitest+Preact问题:添加forwardRef导致mock的setValue未触发

Preact组件添加forwardRef后测试用例失败问题

未使用forwardRef的组件测试通过

我有一个可正常运行的Preact组件和对应的Vitest测试用例,最简示例如下:

组件

import { ChangeEvent } from 'preact/compat';

export function DateInput({
  value,
  setValue,
  label,
}: {
  value: string;
  setValue: (value: string) => void;
  label: string;
}) {
  const storeValue = (e: ChangeEvent): void => {
    // console.log('event fired'); --> 可触发
    const elem: HTMLInputElement = e.currentTarget as HTMLInputElement;
    setValue(elem.value);
  };

  return (
    <>
      <label htmlFor="test-id">{label}</label>
      <input type="date" value={value} id="test-id" onChange={storeValue} />
    </>
  );
}

测试用例(可通过)

it.only('should update state when date is changed', async () => {
  const setValue = vi.fn();
  const { container } = render(
    <DateInput
      value={m.valueOutput1} // "2024-01-30"
      setValue={setValue}
      label={m.customLabel} // "Test label:"
    />
  );

  const htmlInput: HTMLInputElement | null = queryByLabelText(
    container as HTMLElement,
    m.customLabel
  );
  if (htmlInput) {
    await act(() => {
      fireEvent.change(htmlInput, { target: { value: m.valueOutput2 } }); // "2024-01-31"
    });
    await waitFor(() => {
      expect(setValue).toHaveBeenCalledOnce(); // 无forwardRef时通过,添加后失败
    });
  }
});

添加forwardRef后测试用例失败

修改组件使用forwardRef后,测试用例失败,报错信息:

AssertionError: expected "spy" to be called once, but got 0 times

对应代码行:

201|       await waitFor(() => {
    202|         expect(setValue).toHaveBeenCalledOnce();
       |                          ^
    203|       });

添加forwardRef后的组件

import { Ref } from 'preact';
import { ForwardedRef, forwardRef, ChangeEvent } from 'preact/compat';

export const DateInput = forwardRef(function DateInput(
  {
    value,
    setValue,
    label,
  }: {
    value: string;
    setValue: (value: string) => void;
    label: string;
  },
  ref: ForwardedRef<HTMLElement>
) {
  const storeValue = (e: ChangeEvent): void => {
    // console.log('event fired'); --> 不再触发
    const elem: HTMLInputElement = e.currentTarget as HTMLInputElement;
    setValue(elem.value);
  };

  return (
    <>
      <label htmlFor="test-id">{label}</label>
      <input
        type="date"
        value={value}
        id="test-id"
        onChange={storeValue}
        ref={ref as Ref<HTMLInputElement>}
      />
    </>
  );
});

已尝试的解决方法

  • 搜索4小时未找到完全匹配的问题
  • 测试中使用/不使用async函数(act和waitFor)均无效果
  • 验证测试步骤执行顺序与代码一致
  • 为测试组件添加React.createRef()也无法解决
  • 调试发现使用forwardRef时onChange事件完全未触发,断点仅能打到input标签处,无法进入事件回调

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 02:18:17