<!DOCTYPE html>
<html>

  <head>
    <link data-require="jasmine@1.3.1" data-semver="1.3.1" rel="stylesheet" href="//cdn.jsdelivr.net/jasmine/1.3.1/jasmine.css" />
    
    <!-- Include the Jasmine, JQuery and Angular libraries. -->
    <script data-require="jasmine@1.3.1" data-semver="1.3.1" src="//cdn.jsdelivr.net/jasmine/1.3.1/jasmine.js"></script>
    <script data-require="jasmine@1.3.1" data-semver="1.3.1" src="//cdn.jsdelivr.net/jasmine/1.3.1/jasmine-html.js"></script>
    <script data-require="angular.js@1.2.16" data-semver="1.2.16" src="https://code.angularjs.org/1.2.16/angular.js"></script>
    <script data-require="jquery@2.0.3" data-semver="2.0.3" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
    <script data-require="json2@*" data-semver="0.0.2012100-8" src="//cdnjs.cloudflare.com/ajax/libs/json2/20121008/json2.js"></script>
    <!-- angular-mocks.js is required for our unit tests. -->
    <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular-mocks.js"></script>
   
    <!-- The application whose directive we're testing. -->
    <script src="myApplication.js"></script>
    
    <!-- Our Jasmine tests. -->
    <script src="myTests.js"></script>
    
    <!-- Let's get started! -->
    <script src="jasmineBoot.js"></script>
  </head>

  <body></body>

</html>
describe('directiveUsingAsyncService', function(){
  
  var elementUnderTest;
  var deferredResolution;
  var parentScope;
  
  beforeEach(module('app'));
  
  beforeEach(angular.mock.inject(function($compile, $rootScope, $q, AsyncService ) {

    // $q.defer() returns an object that packages a promise together with
    // methods to resolve or reject it. We will use this variable to manually
    // resolve the promise at the right moment.
    deferredResolution = $q.defer();
   
    // Replace the AsyncService.promiseToDoSomething() with a spy that
    // returns the promise inside our $q.defer() object.
    spyOn(AsyncService,'promiseToDoSomething')
      .andReturn(deferredResolution.promise); 
     
    // Add the directive we want to test to the DOM.
    elementUnderTest = angular.element('<directive-using-async-service></directive-using-async-service>');
    parentScope = $rootScope.$new();
    $compile(elementUnderTest)(parentScope);
    $('body').append(elementUnderTest);    
    parentScope.$apply();
  }));
  
  afterEach(function() {
    $(elementUnderTest).remove();  
  });
  
  var getCurrentText = function () {
    return $(elementUnderTest).text();
  }
  
  it('says "Waiting..." before the async method completes', function() {
    
    // We have not yet resolved deferToResolveCallToAsyncService.promise,
    // so the directive should behave as if the service call has not completed.
    expect(getCurrentText()).toBe("Waiting...");
  });
  
  it('says "Done!" after the async method completes', function() {
    
    // Pretend that the AsyncService.promiseToDoSomething has completed.
    deferredResolution.resolve("Here's your data!");
    // Need to run a digest cycle. Angular's asynchronous methods such as
    // $http.get generally do this for you, but our method does no such favor.
    parentScope.$apply();
    
    expect(getCurrentText()).toBe("Done!");
  });
});
angular.module('app',[])

.service('AsyncService', function ($q) {
  
  // Like Angular's $http.get, this function returns a promise.
  this.promiseToDoSomething = function() {
    return $q.when('Promise fulfilled!');
  };
})

.directive('directiveUsingAsyncService', function() {
  
  return {
    restrict: 'E',
    
    scope: {},
    
    controller: ['$scope', 'AsyncService', function ($scope, asyncService) {
      
      // The text to which this directive's <p> element binds changes from 
      // "Waiting..." to "Done!" when the async operation completes.
      $scope.text = 'Waiting...';
      
      // Like Angular's $http.get, this function returns a promise.
      asyncService.promiseToDoSomething().then( function() {
        $scope.text = 'Done!';
      });
    }],
    
    template: '<p>{{text}}</p>'
  };
});
 // Runs the Jasmine 1.3.1 tests.
 // Jasmine 2.0 provides this functionality in its boot.js.
 
(function () {
    var jasmineEnv = jasmine.getEnv();
    jasmineEnv.updateInterval = 1000;

    var trivialReporter = new jasmine.TrivialReporter();

    jasmineEnv.addReporter(trivialReporter);

    jasmineEnv.specFilter = function (spec) {
        return trivialReporter.specFilter(spec);
    };

    var currentWindowOnload = window.onload;

    window.onload = function () {
        if (currentWindowOnload) {
            currentWindowOnload();
        }
        execJasmine();
    };

    function execJasmine() {
        jasmineEnv.execute();
    }

})();