AngularJS Promise回调在JasmineJS测试中未触发
AngularJS Promise回调在JasmineJS测试中未触发
问题介绍
我正在尝试对一个封装了Facebook JavaScript SDK FB
对象的AngularJS服务进行单元测试;然而,测试不起作用,我一直无法找出原因。同时,当我在浏览器中而不是使用JasmineJS单元测试运行时,使用Karma测试运行器时,服务代码是可行的。我正在使用Angular promises来测试一个异步方法,通过$q
对象实现。我已经设置了异步运行测试,使用Jasmine 1.3.1异步测试方法,但是waitsFor()
函数从不返回true
(参见下面的测试代码),只是在5秒后超时。(Karma还没有使用Jasmine 2.0的异步测试API)。我认为可能是因为promise的then()
方法从未触发(我设置了console.log()
来显示),尽管在异步方法返回时我调用了$scope.$apply()
,以让Angular知道它应该运行一个digest循环并触发then()
回调...但我可能是错的。这是运行测试时的错误输出:
Chrome 32.0.1700 (Mac OS X 10.9.1) service Facebook should return false
if user is not logged into Facebook FAILED
timeout: timed out after 5000 msec waiting for something to happen
Chrome 32.0.1700 (Mac OS X 10.9.1):
Executed 6 of 6 (1 FAILED) (5.722 secs / 5.574 secs)
代码
这是我的服务的单元测试(请参见内联注释,解释我到目前为止的发现):
'use strict'; describe('service', function () { beforeEach(module('app.services')); describe('Facebook', function () { it('should return false if user is not logged into Facebook', function () { // 提供一个Facebook JavaScript SDK `FB`对象的假版本: module(function ($provide) { $provide.value('fbsdk', { getLoginStatus: function (callback) { return callback({}); }, init: function () {} }); }); var done = false; var userLoggedIn = false; runs(function () { inject(function (Facebook, $rootScope) { Facebook.getUserLoginStatus($rootScope) // 这个`then()`回调从未运行,即使我在服务中调用了`$scope.$apply()` :( .then(function (data) { console.log("Found data!"); userLoggedIn = data; }) .finally(function () { console.log("Setting `done`..."); done = true; }); }); }); // 这只是在5秒后超时,因为`done`在上面的`then()`方法中从未更新为`true` :( waitsFor(function () { return done; }); runs(function () { expect(userLoggedIn).toEqual(false); }); }); // it() }); // Facebook spec }); // Service module spec
这是我正在测试的Angular服务(请参见内联注释,解释我到目前为止的发现):
'use strict'; angular.module('app.services', []) .value('fbsdk', window.FB) .factory('Facebook', ['fbsdk', '$q', function (FB, $q) { FB.init({ appId: 'xxxxxxxxxxxxxxx', cookie: false, status: false, xfbml: false }); function getUserLoginStatus ($scope) { var deferred = $q.defer(); // 这是延迟promise被解决的地方。请注意,我在最后调用了`$scope.$apply()`,以让Angular知道触发调用`getUserLoginStatus()`的`then()`回调。 FB.getLoginStatus(function (response) { if (response.authResponse) { deferred.resolve(true); } else { deferred.resolve(false) } $scope.$apply(); // <-- 告诉Angular触发`then()`。 }); return deferred.promise; } return { getUserLoginStatus: getUserLoginStatus }; }]);
资源
这是我已经查看过的其他资源的列表,以尝试解决这个问题。
- Angular API参考:
$q
这解释了如何在Angular中使用promises,并提供了一个使用promises的代码单元测试的示例(请注意解释为什么需要调用$scope.$apply()
来触发then()
回调)。 - Jasmine异步测试示例
- Jasmine.Async:使Jasmine的异步测试更简单
- 使用Jasmine 2.0.0测试异步JavaScript 这些示例演示了如何使用Jasmine 1.3.1的异步方法来测试实现Promise模式的对象。它们与我自己的测试模式略有不同,我的模式是根据直接来自Jasmine 1.3.1异步测试文档的示例建模的。
- StackOverflow答案
- Angular JS中未调用Promise回调
- angularjs - 控制器中的promise永远不会解决
- 返回自服务的AngularJS promises未触发
总结
请注意,我知道已经存在其他用于Facebook JavaScript SDK的Angular库,例如以下:
我现在不想使用它们,因为我想学习如何自己编写一个Angular服务。因此,请限制回答仅帮助我修复代码中的问题,而不是建议我使用其他人的解决方案。
那么,有没有人知道为什么我的测试不起作用?