steveareeno
steveareeno

Reputation: 1977

jasmine - TypeError: Unable to get property 'catch' of undefined or null reference

I am trying to create a unit test for a service call in my method. The unit test returns the following error:

TypeError: Unable to get property 'catch' of undefined or null reference

Controller method I am testing:

$scope.getAsset = function (id) {
    if ($scope.id != '0') {
        assetFactory.getAsset($scope.id)
        .then(function (response) {
            $scope.asset = response.data;
        })
        .catch(function (error) {
            alertService.add('danger', 'Unable to load asset data: ' + error.statusText + '(' + error.status + '). Please report this error to the application administrator');
        });
    }
};

My unit test is as follows:

it('method getAsset() was called', function () {
    var asset = { AssetId: 'TEST123' };
    var spy = spyOn(assetFactory, 'getAsset').and.callFake(function () {
        return {
            then: function (callback) {
                return callback(asset);
            }
        };
    });
    // call the controller method
    var result = scope.getAsset();
    // assert that it called the service method. must use a spy
    expect(spy).toHaveBeenCalled();
});

When I remove the ".catch(function (error)" statement from my controller method, the test passes. It appears I have to implement the catch in my spy but I can't figure out how.

Upvotes: 4

Views: 4224

Answers (2)

Sibeesh Venu
Sibeesh Venu

Reputation: 21829

I also had this problem, but the above solution couldn't help. My problem was a bit different. I was using a mock as preceding.

jasmine.createSpy('mockFunc()').and.callFake()

Then I changed it to as below with a call back function.

jasmine.createSpy('mockFunc()').and.callFake(function() { })

I know it sounds crazy, but this solved my issue. You can also give a try if you had done the same mistake.

Upvotes: 0

fracz
fracz

Reputation: 21278

The then and catch methods comes from the promise pattern which is implemented in AngularJS by the $q service.

Your mocked (faked) method should also return a promise. The easiest way is to use $q.when(value). It creates promise which immediately resolves to given value.

Try:

var response = {data: asset};
var spy = spyOn(assetFactory, 'getAsset').and.returnValue($q.when(response));

Of course, you need to inject $q in your tests.

It's also worth to read How to unit-test promise-based code in Angular.

Upvotes: 3

Related Questions