0

Currently i got stuck in writing a unit test for my angular controller. I have a $scope Function which makes an ajax request and after resolving all promises it assigns the fetched data to $scope.products. But it does not work for me and i don't know what i'm doing wrong here!

controller

$scope.products = [];

// $q.all is used because i've some other data sources too
$scope.query = function (term) {
    $q.all([
        DataService.autocomplete.products(term)

    ]).then(function (results) {
        $scope.products = results[0].data.content;
    });
};

Dataservice

// dataservice return value
return {
    autocomplete: {
        products: function (term) {
            // _makeRequest is a wrapper for a $http call
            return _makeRequest('autocomplete/products', term);
        }
    }
}

Unit-Test

describe('[Autocomplete] AutocompleteCtrl', function () {
    var $scope, DataService;

    beforeEach(module('Autocompleter'));

    beforeEach(inject(function ($rootScope, $controller, _$q_, _DataService_) {

        var deferred = _$q_.defer();
        $scope = $rootScope.$new();
        DataService = _DataService_;

        $controller('AutocompleteCtrl', {$scope: $scope});
        deferred.resolve(['resolveData']);
        spyOn(DataService.autocomplete, 'products').and.returnValue(deferred.promise);
    }));


    describe('Query', function () {

        it('should resolve promise', function () {
            $scope.query('term');
            $scope.$apply();
            expect($scope.products).toBe(['resolveData']);
        });

    });
});

Test-Result

TypeError: 'undefined' is not an object (evaluating 'results[0].data.content')

2 Answers 2

1

Your controller expects the DataService.autocomplete.products() function to return a promise, and expects this promise to be resolved with an object which has a data attribute, since you're doing:

results[0].data.content

In your test, you resolve the fake promise with the following value:

['resolveData']

So, instead of getting an object looking like

{
    data: 
    {
        content: 'someValue'
    }
}

the controller receives ['resolveData'].

Obviously, accessing the data attribute of ['resolveData'] will lead to an undefined value.

Sign up to request clarification or add additional context in comments.

2 Comments

OP already state that he use $q.all() because there're some other data sources too.
Fair enough. I missed it. I'll remove this part from my answer.
1

You are expecting .data.content from the result of DataService.autocomplete.products().

Therefore, you should change your mock data from:

deferred.resolve(['resolveData']);

to this instead:

deferred.resolve({ data: { content: ['resolveData'] } });

Hope this helps.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.