0

I am new to promises and seem to have the actual code working, but trying to write a unit test too...

Heres my controller:

appModule.controller('MyController', function($scope, myService, $timeout, mySecondService) {

    $scope.accept = false;
    $scope.loading = false;
    $scope.text = 'Some text';

    $scope.testCall = function() {

        $scope.person = true;
        $scope.text = '';
        $scope.loading = true;

        myService.getWeather()            
            .then(function(data) {
                if (data.valid===true) {
                    $timeout(function(){
                        $scope.loading = false;
                        $scope.accept = true;

                        $timeout(function(){
                            $scope.customer.cart = false;
                        }, 1400);

                    }, 1500);
                }
                else {
                    $scope.person = false;
                    $scope.newMessage = mySecondService.getItem();
                }
            }, function(error) {
                $scope.person = false;
                $scope.newMessage = mySecondService.getItem();
            });
    }
});

ControllerSpec:

beforeEach(module('myApp'));

describe("MyController Tests", function() {

    var scope;
    var ctrl;

    var customerInfo = {           
            "ID" : "212143513",
            "firstName" : "Lewis",
            "lastName" : "Noel"
    };

    beforeEach(inject(function($rootScope, $controller, myService) {
        scope = $rootScope.$new();
        rootScope = $rootScope;        

        mockMyService = myService;      

        ctrl = $controller('MyController', {$scope:scope, myService:mockMyService});

        spyOn(scope, 'testCall').and.callThrough();
    }));

    it("On controller load, initialise variables", function() {
        expect(scope.text).toEqual('Some text');
        expect(scope.loading).toEqual(false);
        expect(scope.accept).toEqual(false);
    });
});

The above tests the initailisation of the $scope, but nothing within the service...

Here's my service:

appModule.factory('myService', function ($http, $q) {
return {
        getWeather: function() {
            return $http.get('/cart/customerCart/546546')
                .then(function(response) {
                    if (typeof response.data === 'object') {
                        return response.data;
                    }
                    else {
                        // invalid response
                        return $q.reject(response.data);
                    }

                }, function(response) {
                    // something went wrong
                    return $q.reject(response.data);
                });
        }
    };
});
2
  • You need to isolate the component that you are testing. If you are in the controller test instead of assign the original service to the controller, pass an object that mimics the same API of your service but that doesn't make any request. Or use the ngMockE2E service. Anywaqy you'll need to call manually scope.$apply to run the request because the mock module is holding then from been executed Commented Jan 25, 2016 at 14:47
  • @Raulucco - not a very useful comment. If you look at my first test, you cans see ive isolated the controller.. Once that is successful, i would isolate the service next. Commented Jan 25, 2016 at 15:09

1 Answer 1

1

If you're asking how to test services in general, here's what I do:

describe("myService", function() {
  var myService;
  beforeEach(inject(function($rootScope, _myService_) {
    myService = _myService_;
  }));

  it("On controller load, initialise variables", function() {
    var result;
    myService.getWeather().then( function (data) {
      result = data;
    });
    $rootScope.$apply();
    expect(result).toEqual(whatever);
  });
});

Notes:

  • You can use the _myService_ underscore trick to get the service myService without it creating a local variable with that name (see docs).
  • You need to call $rootScope.$apply() to flush promises in tests. see docs

EDIT: You're using promises wrongly, I would refactor your factory as so (untested):

appModule.factory('myService', function ($http, $q) {
  return {
    getWeather: function() {
      var defer = $q.defer();
      $http.get('/cart/customerCart/546546')
         .then(function(response) {
            if (typeof response.data === 'object') {
               defer.resolve(response.data);
            }
            else {
               // invalid response
               defer.reject(response.data);
            }
          }, function(response) {
            // something went wrong
            defer.reject(response.data);
          });
      return defer.promise;
    }
  };
});
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. Is this a valid test for my scenario? Does this test $q ??
Yes, that's the idea (though be aware I just threw that code in the answer, so check). If it doesn't, just come back and ask.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.