title: AngularJS Promise Callback Not Trigged in JasmineJS Test
body: <h1>Problem Intro</h1>
  
  <p>I'm trying to unit test an AngularJS service that wraps the <a href="https://developers.facebook.com/docs/javascript/quickstart" rel="nofollow noreferrer">Facebook
  JavaScript SDK</a> <code>FB</code> 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 <a href="http://pivotal.github.io/jasmine/" rel="nofollow noreferrer" title="Jasmine 1.3.1 Documentation">JasmineJS</a> unit
  test, run with <a href="http://karma-runner.github.io/0.10/index.html" rel="nofollow noreferrer">Karma test runner</a>.</p>
  
  <p>I'm testing an asynchronous method using Angular promises via the <a href="http://docs.angularjs.org/api/ng.$q" rel="nofollow noreferrer"><code>$q</code></a>
  object. I have the tests set up to run asynchronously using the <a href="http://pivotal.github.io/jasmine/#section-Asynchronous_Support" rel="nofollow noreferrer">Jasmine
  1.3.1 async testing methods</a>, but <strong>the <code>waitsFor()</code>
  function never returns <code>true</code> (see test code below), it just times-out
  after 5 seconds</strong>. (Karma doesn't ship with the Jasmine 2.0 async testing API yet).</p>
  
  <p>I think it might be because the <code>then()</code> method of the
  promise is never triggered (I've got a <code>console.log()</code> set up to show
  that), even though I'm calling <code>$scope.$apply()</code> when the asynchronous
  method returns, to let Angular know that it should run a digest
  cycle and trigger the <code>then()</code> callback...but I could be wrong.</p>
  
  <p>This is the error output that comes from running the test:</p>
  
  <pre class="lang-none prettyprint-override"><code>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></pre>
  
  <h1>The Code</h1>
  
  <p>This is my unit test for the service (<strong>see inline comments that explain what I've found so far</strong>):</p>
  
  <pre class="lang-javascript prettyprint-override"><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
  </code></pre>
  
  <p>And this is my Angular service that is being tested (<strong>see inline comments that explain what I've found so far</strong>):</p>
  
  <pre class="lang-javascript prettyprint-override"><code>'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(); // &lt;-- Tell Angular to trigger `then()`.
        });
  
        return deferred.promise;
      }
  
      return {
        getUserLoginStatus: getUserLoginStatus
      };
    }]);
  </code></pre>
  
  <h1>Resources</h1>
  
  <p>Here is a list of other resources that I've already taken a look at to
  try to solve this problem.</p>
  
  <ul>
  <li><p><a href="http://docs.angularjs.org/api/ng.$q" rel="nofollow noreferrer">Angular API Reference: <code>$q</code></a></p>
  
  <p>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 <code>$scope.$apply()</code> needs to be called to trigger the <code>then()</code> callback).</p></li>
  <li><p>Jasmine Async Testing Examples</p>
  
  <ul>
  <li><a href="http://lostechies.com/derickbailey/2012/08/18/jasmine-async-making-asynchronous-testing-with-jasmine-suck-less/" rel="nofollow noreferrer">Jasmine.Async: Making Asynchronous Testing With Jasmine Suck Less</a></li>
  <li><p><a href="http://blogs.lessthandot.com/index.php/webdev/uidevelopment/javascript/testing-asynchronous-javascript-w-jasmine/" rel="nofollow noreferrer">Testing Asynchronous Javascript w/ Jasmine 2.0.0</a></p>
  
  <p>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 <a href="http://pivotal.github.io/jasmine/#section-Asynchronous_Support" rel="nofollow noreferrer">Jasmine 1.3.1 async testing documentation</a>.</p></li>
  </ul></li>
  <li><p>StackOverflow Answers</p>
  
  <ul>
  <li>Promise callback not called in Angular JS
  
  <ul>
  <li><a href="https://stackoverflow.com/a/16323920/456814">Answer 1</a></li>
  <li><a href="https://stackoverflow.com/a/16323885/456814">Answer 2</a></li>
  </ul></li>
  <li><a href="https://stackoverflow.com/a/14246907/456814">angularjs - promise never resolved in controller</a></li>
  <li><a href="https://stackoverflow.com/a/14530341/456814">AngularJS promises not firing when returned from a service</a></li>
  </ul></li>
  </ul>
  
  <h1>Summary</h1>
  
  <p><strong>Please note that I'm aware that there are already other Angular libraries out there for the Facebook JavaScript SDK</strong>, such as the following:</p>
  
  <ul>
  <li><a href="https://github.com/pc035860/angular-easyfb" rel="nofollow noreferrer">angular-easyfb</a></li>
  <li><a href="https://github.com/Ciul/angular-facebook" rel="nofollow noreferrer">angular-facebook</a></li>
  </ul>
  
  <p>I'm not interested in using them right now, because I wanted to learn how to write an Angular service myself. <strong>So please keep answers restricted to helping me fix the problems in <em>my code</em>, instead of suggesting that I use someone else's</strong>.</p>
  
  <p>So, with that being said, <strong>does anyone know why my test isn't working?</strong></p>