Prime By Design Prime By Design - 6 months ago 17
Javascript Question

Mocked service returning Object ($$state) error

I have been following the angular testing Play by Play on PluralSight by John Papa and Ward Bell.

I'm currently getting the following error when I run my specs.

AssertionError: expected { Object ($$state) } to have a property 'length'
at Assertion.assertLength (bower_components/chai/chai.js:1331:37)
at Assertion.assert (bower_components/chai/chai.js:4121:49)
at Context.<anonymous> (scripts/home/homeController.Specs.js:48:49)


Note that I have only included the code that I think is relevant so that I am not overloading this question with irrelevant information. If you need to see more code it's not a problem.

My code is as follows:

homeController.js:

window.app.controller('homeController', ['$scope', 'sidebarService',
function ($scope, sidebarService) {

$scope.title = 'Slapdash';
$scope.sidebar = {
"items": sidebarService.getSidebarItems()
};

}])


sidebarService.js:

(function () {
window.app

.service('sidebarService',['$http', function ($http) {

this.getSidebarItems = function () {
$http.get("http://wwww.something.com/getSidebarItems")
.then(function (response) {
return response.data;
});
};
}]);
}());


homeController.Specs.js:

beforeEach:

beforeEach(function () {

bard.appModule('slapdash');

bard.inject(this, '$controller', '$q', '$rootScope')

var mockSidebarService = {
getSidebarItems : function(){
return $q.when(mockSidebarMenuItems);
}
};

controller = $controller('homeController', {
$scope: scope,
sidebarService: mockSidebarService
});

});


failing spec:

it('Should have items', function () {
$rootScope.$apply();

expect(scope.sidebar.items).to.have.length(mockSidebarMenuItems.length); // same number as mocked
expect(sidebarService.getSidebarItems).to.have.been.calledOnce; // it's a spy

});

Answer

The answer was that I was returning a result from the service not a promise.

    $http.get("http://wwww.something.com/getSidebarItems")
        .then(function (response) {
            return response.data; // <- returning data not promise
        });

When I was mocking I was using

var mockSidebarService = {
    getSidebarItems : function(){
        return $q.when(mockSidebarMenuItems);
    }
};

which mocks a promise. However I just needed to return the data as the promise was awaited in the service.

       mockSidebarService = {
           getMenuItems : function(){
               return mockSidebarMenuItems
           }
       };

I made the changes and it all works now. Took a while but at least it's making sense.