AngularJS无极回调JasmineJS试验未触发时 [英] AngularJS Promise Callback Not Trigged in JasmineJS Test
问题描述
我试图单元测试封装了 Facebook上AngularJS服务
JavaScript的SDK FB
对象;然而,测试不工作,
我一直无法找出原因。此外,该服务code呢
工作时,我在浏览器中,而不是 JasmineJS 单位运行
测试中,与噶测试运行运行。
I'm trying to unit test an AngularJS service that wraps the Facebook
JavaScript SDK FB
object; however, the test isn't working,
and I haven't been able to figure out why. Also, the service code does
work when I run it in a browser instead of a JasmineJS unit
test, run with Karma test runner.
我测试通过 $ Q
目的。我已经使用茉莉花设置为异步运行测试
1.3.1异步测试方法的,但的 waitsFor()
函数永远不会返回真正
(见测试code以下),它只是将超时
5秒钟后。 (噶不与茉莉花2.0异步API测试尚未出货)。
I'm testing an asynchronous method using Angular promises via the $q
object. I have the tests set up to run asynchronously using the Jasmine
1.3.1 async testing methods, but the waitsFor()
function never returns true
(see test code below), it just times-out
after 5 seconds. (Karma doesn't ship with the Jasmine 2.0 async testing API yet).
我想可能是因为在则()
方法
承诺永远不会触发(我有一个的console.log()
设置为显示
那),即使我打电话 $范围。$适用()
当异步
方法返回,让角知道它应该运行摘要
循环并触发则()
回调...但我可能是错的。
I think it might be because the then()
method of the
promise is never triggered (I've got a console.log()
set up to show
that), even though I'm calling $scope.$apply()
when the asynchronous
method returns, to let Angular know that it should run a digest
cycle and trigger the then()
callback...but I could be wrong.
这是来自运行测试的错误输出:
This is the error output that comes from running the test:
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)
的code
这是我的服务单元测试(看到,解释一下我到目前为止发现内嵌注释):
'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
这是正在测试我的角度服务(看到,解释一下我到目前为止发现内嵌注释):
'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
};
}]);
资源
下面是我在已经采取了看其他资源列表
试图解决这个问题。
Resources
Here is a list of other resources that I've already taken a look at to try to solve this problem.
这说明了如何使用承诺的角度,以及给予使用承诺如何单元测试code的例子(注意,为什么 $范围的解释。$适用()
需要调用触发则()
回调)。
This explains how to use promises in Angular, as well as giving an example of how to unit-test code that uses promises (note the explanation of why $scope.$apply()
needs to be called to trigger the then()
callback).
茉莉花异步测试实例
- Jasmine.Async:进行异步测试茉莉花少犯几次
-
<一个href=\"http://blogs.lessthandot.com/index.php/webdev/uidevelopment/javascript/testing-asynchronous-javascript-w-jasmine/\">Testing异步JavaScript瓦特/茉莉花2.0.0
这给出了如何使用茉莉花1.3.1异步方法来测试实现无极模式对象的示例。他们是从我在我自己的测试,这是该示例仿照使用的模式直接从茉莉花自带略有不同1.3.1异步测试文档。
These give examples of how to use the Jasmine 1.3.1 async methods to test objects implementing the Promise pattern. They're slightly different from the pattern I used in my own test, which is modeled after the example that comes directly from the Jasmine 1.3.1 async testing documentation.
StackOverflow的答案
StackOverflow Answers
- 无极回调角JS不叫
- Promise callback not called in Angular JS
- Answer 1
- Answer 2
请注意,我知道,已经有其他的角图书馆在那里为Facebook的JavaScript SDK ,如以下内容:
- angular-easyfb
- angular-facebook
我不感兴趣使用它们,现在,因为我想学习如何编写一个角度的服务喽。 所以,请保持限于帮我解决了问题答案的我的code 的,而不是暗示我用别人的
I'm not interested in using them right now, because I wanted to learn how to write an Angular service myself. So please keep answers restricted to helping me fix the problems in my code, instead of suggesting that I use someone else's.
所以,他这样说,有谁知道为什么我的测试是不工作?
推荐答案
TL; DR
呼叫
$ rootScope $摘要()
从测试code,它会传递:Call
$rootScope.$digest()
from your test code and it'll pass:it('should return false if user is not logged into Facebook', function () { ... var userLoggedIn; inject(function (Facebook, $rootScope) { Facebook.getUserLoginStatus($rootScope).then(function (data) { console.log("Found data!"); userLoggedIn = data; }); $rootScope.$digest(); // <-- This will resolve the promise created above expect(userLoggedIn).toEqual(false); }); });
请注意:我删除
的run()
和等待()
调用,因为正在这里不需要他们(无正在执行实际的异步调用)。Note: I removed
run()
andwait()
calls because they're not needed here (no actual async calls being performed).龙解释
下面是发生了什么:当你调用
getUserLoginStatus()
,它在内部运行FB.getLoginStatus()
这反过来执行其回调的立即,因为它应该,因为你已经嘲笑它做precisely这一点。但是,你的$范围。$适用()
呼叫是指回调中,所以它被执行的前的的。然后( )
语句在测试中。而且,由于则()
创建一个新的希望,新的消化需要这一承诺得到解决。Here's what's happening: When you call
getUserLoginStatus()
, it internally runsFB.getLoginStatus()
which in turn executes its callback immediately, as it should, since you've mocked it to do precisely that. But your$scope.$apply()
call is within that callback, so it gets executed before the.then()
statement in the test. And sincethen()
creates a new promise, a new digest is required for that promise to get resolved.相信这个问题不会在浏览器中发生,因为的二分之一的原因:
I believe this problem doesn't happen in the browser because of one out of two reasons:
-
FB.getLoginStatus()
不立即调用它的回调,所以任何则()
通话先运行;或 - 别的东西在应用程序中触发一个新的周期消化
FB.getLoginStatus()
doesn't invoke its callback immediately so anythen()
calls run first; or- Something else in the application triggers a new digest cycle.
所以,把它包起来,如果你创建一个测试中的承诺,明确与否,你将不得不触发在某些时候摘要周期为了这个承诺得到解决。
So, to wrap it up, if you create a promise within a test, explicitly or not, you'll have to trigger a digest cycle at some point in order for that promise to get resolved.
这篇关于AngularJS无极回调JasmineJS试验未触发时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- Promise callback not called in Angular JS