AngularJS Promise回调在JasmineJS测试中未触发

14 浏览
0 Comments

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
    };
  }]);

资源

这是我已经查看过的其他资源的列表,以尝试解决这个问题。

总结

请注意,我知道已经存在其他用于Facebook JavaScript SDK的Angular库,例如以下:

我现在不想使用它们,因为我想学习如何自己编写一个Angular服务。因此,请限制回答仅帮助我修复代码中的问题,而不是建议我使用其他人的解决方案

那么,有没有人知道为什么我的测试不起作用?

0