Angular项目Selenium-Karma测试Mock Promise方法时遇未定义属性错误
解决Angular测试中Mock void Promise方法时的"Cannot read property 'success' of undefined"错误
你遇到的问题核心是Mock的返回值没有匹配业务代码的调用结构:你的保存方法虽然标记为void,但实际返回了一个类Promise对象,而业务代码里应该是用了saveDetails().success(() => { /* 处理逻辑 */ })的链式调用写法——但你当前的Mock没有提供success这个属性,所以才会抛出这个错误。下面是具体的解决思路和方案:
问题根源拆解
AngularJS时代的$http服务返回的不是标准ES6 Promise,而是带有success()和error()特有的回调方法的类Promise对象;如果你的保存方法封装了这类调用,业务代码就会依赖这个非标准的API。而你之前Mock的可能是普通ES6 Promise,它本身并没有success方法,自然会报错。
两种可行的Mock方案
方案1:直接模拟带success/error的回调对象
如果原方法的返回结构是AngularJS风格的回调对象,你可以直接Mock一个包含对应方法的对象,确保链式调用能正常执行:
beforeEach(() => { // 假设你的对话框服务是dialogService,目标方法是saveDetails spyOn(dialogService, 'saveDetails').and.returnValue({ // 模拟success回调:执行传入的函数,并返回自身支持链式调用 success: function(callback) { callback(); return this; }, // 可选:如果业务代码用到error回调,也需要同步模拟 error: function(callback) { return this; } }); });
方案2:基于$q创建带success方法的Promise
如果原方法是用Angular的$q创建的Promise,你可以给Promise对象手动添加success方法,对齐业务代码的调用习惯:
beforeEach(inject(($q, $rootScope) => { const deferred = $q.defer(); const mockPromise = deferred.promise; // 给Promise添加success方法,映射到标准then回调 mockPromise.success = function(callback) { this.then(callback); return this; // 保持链式调用的完整性 }; // 让Mock方法返回这个自定义Promise spyOn(dialogService, 'saveDetails').and.returnValue(mockPromise); // 根据测试场景,提前resolve或reject Promise deferred.resolve(); // 触发Angular的digest循环,让Promise回调执行 $rootScope.$digest(); }));
关键注意事项
- 链式调用的完整性:
success和error方法都要返回this,这样如果业务代码有多个链式调用(比如.success().error())才不会中断。 - 触发Digest循环:Angular的Promise依赖
$rootScope的digest机制,Mock完Promise后一定要调用$rootScope.$digest(),否则回调不会执行,可能导致测试断言失败。 - 匹配原方法结构:如果原方法返回的是标准ES6 Promise,但业务代码错误用了
.success(),那你可能需要同时修正业务代码;如果是AngularJS的传统写法,就按上面的方式Mock即可。
调整后,你的测试用例应该就能正常执行,不会再出现success属性未定义的错误了。
内容的提问来源于stack exchange,提问作者Sameera Manorathna
相关产品推荐
相关产品推荐

