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

使用Jest测试Redux Reducer时遭遇TypeError: expect(...).arrayContaining is not a function错误求修复

Jest测试Redux Reducer时遭遇TypeError: expect(...).arrayContaining is not a function错误求修复

嘿,我来帮你搞定这个问题!你现在遇到了两个核心问题:Jest匹配器语法用错了,还有Reducer本身的逻辑bug,咱们一步步来修复:

首先解决TypeError的根源:Jest匹配器用法错误

你之所以会碰到TypeError: expect(...).arrayContaining is not a function,是因为arrayContaining是Jest的期望匹配器,它不能直接链式调用在expect()后面,必须作为参数传给toEqual、toContainEqual这类断言方法。而且它的参数必须是一个数组,不是多个零散的对象。

举个错误和正确用法的对比:

// ❌ 错误用法
expect(mockStore.getState()).arrayContaining(obj1, obj2)

// ✅ 正确用法
expect(mockStore.getState()).toEqual(expect.arrayContaining([obj1, obj2]))

然后修复测试用例的逻辑错误

你写的第二个测试用例,目标是验证FETCH_COURSE_SUCCESS触发后的状态,但你却dispatch了SELECT_COURSE的action——这完全不匹配,肯定得不到你想要的结果!

最后修复Reducer的核心逻辑bug

你的Reducer在处理SELECT_COURSE和UNSELECT_COURSE时犯了一个关键错误:它每次都把原始的data数组重新映射后追加到state里,而不是基于当前已有的state去修改对应课程的选中状态。这会导致state里的课程不断重复累加,选中状态也不会正确更新。


修复后的完整代码

1. 修复后的测试文件(myJestCode.js)

import { courseReducer } from "./courseReducer";
import { configureStore } from '@reduxjs/toolkit';
import { SELECT_COURSE, UNSELECT_COURSE, FETCH_COURSE_SUCCESS } from './courseActionTypes';

describe('course reducer', () => {
  // 这个测试用例没问题,保留
  it('returns an empty array as default state', () => {
    const store = configureStore({ reducer: courseReducer });
    expect(store.getState()).toEqual([]);
  });

  // 修复后的FETCH测试用例
  it('should return course array with isSelected set to false after FETCH_COURSE_SUCCESS', () => {
    const mockStore = configureStore({ reducer: courseReducer });
    // 👉 这里要dispatch正确的action类型!之前错用了SELECT_COURSE
    mockStore.dispatch({ type: FETCH_COURSE_SUCCESS });
    
    // 👉 正确使用arrayContaining匹配器
    expect(mockStore.getState()).toEqual(expect.arrayContaining([
      { id: 1, name: 'ES6', credit: 60, isSelected: false },
      { id: 2, name: 'Webpack', credit: 20, isSelected: false },
      { id: 3, name: 'React', credit: 40, isSelected: false }
    ]));
    // 如果需要严格匹配数组的长度和顺序,可以直接用toEqual([...])
  });

  // 新增一个测试SELECT_COURSE的用例,验证修复后的Reducer逻辑
  it('should set isSelected to true for course id 1 when SELECT_COURSE is dispatched', () => {
    const mockStore = configureStore({ reducer: courseReducer });
    // 先获取课程数据
    mockStore.dispatch({ type: FETCH_COURSE_SUCCESS });
    // 再触发选中操作(注意action里的index对应课程id)
    mockStore.dispatch({ type: SELECT_COURSE, index: 1 });
    
    expect(mockStore.getState()).toEqual(expect.arrayContaining([
      { id: 1, name: 'ES6', credit: 60, isSelected: true },
      { id: 2, name: 'Webpack', credit: 20, isSelected: false },
      { id: 3, name: 'React', credit: 40, isSelected: false }
    ]));
  });
});

2. 修复后的Reducer文件(courseReducer.js)

import { configureStore } from '@reduxjs/toolkit';
import { SELECT_COURSE, UNSELECT_COURSE, FETCH_COURSE_SUCCESS } from './courseActionTypes';

// 测试用的课程数据
const data = [
  { id: 1, name: "ES6", credit: 60 },
  { id: 2, name: "Webpack", credit: 20 },
  { id: 3, name: "React", credit: 40 }
];

export const courseReducer = (state = [], action) => {
  switch(action.type) {
    case FETCH_COURSE_SUCCESS:
      // 避免重复添加数据:如果state已有内容,直接返回;否则添加带isSelected的课程
      if (state.length > 0) return state;
      return data.map(course => ({ ...course, isSelected: false }));
    
    case SELECT_COURSE:
      // 👉 遍历当前state,修改对应id的课程的选中状态
      return state.map(course => 
        course.id === action.index ? { ...course, isSelected: true } : course
      );
    
    case UNSELECT_COURSE:
      // 👉 同理,遍历当前state修改选中状态
      return state.map(course => 
        course.id === action.index ? { ...course, isSelected: false } : course
      );
    
    default:
      return state;
  }
};

// 本地测试用的store
const store = configureStore({ reducer: courseReducer });
console.log('Initial state:', store.getState());
store.dispatch({ type: FETCH_COURSE_SUCCESS });
console.log('After FETCH:', store.getState());
store.dispatch({ type: SELECT_COURSE, index: 1 });
console.log('After SELECT id 1:', store.getState());

为什么这些修改能解决问题?

  1. Jest语法修正:把arrayContaining放在toEqual内部,符合Jest匹配器的正确调用方式。
  2. 测试用例逻辑修正:dispatch了正确的FETCH_COURSE_SUCCESS action,确保测试场景和目标一致。
  3. Reducer逻辑修正:处理SELECT/UNSELECT时,基于当前state进行修改,而不是重复追加原始数据,保证状态更新的正确性。

备注:内容来源于stack exchange,提问作者Moez Ben Rebah

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.23 09:22:40