I have recently updated my application from Angular 1.5 to 1.6.3 and started getting Jasmine unit test failures (with PhantomJS) around promise based code I have written:
Possibly unhandled rejection: undefined thrown
Reading around I see that the accepted solution is to chain .then() with .catch() blocks to handle the rejections gracefully.
I have done this for one of my source files that I am testing to prove this gets past the error which it does.
However, it has now uncovered a further issue where an expectation I am testing when a promise rejection is called in my code is no longer passing.
This is the function I am trying to test (after adding the required catch blocks)
public deleteSomething = (thing) => {
return this.UserMessages.buildConfirmDialog().then(() => {
this.someService.remove(thing)
.then(() => {
this.UserMessages.showToast('Something deleted');
})
.catch((error) => {
//handle error
});
})
.catch((error) => {
//handle error
});
}
And here is the test:
var thing = {foo: 'bar'},
deferredRemove,
deferredConfirm,
//Mock service below injected into controller later on before test are run
UserMessages = {
buildConfirmDialog: jasmine.createSpy('buildConfirmDialog').and.callFake(function() {
deferredConfirm = $q.defer();
return deferredConfirm.promise.catch(angular.noop);
})
};
//Inject and controller setup here...
describe('When deleting something', function() {
beforeEach(function() {
deferredRemove = $q.defer();
spyOn(someService, 'remove').and.returnValue(deferredRemove.promise.catch(angular.noop));
});
describe('and the user confirms the deletion', function() {
beforeEach(function() {
ctrl.deleteSomething(thing);
deferredConfirm.resolve();
deferredRemove.resolve();
$rootScope.$apply();
});
it('should call remove on someService', function() {
console.log('someService.remove.calls = ' + someService.remove.calls.count());
expect(someService.remove).toHaveBeenCalled();
});
});
describe('and the user cancels the deletion', function() {
beforeEach(function() {
someService.remove.calls.reset();
vm.deleteSomething(thing);
deferredConfirm.reject({});
$rootScope.$apply();
});
it('should not call remove on someService', function() {
console.log('someService.remove.calls = ' + someService.remove.calls.count());
expect(someService.remove.calls.count()).toEqual(0);
});
});
});
I didnt have the .catch(angular.noop)
parts in prior to upgrading to 1.6.3 and came across some posts suggesting to do this in order to make the tests happy, which certainly helped for me in getting past the unhandled rejection error in my test run.
The problem I am now facing is that for the reject test spec, there should be no call made to a remove function in my service, and so the number of calls should be zero, but it keeps coming out as 1. I added the line to reset the calls in my test to be sure it wasnt the previous test contributing (I know calls are meant to be reset between tests).
This test was running just fine when I was on 1.5, so this has to be something with the way my code\test is written not playing nicely with changes in 1.6.x
Can someone shed some light on what may be going on here please?
Thanks