0

I'm learning to use Karma and Jasmine for unit-testing in Angular, and am trying to determine how to properly mock out a factory and test that it is called by a controller. The factory makes a simple http request from the ESPN API. When the controller calls it, it passes the response data to an array. What I have so far is based off of this: Angular unit-test controllers - mocking service inside controller. Unfortunately I just can't seem to get it right.

Here is what my controller and factory look like:

angular.module('TeamApp.services',[])
.factory('espnAPIservice',function($http) {
        var espnAPI = {};
        espnAPI.getTeams = function() {
            return $http({
                method: 'GET',
                url: 'http://api.espn.com/v1/sports/hockey/nhl/teams?'
            })
        }
        return espnAPI;
    });

//Calls the espnAPIservice and stores the retrieved information in an array
angular.module('TeamApp.controllers',[])
.controller('TeamCtrl', ['$scope','espnAPIservice',function($scope,espnAPIservice) {
        $scope.teams = [];

        espnAPIservice.getTeams().success(function (response) {
            $scope.teams = response;
        });
    }]);

angular.module('TeamApp',['TeamApp.services','TeamApp.controllers']);

Here is my test for it so far:

describe('controller: TeamCtrl', function() {
    var $scope, ctrl;

    //Inject controller module into the factory that it the controller will call
    beforeEach(module('TeamApp.controllers', function($provide) {
        var espnAPIservice = {
            getTeams: function(){}
        };
        spyOn(espnAPIservice,'getTeams').andReturn('ESPN'); //change return value
        $provide.value('espnAPIservice',espnAPIservice);
    }));

    //Inject the $controller and $rootScope services
    beforeEach(inject(function($rootScope, $controller, espnAPIservice) {
        //Create a new scope that is the child of $rootScope
        $scope = $rootScope.$new();
        //Create the controller
        ctrl = $controller('TeamCtrl',{$scope: $scope, espnAPIservice: espnAPIservice});
    }));

    it('should call the getTeams function', function(){
        expect($scope.teams).toBe('ESPN');
    });

And here is the error I get when I run the test:

PhantomJS 1.9.7 (Windows 7) controller: TeamCtrl should call the getTeams function FAILED

TypeError: 'undefined' is not a function (evaluating 'espnAPIservice.getTeams().success(function (response) {
$scope.teams = response; })')

at c:/Users/jquering/Documents/Coding Practice/Angular Practice/nhlStats/app/scripts/teams.js:21
at invoke (c:/Users/jquering/Documents/Coding Practice/Angular Practice/nhlStats/app/lib/angular.js:3762)
at instantiate (c:/Users/jquering/Documents/Coding Practice/Angular Practice/nhlStats/app/lib/angular.js:3773)
at c:/Users/jquering/Documents/Coding Practice/Angular Practice/nhlStats/app/lib/angular.js:6884
at c:/Users/jquering/Documents/Coding Practice/Angular Practice/nhlStats/test/controllers/spec/main.js:18
at invoke (c:/Users/jquering/Documents/Coding Practice/Angular Practice/nhlStats/app/lib/angular.js:3762)
at workFn (c:/Users/jquering/Documents/Coding Practice/Angular Practice/nhlStats/app/lib/angular-mocks.js:2144)

undefined
Expected [ ] to be 'ESPN'.
PhantomJS 1.9.7 (Windows 7): Executed 1 of 1 (1 FAILED) ERROR (0.009 secs / 0.008 secs)

Any help would be much appreciated!

Community
  • 1
  • 1
Jerridan
  • 5
  • 4

1 Answers1

0

how to properly mock out a factory

beforeEach(module(function ($provide){
    $provide.factory('TheSameName', function (){
      //return your mock here
    });
}));
Stepan Suvorov
  • 25,118
  • 26
  • 108
  • 176
  • Alright that got rid of the TypeError, but now I'm getting "Error: [ng:areq] Argument 'TeamCtrl' is not a function, got undefined" in my second beforeEach statement. – Jerridan Jun 12 '14 at 23:09
  • could you please the question with full stack trace for this error? – Stepan Suvorov Jun 13 '14 at 07:28
  • Thanks @STEVER, in order to get your example to work I had to change my controller a bit. My line with "espnAPIservice.getTeams().success(function (response)" was causing problems, needed to just have "$scope.teams = espnAPIservice.getTeams();" It's working now! – Jerridan Jun 13 '14 at 17:52