lundi 28 mars 2016

Best way to use Jasmine to test Angular Controller calls to Services with Promise return

After a week looking for a good answer/sample, I decided to post my question.

I need to know how is the best way to code and test something like this:

Controller

// my.controller.js
(function () {

  'use strict';

  angular.module('myApp.myModule').controller('Awesome', Awesome);

  function Awesome($http, $state, AwesomeService) {

    var vm = this; // using 'controllerAs' style

    vm.awesomeThingToDo = awesomeThingToDo;

    function awesomeThingToDo() {
      AwesomeService.awesomeThingToDo().then(function (data) {
        vm.awesomeMessage = data.awesomeMessage;
      });
    }
  }
})();

Service

// my.service.js
(function () {
  'use strict';

  angular.module('myApp.myModule').factory('AwesomeService', AwesomeService);

  function AwesomeService($resource, $http) {

    var service = {
      awesomeThingToDo: awesomeThingToDo
    }

    return service;

    function awesomeThingToDo() {

      var promise = $http.get("/my-backend/api/awesome").then(function (response) {
          return response.data;
        });

      return promise;
    }
  }
})();

My app works OK with this structure. And my Service unit tests are OK too. But I don't know how to do unit tests on Controller.

I tried something like this:

Specs

// my.controller.spec.js
(function () {
  'use strict';

  describe("Awesome Controller Tests", function() {

    beforeEach(module('myApp.myModule'));

    var vm, awesomeServiceMock;

    beforeEach(function () {
      awesomeServiceMock = { Is this a good (or the best) way to mock the service?
        awesomeThingToDo: function() {
          return {
            then: function() {}
          }
        }
      };
    });

    beforeEach(inject(function ($controller) {
      vm = $controller('Awesome', {AwesomeService : awesomeServiceMock});
    }));

    it("Should return an awesome message", function () {
      // I don't know another way do to it... :(
      spyOn(awesomeServiceMock, "awesomeThingToDo").and.callFake(function() {
        return {
          then: function() {
            vm.awesomeMessage = 'It is awesome!'; // <-- I think I shouldn't do this.
          }
        }
      });

      vm.awesomeThingToDo(); // Call to real controller method which should call the mock service method.

      expect(vm.awesomeMessage).toEqual('It is awesome!'); // It works. But ONLY because I wrote the vm.awesomeMessage above.

    });

  });
})();

My app uses Angular 1.2.28 and Jasmine 2.1.3 (with Grunt and Karma).

Aucun commentaire:

Enregistrer un commentaire