【发布时间】:2014-02-07 00:06:59
【问题描述】:
问题介绍
我正在尝试对包装 Facebook
JavaScript SDK FB 对象的 AngularJS 服务进行单元测试;但是,测试不起作用,
我一直无法弄清楚为什么。此外,服务代码确实
当我在浏览器而不是JasmineJS 单元中运行它时工作
测试,使用Karma test runner 运行。
我正在通过$q 使用 Angular 承诺测试异步方法
目的。我将测试设置为使用Jasmine
1.3.1 async testing methods 异步运行,但waitsFor()
函数永远不会返回true(参见下面的测试代码),它只是超时
5 秒后。 (Karma 尚未附带 Jasmine 2.0 异步测试 API)。
我想可能是因为then() 方法
承诺永远不会被触发(我有一个 console.log() 设置显示
那),即使我在异步时调用$scope.$apply()
方法返回,让 Angular 知道它应该运行一个摘要
循环并触发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)
代码
这是我对服务的单元测试(查看内联 cmets 来解释我目前的发现):
'use strict';
describe('service', function () {
beforeEach(module('app.services'));
describe('Facebook', function () {
it('should return false if user is not logged into Facebook', function () {
// Provide a fake version of the Facebook JavaScript SDK `FB` object:
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)
// This `then()` callback never runs, even after I call
// `$scope.$apply()` in the service :(
.then(function (data) {
console.log("Found data!");
userLoggedIn = data;
})
.finally(function () {
console.log("Setting `done`...");
done = true;
});
});
});
// This just times-out after 5 seconds because `done` is never
// updated to `true` in the `then()` method above :(
waitsFor(function () {
return done;
});
runs(function () {
expect(userLoggedIn).toEqual(false);
});
}); // it()
}); // Facebook spec
}); // Service module spec
这是我正在测试的 Angular 服务(查看内联 cmets 来解释我目前的发现):
'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();
// This is where the deferred promise is resolved. Notice that I call
// `$scope.$apply()` at the end to let Angular know to trigger the
// `then()` callback in the caller of `getUserLoginStatus()`.
FB.getLoginStatus(function (response) {
if (response.authResponse) {
deferred.resolve(true);
} else {
deferred.resolve(false)
}
$scope.$apply(); // <-- Tell Angular to trigger `then()`.
});
return deferred.promise;
}
return {
getUserLoginStatus: getUserLoginStatus
};
}]);
资源
这是我已经查看过的其他资源的列表 尝试解决这个问题。
-
这解释了如何在 Angular 中使用 Promise,并举例说明如何对使用 Promise 的代码进行单元测试(注意解释为什么需要调用
$scope.$apply()来触发then()回调)。 -
Jasmine 异步测试示例
- Jasmine.Async: Making Asynchronous Testing With Jasmine Suck Less
-
Testing Asynchronous Javascript w/ Jasmine 2.0.0
这些示例说明了如何使用 Jasmine 1.3.1 异步方法来测试实现 Promise 模式的对象。它们与我在自己的测试中使用的模式略有不同,该模式是根据直接来自 Jasmine 1.3.1 async testing documentation 的示例建模的。
-
StackOverflow 答案
总结
请注意,我知道已经有其他适用于 Facebook JavaScript SDK 的 Angular 库,例如:
我现在对使用它们不感兴趣,因为我想学习如何自己编写 Angular 服务。 因此,请将答案限制在帮助我解决我的代码中的问题,而不是建议我使用其他人的。
那么,话虽如此,有人知道为什么我的测试不起作用吗?
【问题讨论】:
-
您是否尝试过 $rootScope.$apply 而不是仅在 $scope 上?
-
@hassassin 我的测试实际上是将
$rootScope传递给我的服务,所以服务基本上是在调用$rootScope.$apply()。所以是的,我已经尝试过了。不过谢谢你的建议! -
要使用 Jasmine 2.0,您应该能够使用
npm install karma-jasmine@2_0而不是npm install karma-jasmine安装 karma-jasmine
标签: javascript angularjs jasmine karma-runner