awdyson
awdyson

Reputation: 363

How do I test a rejected Angular (1.6.1) promise in jasmine?

Below was my approach to testing rejected promises in angular 1.5.x. Updating to 1.6.1 has introduced the "Possibly unhandled rejection" error. I understand the purpose of this error, but I haven't figure out a simple way around it. Jasmine's (2.5.x) and.throwError() method seems to cause tests to fail by virtue of being an error.

describe('TestTarget', () => {
    let $q, $rootScope, TestTarget, SomeModel;

    beforeEach(() => {
        SomeModel = jasmine.createSpyObj('SomeModel', ['get']);

        module('something');
        module($provide => {
            $provide.value('SomeModel', SomeModel);
        });

        inject((_$q_, _$rootScope_, _TestTarget_) => {
            $q = _$q_;
            $rootScope = _$rootScope_;
            TestTarget = _TestTarget_;
        });
    });

    describe('get()', () => {
        it('on error, adds a danger message', () => {
            SomeModel.get.and.returnValue($q.reject());
            // SomeModel.get.and.throwError(); // doesn't work either
            TestTarget.get();
            $rootScope.$digest();
            expect(SomeModel.get).toHaveBeenCalled();
            expect(<< the rejection outcome of TestTarget.get().then() >>);
        });
    });
});

I want to continue to pass rejected promises across my models, services, and controllers.

Upvotes: 2

Views: 2327

Answers (2)

Sreekanth
Sreekanth

Reputation: 533

I had this issue with angular 1.6.1. Try callFake instead of returnValue in your test.

describe('TestTarget', () => {
let $q, $rootScope, TestTarget, SomeModel;

beforeEach(() => {
    SomeModel = jasmine.createSpyObj('SomeModel', ['get']);

    module('something');
    module($provide => {
        $provide.value('SomeModel', SomeModel);
    });

    inject((_$q_, _$rootScope_, _TestTarget_) => {
        $q = _$q_;
        $rootScope = _$rootScope_;
        TestTarget = _TestTarget_;
    });
});

describe('get()', () => {
    it('on error, adds a danger message', () => {
        SomeModel.get.and.callFake(() => $q.reject());
        // SomeModel.get.and.throwError(); // doesn't work either
        TestTarget.get();
        $rootScope.$digest();
        expect(SomeModel.get).toHaveBeenCalled();
        expect(<< the rejection outcome of TestTarget.get().then() >>);
    });
});

});

Upvotes: 0

Ali Motevallian
Ali Motevallian

Reputation: 1380

Let us say your actual code is like this:

angular.module('myApp').service('TestTarget', ['SomeModel', function(SomeModel) {
    this.get = function() {
        return SomeModel.get();
    }
}]);

My assumption is you have no .catch block chained to the returning Promise. In this case you can simply test it like this:

it('on error, adds a danger message', () => {
    SomeModel.get.and.returnValue($q.reject('some error'));
    TestTarget.get()
        .then(function() {
            fail('the promise should not have been resolved');
        }).catch(function(err) {
            expect(err).toBe('some error');
        });
    $rootScope.$digest();
    expect(SomeModel.get).toHaveBeenCalled();
});

Notice that I add a catch block to my function call. The $rootScope.$digest() makes sure that the promise is resolved and all its chained then and catch blocks are getting called.

Upvotes: 3

Related Questions