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

Redux Saga测试异常:未调用API导致modules未定义

问题:Redux Saga测试中出现「TypeError: modules is not iterable」错误

测试Redux Saga代码时,saga未在测试环境中正确获取api.getModules的返回值,导致modules变量未定义,触发「TypeError: modules is not iterable」错误,但该saga在实际应用中运行正常。

相关代码

测试代码

import { call, put } from "redux-saga/effects";
import { addModule } from "../store/modules";
import { getModulesSaga } from "./ModuleSagas";
import * as api from '../api/app';


it('fetches the modules from the server', () => {
    const generator = getModulesSaga();
    expect(generator.next().value).toEqual(call(api.getModules)); // pass
    expect(generator.next().value).toEqual(put(addModule())); // fail TypeError: modules is not iterable
})

Sagas代码(sagas/ModuleSagas.ts)

import { call, put } from "redux-saga/effects";
import { addModule } from "../store/modules";
import * as api from "../api/app";

export function* getModulesSaga() {
    const modules = yield call(api.getModules);

    console.log(modules); // console.log undefined
    
    for (const module of modules) {
        yield put(addModule(module));
    }
}

API代码(api/app.ts)

import noAuthClient from './clients/unauthClient';

export const getModules = async () => {
    console.log('[API] getModules');

    return [
        {id: 1, name: 'Module 1'},
    ]

    //return await noAuthClient.get('/api/modules');
} 

Jest输出

FAIL  sagas/module_sagas.test.js
  ● Console

    console.log
      undefined

      at log (sagas/ModuleSagas.ts:8:13)
          at getModulesSaga.next (<anonymous>)

  ● fetches the modules from the server

    TypeError: modules is not iterable

       8 |     console.log(modules);
       9 |     
    > 10 |     for (const module of modules) {
         |                          ^
      11 |         yield put(addModule(module));
      12 |     }
      13 | }

      at modules (sagas/ModuleSagas.ts:10:26)
          at getModulesSaga.next (<anonymous>)
      at Object.next (sagas/module_sagas.test.js:10:

解决方案

原因分析

Redux Saga的generator函数是惰性执行的,测试时调用generator.next()仅会执行到下一个yield语句并返回描述对象。第一个yield call(api.getModules)执行后,必须手动传入该call的模拟返回值,否则saga中的modules会被赋值为undefined,迭代时就会触发错误。

修复后的测试代码

import { call, put } from "redux-saga/effects";
import { addModule } from "../store/modules";
import { getModulesSaga } from "./ModuleSagas";
import * as api from '../api/app';

it('fetches the modules from the server', () => {
    // 模拟api返回的模块数据
    const mockModules = [{id: 1, name: 'Module 1'}];
    const generator = getModulesSaga();
    
    // 验证第一个yield:调用api.getModules
    expect(generator.next().value).toEqual(call(api.getModules));
    
    // 传入模拟数据,为saga中的modules变量赋值
    expect(generator.next(mockModules).value).toEqual(put(addModule(mockModules[0])));
    
    // 验证saga执行结束
    expect(generator.next().done).toBe(true);
})

多模块场景的完整测试

如果API返回多个模块,可逐步验证所有put操作:

it('fetches all modules from the server', () => {
    const mockModules = [
        {id: 1, name: 'Module 1'},
        {id: 2, name: 'Module 2'}
    ];
    const generator = getModulesSaga();
    
    expect(generator.next().value).toEqual(call(api.getModules));
    // 验证第一个模块的addModule动作
    expect(generator.next(mockModules).value).toEqual(put(addModule(mockModules[0])));
    // 验证第二个模块的addModule动作
    expect(generator.next().value).toEqual(put(addModule(mockModules[1])));
    // 确认saga执行完成
    expect(generator.next().done).toBe(true);
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 04:20:15