TypeError: Cannot read properties of undefined (reading 'id') 测试API调用报错求助
问题排查与解决方案
错误触发根因
这个TypeError: Cannot read properties of undefined (reading 'id')报错是代码尝试读取undefined值的id属性导致的,结合你的代码有两个明确的触发场景:
1. 单测场景触发
你的单测代码仅对api.send做了调用监听,没有配置符合业务逻辑的模拟返回值:
- 首先如果
component.addItem方法没有正确将传入的item赋值给组件的this.item属性,第一次调用api.send时读取this.item['id']就会直接报错 - 其次即使
this.item初始值正常,spyOn(api, 'send')默认会替换原方法且返回undefined,若你没有手动配置spy返回Promise,业务代码调用api.send后尝试调用.then()会先触发undefined调用then的错误;即使你配置了返回空Promise,但没有模拟返回的data数组,第一个.then里拿到的resEsp.data[0]就是undefined,赋值给this.item后,第二次调用api.send时读取this.item.id就会触发你遇到的报错
2. 生产运行时触发
业务代码没有对接口返回值做非空校验:
调用第一个ES语言的接口后,直接取resEsp['data'][0]赋值给this.item,如果接口返回的data是空数组、或者接口返回结构不符合预期,resEsp['data'][0]就是undefined,后续读取this.item.id就会触发报错。
修复方案
1. 单测代码修复
给spy配置模拟返回值,同时处理异步断言:
it('should call api.send', async () => { // 模拟api.send返回符合业务预期的结构 let spy1 = spyOn(api, 'send').and.returnValue(Promise.resolve({ data: [{ id: 1, name: 'test' // 补充其他业务需要的字段 }] })); let item = { id: 1, name: 'test', } component.addItem(item); component.itemToForm(); // 等待异步逻辑执行完成再做断言 await spy1.calls.mostRecent().returnValue; expect(spy1).toHaveBeenCalled(); });
修复前先确认component.addItem方法逻辑正常,确实会将传入的item赋值给组件的this.item属性。
2. 业务代码健壮性优化
增加非空判断,避免接口返回异常时直接报错,同时调整Promise写法避免嵌套回调地狱:
itemToForm = () => { // 先判断初始item是否存在合法id if (!this.item?.id) return; // 如果运行环境不支持可选链,替换为 if (!this.item || !this.item.id) return this.api.send(this.component, 'get', { lang: 'ES', filter: { id: this.item['id'] } } ).then(resEsp => { // 校验返回的data数组是否有值 if (!resEsp?.data?.length) return; this.item = resEsp['data'][0]; return this.api.send(this.component, 'get', { lang: 'EN', filter: { id: this.item['id'] } } ); }).then(res => { if (!res?.data?.length) { // 英文接口无返回时也可正常执行基础setForm逻辑 if (this.item) this.setForm(); return; } let itemEng = res['data'][0]; let fields = this.formDef.map(register => register.filter( field => field['register_table'].indexOf('traduction') !== -1 ).map( field => field['field_name']) ).filter(register => register.length); fields = fields.length ? fields[0] : []; if (itemEng) { this.item = Object.keys(itemEng).reduce((obj, key) => { obj[key] = this.item[key]; if (fields.indexOf(key) !== -1) { obj[key + '_eng'] = itemEng[key]; } return obj; }, {}); } if (this.item) { this.setForm(); } }).catch(err => { // 增加异常捕获,避免接口报错导致页面逻辑阻塞 console.error('获取多语言数据失败', err); }) }
内容的提问来源于stack exchange,提问作者David Angarita
相关产品推荐
相关产品推荐

