Reputation: 1319
I have the following code:
$scope.deleteJob = function(job) {
SandboxService.deleteJob(job.id).then(res => {
if (res.status == 200) {
ngToast.success();
$scope.refreshApps();
}
else {
ngToast.danger();
}
});
};
And the following unit test:
it('should show success toast on delete and refresh apps', () => {
spyOn(sandboxService, 'deleteJob').and.returnValue(Promise.resolve({status: 500}));
spyOn(ngToast, 'success');
spyOn(scope, 'refreshApps');
let mockJob = {
'id': 1
};
scope.deleteJob(mockJob);
sandboxService.deleteJob().then(() => {
expect(ngToast.success).toHaveBeenCalled();
expect(scope.refreshApps).toHaveBeenCalled();
});
});
Basically when deleting a job, if the delete was a success with a returned status of 200 then show a success toast and refresh, else show a danger toast.
I expect the test to fail, as it returns a status of 500, but it passes. This implies that ngToast.success()
and scope.refreshApps()
have been called.
I added some logs to the code, and it does return status: 500
and go to the else
block.
What am I missing here?
Upvotes: 0
Views: 255
Reputation: 1319
@uminder's answer pointed out that the test was finishing before the expect
functions were even called due the asynchronous nature - verified by adding some logs inside the test.
The solution was to add an argument to the test that is to be called when the test has finished: https://jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support
it('should show success toast on delete and refresh apps', (done) => {
spyOn(sandboxService, 'deleteJob').and.returnValue(Promise.resolve({status: 200}));
spyOn(ngToast, 'success');
spyOn(scope, 'refreshApps');
let mockJob = {
'id': 1
};
scope.deleteJob(mockJob);
sandboxService.deleteJob().then(() => {
expect(ngToast.success).toHaveBeenCalled();
expect(scope.refreshApps).toHaveBeenCalled();
done();
});
});
Upvotes: 0
Reputation: 26190
The problem is related to the asynchronous nature of deleteJob
. Your it
test ends even before expect
is performed. Therefore you need some sort of synchronization. This could basically be done with fakeAsync
and tick
from @angular/core/testing
.
it('should show success toast on delete and refresh apps', fakeAsync(() => {
...
sandboxService.deleteJob();
tick();
expect(ngToast.success).toHaveBeenCalled();
expect(scope.refreshApps).toHaveBeenCalled();
}));
The problem however is that you're overwriting the original behaviour of deleteJob
with the spy below, hence ngToast.success
and scope.refreshApps
won't be called and the test will fail.
spyOn(sandboxService, 'deleteJob').and.returnValue(Promise.resolve({status: 500}));
Upvotes: 1