Search code examples
angularjsunit-testingtestingjasmineangularjs-ngmock

Jasmine test with angular ng-mock not working with controller and promise


I have been playing a bit with the following code and I am not able to find the issue, the test fails wit the following message: "Expected undefined not to be undefined."

I have a Service which returns a promise to my controller. In the controller, I am using $q.all to do some stuff immediately after I get the promise resolved.

I tried to follow this example, but the big difference I see is that in the example it has the call in the root of the controller and I have the service call inside of the method "$scope.CustomerTest" so I have this additional line to before the apply ( $scope.$apply() ) "$scope.CustomerTest('Mr');":

http://www.bradoncode.com/blog/2015/07/13/unit-test-promises-angualrjs-q/

This is my test code:

var $scope;
var $q;
var deferred;
var $httpBackend;

//Inject the module "before each test"
beforeEach(angular.mock.module('marketingApp'));

beforeEach(inject(function ($controller,_$httpBackend_,  _$rootScope_, _$q_, marketingService) {
    $q = _$q_;
    $scope = _$rootScope_.$new();
    $httpBackend = _$httpBackend_;

    // We use the $q service to create a mock instance of defer
    deferred = _$q_.defer();

    // Use a Jasmine Spy to return the deferred promise
    spyOn(marketingService, 'getTitleSuggested').and.returnValue(deferred.promise);

    // Init the controller, passing our spy service instance
    $controller('customerController', {
        $scope: $scope,
        marketingService: marketingService
    });
}));

it('should resolve promise', function () {
    // Setup the data we wish to return for the .then function in the controller
    var titles = [{ "Id": 1, "Name": "Mr" }];

    deferred.resolve(titles);

    $httpBackend.when('GET', '/MarketingCustomers/GetTitleSuggested')
        .respond(200, titles);

    //I call to the controller method here.
    $scope.CustomerTest('Mr');

    $scope.$apply();

    // Since we called apply, not we can perform our assertions
    //expect($scope.TitlesTest).not.toBe(undefined);
    expect($scope.SelectedCustomerTitle).toEqual('Mr');
    //expect($scope.error).toBe(undefined);
});

And this is the plunker:

http://plnkr.co/edit/3IMzqH1yKW8kazZFWaA0?p=preview

Commenting the first test (it) of the controller.spec.js the other two test works. Any help please?


Solution

  • Resolved my issue here is again the plunker if someone has similar problem, hopefully it can helps.

    Here is the test:

    describe('CustomerController.js', function() {
    
    var results = [{
     "Id": 1,
     "Name": "Mr"
    }];
    
    var $controller;
    var $q;
    var $rootScope;
    var $scope;
    var marketingService;
    
    beforeEach(angular.mock.module('marketingApp'));
    
    beforeEach(inject(function(_$rootScope_, $controller, _$q_, 
    _marketingService_) {
    $scope = _$rootScope_.$new();
    $q = _$q_;
    $rootScope = _$rootScope_;
    marketingService = _marketingService_;
    
    $controller('customerController', {
      $scope: $scope,
      $rootScope: $rootScope
    });
    
    spyOn(marketingService, 'getTitleSuggested').and.callFake(function() {
      var deferred = $q.defer();
      deferred.resolve(results);
      return deferred.promise;
    });
    
    }));
    
    it('It should call the service" ', function() {
    
    $scope.CustomerTest('Mr');
    expect(marketingService.getTitleSuggested).toHaveBeenCalledWith('Mr');
    });
    
    
    it('It should populate the "$scope.TitlesTest" ', function() {
    
    $scope.CustomerTest('Mr');
    $rootScope.$apply();
    
    expect($scope.hello).toEqual('Hello Mr Marcos');
    expect($scope.Titles[0].Name).toBe('Mr');
    expect($scope.Titles).toBe(results);
    });
    

    });

    and this is the plunker: http://plnkr.co/edit/3IMzqH1yKW8kazZFWaA0?p=preview