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

如何用@testing-library/react更新组件Props?Jest测试新手求教

如何在Jest + @testing-library中测试组件Props更新

先指出你现有测试代码的几个问题:

  • 测试顺序搞反了:还没渲染组件就去查询test-dropdown元素,肯定会报错,得先渲染再做断言。
  • onSelect绑定错误:你写的onSelect={onSelectMock(items[1])}是直接执行了mock函数,不是传递点击时要触发的回调,应该改成传递一个函数。
  • 未正确获取点击元素:el[1]根本没定义,得用测试库的查询方法(比如getAllByRole)拿到对应的选项元素。
  • 受控组件逻辑没处理:你的Dropdown是受控组件,selected值完全由外部props决定,点击选项后需要父组件主动更新selected并重新传递给Dropdown,组件才会显示新值,原测试没做这一步。

修正后的测试方案(受控组件场景)

如果要保持Dropdown的受控属性,测试时需要模拟父组件更新props的行为,用测试库的rerender方法重新渲染组件:

import { render, screen, fireEvent } from '@testing-library/react';
import Dropdown from './Dropdown';

const items = [{id: 1, name: "1"}, {id: 2, name: "2"}];
const initialValue = "Select";

test("点击选项后更新Dropdown的selected值", () => {
  const onSelectMock = jest.fn();
  let currentSelected = undefined;

  // 初始渲染组件,传入初始状态的selected
  const { rerender } = render(
    <Dropdown 
      items={items} 
      initialValue={initialValue} 
      selected={currentSelected} 
      onSelect={() => {
        // 模拟父组件接收到选择事件后更新selected
        currentSelected = items[1].name;
        // 重新渲染组件,传入更新后的selected
        rerender(
          <Dropdown 
            items={items} 
            initialValue={initialValue} 
            selected={currentSelected} 
            onSelect={onSelectMock} 
          />
        );
      }} 
    />
  );

  // 验证初始显示文本
  expect(screen.getByTestId('test-dropdown')).toHaveTextContent('Select');

  // 获取第二个选项并点击
  const secondOption = screen.getAllByRole('list')[1];
  fireEvent.click(secondOption);

  // 验证显示文本已更新
  expect(screen.getByTestId('test-dropdown')).toHaveTextContent('2');
  // 验证onSelect回调被触发
  expect(onSelectMock).toHaveBeenCalled();
});

更贴近实际场景的改进:改成非受控组件

如果希望Dropdown自己维护选中状态(不需要父组件每次手动更新),可以把组件改成非受控模式,内部用useState管理选中值,这样测试会更简单:

改造后的Dropdown组件:

import { useState } from 'react';

interface IDropdownProps {
  initialValue: string;
  items: Array<{ id: number; name: string }>;
  selected?: string;
  onSelect?: (item: { id: number; name: string }) => void;
}

const Dropdown: React.FC<IDropdownProps> = ({ initialValue, items, selected, onSelect }) => {
  // 内部维护选中状态,优先使用外部传入的selected(兼容受控模式)
  const [internalSelected, setInternalSelected] = useState(selected || initialValue);

  const handleClick = (item) => {
    setInternalSelected(item.name);
    // 触发外部回调通知选择结果
    onSelect?.(item);
  };

  return (
    <div>
      <div data-testid="test-dropdown">{internalSelected}</div>
      <ul>
        {items.map((el) => (
          <li 
            key={`a${el.id}`} 
            onClick={() => handleClick(el)}
            role="listitem" // 注意:li的role应该是listitem,ul才是list
          >
            {el.name}
          </li>
        ))}
      </ul>
    </div>
  );
};

export default Dropdown;

对应的测试代码:

import { render, screen, fireEvent } from '@testing-library/react';
import Dropdown from './Dropdown';

const items = [{id: 1, name: "1"}, {id: 2, name: "2"}];
const initialValue = "Select";

test("点击选项后自动更新显示文本", () => {
  const onSelectMock = jest.fn();
  render(<Dropdown items={items} initialValue={initialValue} onSelect={onSelectMock} />);

  // 初始状态验证
  expect(screen.getByTestId('test-dropdown')).toHaveTextContent('Select');

  // 点击第二个选项
  const secondOption = screen.getAllByRole('listitem')[1];
  fireEvent.click(secondOption);

  // 验证显示文本更新
  expect(screen.getByTestId('test-dropdown')).toHaveTextContent('2');
  // 验证回调函数拿到了选中的项
  expect(onSelectMock).toHaveBeenCalledWith(items[1]);
});

内容的提问来源于stack exchange,提问作者Humanoid Mk.12

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 22:49:58