noobcoder noobcoder - 5 months ago 134
Javascript Question

AngularJS TypeError: 'undefined' is not an object' Jasmine test

I am getting the above error on running Jasmine tests when mocking/spying an API call in my tests. Here is my code that calls the API:

UploadedReleasesController.$inject = ['$log', '$scope', '$filter', '$modal', 'ReleaseService', 'TrackService', 'APP_CONFIG', 'DeliveriesService'];
function UploadedReleasesController ($log, $scope, $filter, $modal, releaseService, trackService, APP_CONFIG, deliveriesService){
.
.
.
releaseService.releases(vm.currentWorkspace).then(function (responseValues) {
vm.albums = responseValues;
if(vm.albums.length !== 0){
vm.selected.album = vm.albums[0];


where
releaseService
is my defined service and
releases
is one of its method that I want to spy on. It takes a string argument let's say
'HIGH'
. Here is my test file where I want to mock that call:

describe('app module', function() {
var vm, scope, modalInstance, releaseService, trackService, deliveriesService;

beforeEach(module('app.uploadedReleases')); // Main module name

beforeEach(module('app.config'));
beforeEach(module('auth'));

beforeEach(function() {
var mockReleasesData = {
"test" : 100
}
};

releaseService = jasmine.createSpyObj("releaseService", ["releases"]);
releaseService.releases('HIGH').and.returnValue(mockReleasesData);
});


beforeEach(inject(function($controller, $log, $rootScope, $filter, APP_CONFIG) {

scope = $rootScope.$new();

modalInstance = {
close: jasmine.createSpy('modalInstance.close'),
open: jasmine.createSpy('modalInstance.open'),
dismiss: jasmine.createSpy('modalInstance.dismiss'),
result: {
then: jasmine.createSpy('modalInstance.result.then')
}
};

vm = $controller('UploadedReleasesController', {'APP_CONFIG':APP_CONFIG, '$log':$log, '$scope':scope, '$filter':$filter, '$modal':modalInstance,
'ReleaseService':releaseService, 'TrackService':trackService, 'DeliveriesService':deliveriesService});

}));


Upon running the test, I get the error:


TypeError: 'undefined' is not an object (evaluating 'releaseService.releases('HIGH').and')
at test-release.controller.spec.js:93
TypeError: 'undefined' is not an object (evaluating 'releaseService.releases(vm.currentWorkspace).then')
undefined


Here is the actual releaseService from
release.service.js


releaseService.releases = getReleases;
.
.
.
function getReleases(workspace){
var releases = [];
headers.Workspace = workspace; // set the workspace
var deferred = $q.defer();
// Then make $http calls and return a promise
.
.

Answer

I see a couple things that may be issues:

  1. Calling the release method:

releaseService.releases('HIGH').and.returnValue(mockReleasesData);

releases method is being called here, if a return value should be set here then I think the syntax may be:

releaseService.releases.and.returnValue(mockReleasesData);

Then you can assert on releases being called with the correct data.

  1. After the above is resolved. The mockReleaseData doesn't have a then method. Since it is being returend from releases its then method will be called:

releaseService.releases(vm.currentWorkspace).then(function (responseValues)

   var mockReleasesData = {
        "test" : 100
        },
        then: function(callbackFn) {  
          // could call callbackFn with fake responseValues
        }
    };

What is the intention of the test? Is it to exercise the then anonymous function? With a small amount of restructuring to expose your logic it could be trivial to test.

function handleResponseValues(vm, responseValues) {
            vm.albums = responseValues;
            if(vm.albums.length !== 0){
                vm.selected.album = vm.albums[0];
}

This would still require that the then callback call handleResponseValues with a reference to vm, and responseValues but would expose all the logic independent of the promise chain.

Comments