ItsJustMe
ItsJustMe

Reputation: 125

Karma+Jasmine function that reads a json file always fails

I'm having a hard time understanding how unit testing with Karma+Jasmine works exactly

I'm trying to setup some Unit Tests for my AngularJS app but I'm running into a problem where the Tests don't seem to run a function properly.

I have a function that reads a json file through a $http.get request and populates an array, but when I set up in my unit test to expect the length of the array expect(array.length).toBe(10), it always fails, yet that is the length of the array when I run the App normally. Actually if I print the length in the console.log on the unit test it seems to always be stuck at 1.

But for example if I check some of the variables I declare manually then the expect function works properly.

Can anyone tell me what exactly am I missing here? It's seems i'm missing some of the fundamentals on how unit testing with Karma/Jasmine works.

Any help would be greatly appreciated. Thanks!

Upvotes: 0

Views: 425

Answers (2)

georgeawg
georgeawg

Reputation: 48948

ERRONEOUS

$scope.getAllApps = function(){
    $scope.isLoading = true;
    $http.get('../json/apps.json').then(function (data){
        // ...
    });
    $scope.isLoading = false;
};

BETTER

$scope.getAllApps = function(){
    $scope.isLoading = true;
    $http.get('../json/apps.json').then(function (data){
        // ...
    }).finally(function() {
        $scope.isLoading = false;
    });
};

Because the $http service in non-blocking and asynchronous, it immediately returns a promise. It does not wait for data to return from the server. The isLoading flag needs to wait for the promise to resolve before setting the flag false.

Upvotes: 1

cody mikol
cody mikol

Reputation: 843

Your problem is that $http.get is an asynchronous method. Unless you sepcifically tell angularjs that it needs to flush that response, it will not. The method will exit and the callback of $http.get will not happen in time for your it method to utilize its $scope transformations.

You can achieve this by expecting the call to happen with the $httpBackend API https://docs.angularjs.org/api/ngMockE2E/service/$httpBackend

You can then do

$httpBackend.expectGET('../json/apps.json').respond(200, {mock: 'api response');
$scope.getAllApps();
$httpBackend.flush();
expect(scope.allApps.length).toBe(10);

In your unit tests you should never rely on the actual response of http calls. To ensure you are testing only the method you should always mock the response of what your API is supposed to return.

Upvotes: 1

Related Questions