lundi 16 mai 2016

Angular 1x testing multiple HTTP requests using $httpbackend

Currently, I'm trying to test a controller that's doing multiple HTTP requests using ngMocks $httpBackend service. I've read many docs & tutorials online concerning controller testing, however, I unfortunately haven't encountered how to test multiple http requests calls from a controller modifying a scope object on the same controller on each HTTP call.

How do you account for multiple HTTP requests in your tests?

Note: test setup is using karma/jasmine using Angular 1.5

Intent: I'm trying to test an upvote/down vote feature. On updateVote(idea) I'm decrementing the vote count & inverting an idea's hasVoted property.

ideas.json (fetching ideas from service)

[
  {"Number_of_Votes__c": 10, "hasVoted": true}
]

ideas.controller.js

(function () {

  angular.module('ideas')
    .controller('IdeasController', IdeasController)
    function IdeasController($scope, IdeasService) {
      $scope.ideas = [];

      $scope.getIdeas = function () {
        return IdeasService.getIdeas()
          .then(function(data){
            $scope.ideas = data;
          })
      };

      $scope.updateVote = function(idea){
        if(!idea.hasVoted){
          return this.voteService.vote(this.idea.External_Id__c)
            .then(function(data){
              idea.hasVoted = true;
              idea.Number_of_Votes__c++;
              // console.log('update', idea)
            })
        } 
        else if(idea.hasVoted) {
          return this.voteService.unvote(this.idea.External_Id__c)
            .then(function(data){
              idea.hasVoted = false;
              idea.Number_of_Votes__c--;
              // console.log('update', idea)
            })
          }

      }

    }

})();

ideas.controller.spec

describe('IdeasController', function () {
  var $scope = {};
  var $rootScope;
  var $controller;
  var IdeasService;
  var $httpBackend;
  var idea;
  var mockIdeasData = [
    {"Number_of_Votes__c": 10, "hasVoted": true}
  ];

  beforeEach(angular.mock.module('ideas'));
  beforeEach(function () {
    inject(function(_$controller_, _IdeasService_, _$httpBackend_, _$rootScope_){
      $rootScope = _$rootScope_;
      $scope = $rootScope.$new()
      $controller = _$controller_;
      IdeasService = _IdeasService_;
      $httpBackend = _$httpBackend_;
      var controller = $controller('IdeasController', {$scope: $scope});
    })
  })


  describe('getIdeas', function () {

    it('should have ideas array', function () {
      expect( Array.isArray($scope.ideas) ).toEqual(true);
      expect( $scope.ideas.length ).toEqual(0);
    });

    it("should `getIdeas` from Service", function () {
      $httpBackend
        .when('GET', './ideas.json')
        .respond(200, mockIdeasData);

      $scope.getIdeas(); 
      $httpBackend.flush();
      expect( typeof $scope.getIdeas ).toEqual('function');
      expect( $scope.ideas ).toEqual( mockIdeasData );
    });

  });

  it("should be able to upvote/downvote a particular idea", function () {
    $httpBackend
      .when('GET', './ideas.json')
      .respond(200, mockIdeasData);

      $scope.getIdeas() 
      //scope.ideas --> [{"Number_of_Votes__c": 10, "hasVoted": true}]
      $httpBackend.flush();
      idea = $scope.ideas[0];
      console.log(idea) //{"Number_of_Votes__c": 10, "hasVoted": true}

      //everything seems to not work here.
      $scope.updateVote(idea); //undefined aka idea is not an object 
      expect(idea.Number_of_Votes__c).toEqual(9);
      expect(idea.hasVoted).toEqual(false);


      $scope.updateVote(idea);
      expect(idea.Number_of_Votes__c).toEqual(10);
      expect(idea.hasVoted).toEqual(true);
  });



});

ideas.service.js

(function () {
  angular.module('ideas')
    .factory('IdeasService', IdeasService)
    function IdeasService($http){
      var ideas = [];

      var getIdeas = function(){
        return $http.get('./ideas.json')
          .then(function(response){
            ideas = response.data;
            return ideas;
          });
      };

      var getState = function(){
        return ideas;
      }

      return {
        getIdeas: getIdeas,
        getState: getState
      }

    }


})();

Aucun commentaire:

Enregistrer un commentaire