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

如何用Jest和Enzyme测试React组件中的toggleFilter函数?

如何正确测试React组件中的toggleFilter函数?

首先咱们先理清问题根源:你调用toggleFilter()的时候完全没传type和name参数!这就导致函数里this.state.appliedFilterList[type]中的type是undefined,自然找不到对应的属性,触发了Cannot read property 'includes' of undefined的错误。而且这个函数本身是用来修改组件state的,根本没有返回值,你用expect(...).toBe(true)来断言完全不对。

先回顾下你的核心代码:

你的toggleFilter函数定义:

toggleFilter = (type, name) => { 
  const filterApplied = this.state.appliedFilterList[type].includes(name); 
  if (filterApplied) { 
    // 移除已应用的过滤器
    this.setState(prevState => ({ 
      appliedFilterList: { 
        ...prevState.appliedFilterList, 
        [type]: prevState.appliedFilterList[type].filter(filter => filter !== name) 
      } 
    })); 
  } else { 
    // 添加新过滤器
    this.setState(prevState => ({ 
      appliedFilterList: { 
        ...prevState.appliedFilterList, 
        [type]: [...prevState.appliedFilterList[type], name] 
      } 
    })); 
  } 
};

组件中appliedFilterList的初始结构:

appliedFilterList: { a: [], b: [], t: [] },

下面是修正后的测试方案,覆盖核心场景:

1. 测试「添加过滤器」的场景

it("adds a filter when it's not already applied", () => {
  // 初始化符合组件要求的appliedFilter结构
  const initialAppliedFilter = { a: [], b: [], t: [] };
  const wrapper = shallow(
    <ProductList 
      headerText="Hello World" 
      productList={data} 
      paginationSize="10" 
      accessFilters={["a 1", "a 2"]} 
      bandwidthFilters={["b 1", "b 2"]} 
      termsFilters={["t 1", "t 2"]} 
      appliedFilterList={initialAppliedFilter} 
    />
  );

  // 调用toggleFilter,传入合法的type和name
  wrapper.instance().toggleFilter('a', 'a 1');
  
  // 强制更新组件,因为setState是异步操作
  wrapper.update();
  
  // 断言state中的appliedFilterList是否正确添加了目标值
  expect(wrapper.state('appliedFilterList').a).toEqual(['a 1']);
});

2. 测试「移除过滤器」的场景

it("removes a filter when it's already applied", () => {
  // 初始化时让a类型的过滤器已经包含'a 1'
  const initialAppliedFilter = { a: ['a 1'], b: [], t: [] };
  const wrapper = shallow(
    <ProductList 
      headerText="Hello World" 
      productList={data} 
      paginationSize="10" 
      accessFilters={["a 1", "a 2"]} 
      bandwidthFilters={["b 1", "b 2"]} 
      termsFilters={["t 1", "t 2"]} 
      appliedFilterList={initialAppliedFilter} 
    />
  );

  wrapper.instance().toggleFilter('a', 'a 1');
  wrapper.update();
  
  // 断言a类型的过滤器数组已被清空
  expect(wrapper.state('appliedFilterList').a).toEqual([]);
});

3. 边界情况测试(可选)

如果你的组件需要处理传入非法type的情况,可以加这个测试:

it("does nothing when passing an invalid filter type", () => {
  const initialAppliedFilter = { a: [], b: [], t: [] };
  const wrapper = shallow(
    <ProductList 
      headerText="Hello World" 
      productList={data} 
      paginationSize="10" 
      accessFilters={["a 1", "a 2"]} 
      bandwidthFilters={["b 1", "b 2"]} 
      termsFilters={["t 1", "t 2"]} 
      appliedFilterList={initialAppliedFilter} 
    />
  );

  // 传入组件不支持的type 'x'
  wrapper.instance().toggleFilter('x', 'x 1');
  wrapper.update();
  
  // 断言state没有发生变化
  expect(wrapper.state('appliedFilterList')).toEqual(initialAppliedFilter);
});

额外注意事项

  • 确保你测试时传入的appliedFilter结构完全符合组件预期,必须包含a、b、t三个数组属性,不然也会出现类似的undefined错误。
  • 因为React的setState是异步的,调用toggleFilter后一定要调用wrapper.update()强制组件更新,这样才能拿到最新的state进行断言。
  • 这个函数的核心作用是修改组件state,所以测试的核心应该是验证state的变化是否符合预期,而不是去断言函数的返回值(它本来就没有返回值)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:02:27