Jwqq Jwqq - 3 months ago 12
AngularJS Question

How to fix the unit test issue in my case?

I am trying to unit test two functions codes and keep getting error of undefined object.

my controller

vm = this;
//always fire first in the app
vm.getCompany = function() {
api.getCompany(function(res){
//do stuff
})
}

//always fire second in the app
vm.getEmployee = function() {
api.getEmployee(function(res){
//do stuff
})
}


api service

var company;

function getCompany() {
var company;
var q = $q.defer();
var url = ‘something.com’;

anotherApi.getCompany(url).then(function(comp){
company = comp;
q.resolve(company)
})
}

function getEmployee = function() {
var name = company.name
var url = ‘something.com/’ + name;
var q = $q.defer();
anotherApi.getEmployee(url).then(function(employee){
q.resolve(employee)
})
}


unit test.

beforeEach(function(){
module(‘myApp);
inject(function ($injector) {
$controller = $injector.get('$controller');
$rootScope = $injector.get('$rootScope');
$scope = $rootScope.$new();
$httpBackend = $injector.get('$httpBackend');
api = $injector.get('api');
});

vm = $controller'myCtrl', {
$scope : $scope
});

})

describe (‘test’, function(){
it(‘should get company’, function(){
vm.getCompany();
$httpBackend.flush();
// stuff and works
})
it(‘should get Employee’, function(){
vm.getEmployee()
$httpBackend.flush();
//getting error says
//'undefined' is not an object (evaluating 'company.name’)
})
})


I am getting
'undefined' is not an object (evaluating 'company.name’)

under
getEmployee
function in service.

I have tried many different ways but still not sure how to fix it, can someone help me about it? Thanks!

Answer

What is the expected behavior of the service if getEmployee is called before getCompany is called? You should at least check for company being null before attempting to use it. Also, you may want to consider storing the company in a property that you can access in your service. NOTE: I'm prefixing the property name with an underscore just to make a distinction between the public api and this pseudo-private property:

{
    _company: null,
    getCompany: function() {
        var self = this;
        var url = '...';
        return $http.get(url).then(function(comp){
            self._company = comp;
            return self._company;
        });
    },
    getEmployee: function() {
        var self = this;
        if (!self._company) {
            return null; //or throw error or return rejected promise: $q.reject('company is null')
        } else {
            var url = '...';
            var name = self._company.name;
            return http.get(url);
        }
    }
}

Lastly, you can (and should) test your service separately from your controller now. In your controller test, you can just spyOn your service methods without it calling through to the server. And when you test your service, you can just set the service._company to a mock value when testing the getEmployee method.

Comments