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

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.