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

React单元测试中数组filter+includes失效问题排查

问题:Primereact Column Toggler的onColumnToggle测试时状态未正确更新

我来帮你拆解下这个问题——你遇到的核心卡点是JavaScript对象引用的严格相等判断导致的,咱们一步步理清楚:

你的组件核心代码

constructor() { 
  super(); 
  this.state = { selectedColumns: [] } 
}
componentDidMount() { 
  this.setState({ selectedColumns: this.props.columnProps, }) 
}
onColumnToggle(event) { 
  let selectedColumns = event.value; 
  let orderedSelectedColumns = this.props.columnProps.filter(obj => selectedColumns.includes(obj)); 
  this.setState({selectedColumns: orderedSelectedColumns}); 
}

你的测试代码片段

describe('MyComponent', () => { 
  let wrapper; 
  let instance; 
  beforeEach(() => { 
    MyComponent.defaultProps = { 
      columns: [ 
        {field: 'vin', header: 'Vin'}, 
        {field: 'year', header: 'Year'}, 
        {field: 'brand', header: 'Brand'}, 
        {field: 'color', header: 'Color'} 
      ] 
    }; 
    wrapper = shallow(<MyComponent columnProps={MyComponent.defaultProps.columns}/>); 
    instance = wrapper.instance(); 
    jest.clearAllMocks(); 
  }); 

  describe('onColumnToggle function', () => { 
    it('should change "selectedColumns" state', () => { 
      const columnMock = { 
        value: [ 
          {field: 'year', header: 'Year'}, 
          {field: 'brand', header: 'Brand'} 
        ] 
      } 
      instance.onColumnToggle(columnMock); 
      expect(wrapper.state('selectedColumns')).toEqual(columnMock.value) 
    }) 
  })
})

问题根源

你调试发现selectedColumns.includes(obj)始终返回false,本质原因是:

  • this.props.columnProps里的对象是你在beforeEach中定义的MyComponent.defaultProps.columns的内存实例
  • 而测试时columnMock.value里的对象是全新创建的独立对象,虽然它们的字段和值完全一致,但JavaScript中对象是引用类型,includes内部用的严格相等(===)判断的是两个对象是否指向内存中的同一个地址,而非内容是否相同。

所以includes会判定这是两个不同的对象,返回false,最终filter得到空数组,state自然就变成了空数组。

解决方案

有两种实用的解决方式,你可以根据业务场景选择:

方案1:测试中复用props里的实际对象

既然组件依赖props里的对象引用,那测试时直接取用wrapper.props().columnProps里的对象,而非重新创建:

it('should change "selectedColumns" state', () => {
  const propsColumns = wrapper.props().columnProps;
  // 直接从props里取对应位置的对象引用
  const columnMock = { 
    value: [propsColumns[1], propsColumns[2]] // 对应year和brand的对象
  } 
  instance.onColumnToggle(columnMock); 
  expect(wrapper.state('selectedColumns')).toEqual(columnMock.value) 
})

方案2:修改onColumnToggle函数,基于唯一标识判断(更健壮)

如果实际业务中,Primereact传递的event.value可能不是原props的对象引用(比如经过序列化/反序列化的数据),建议改用对象的唯一标识(比如field字段)来过滤,摆脱对对象引用的依赖:

onColumnToggle(event) { 
  // 先提取选中列的唯一标识field
  const selectedFields = event.value.map(col => col.field); 
  // 用field匹配过滤原props中的列
  const orderedSelectedColumns = this.props.columnProps.filter(obj => selectedFields.includes(obj.field)); 
  this.setState({selectedColumns: orderedSelectedColumns}); 
}

这种方式下,哪怕测试里传的是新对象,只要field匹配就能正确过滤,测试能通过的同时,代码的健壮性也更强。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 14:02:32