如何用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
相关产品推荐
相关产品推荐

