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

