问题
I have previously successfully tested an angular controller that uses ES7 async/await syntax with jasmine -
async updateGridAsync() {
const paging = angular.copy(this.gridData.getServerCallObj());
}
try {
const model = await this.service.getAsync(paging);
this._$rootScope.$apply();
} catch (e){this._notification.error(this._$rootScope.lang.notifications.unexpectedError);
}
}
it('updateGridAsync() should update the gridData when succeed', async (done) => {
expect(ctrl.gridData.totalItems).toEqual(2);
expect(ctrl.gridData.items.length).toEqual(2);
spyOn(service, 'getAsync').and.callFake(() => {
return Promise.resolve(responseStub);
});
await ctrl.updateGridAsync();
expect(service.getAsync).toHaveBeenCalled();
expect(ctrl.gridData.totalItems).toEqual(1);
expect(ctrl.gridData.items.length).toEqual(1);
done();
});
The above code works perfectly. However, I encountered a problem once trying to test the mocked service code, that calls $http.post. This is the code I run in the service:
async getAsync(pagingData, spinner, gridId, payeeId){
const response = await $http.post(url, params);
const model = this.modelFactory(response.data);
return model ;
}
and the test method that isn't able to go a step after the await in updateGridService:
it('getAsync should return correct model', async (done) => {
$httpBackend.whenPOST(theUrl).respond(200, responseStub);
const model = await service.getAsync();
expect(model.list.length).toEqual(2);
$httpBackend.flush();
done();
});
A few things to point out -
- Before using async await, this test passed. Now, I don't get passed the await in the service.
- The functionality works when not in testing context.
- I'm using jasmine 2.4.1 and angularJS 1.6
回答1:
I don't think you can use those together - await is actually waiting till the backend promise resolves and that is triggered by flush, but also triggering it before any request has been made does no good.
I mean if you wanna use it in a straightforward way, I personally use it with a helper that creates timeout for the flush action and then awaits for the request.
export async function withHttp(
callbackHttp: (http: HttpTestingController) => void,
callbackTest: () => Promise<void>
): Promise<void> {
const http = TestBed.get(HttpTestingController);
setTimeout(() => callbackHttp(http));
await callbackTest();
}
Also don't use async test methods together with done (and don't use done when it's just called on the last line of test, it's not needed then).
回答2:
Just ran into the same issue and I think there's no solution for it. Maybe upgrading to Angular 7 helps, hopefully the problem is fixed there. But that's not a quick solution.
Awaiting the asynchronous method that does the HTTP calls leads to a deadlock, because the HTTP calls don't return until $httpBackend.flush()
is called.
Not awaiting the asynchronous method does not help either. Then the assertions after $httpBackend.flush()
can fail because the framework does not wait long enough before continuing with assertions.
I really wonder how this "magic" is implemented. It seems that when the asynchronous method returns either void
or IPromise<void>
it works. Returning Promise<void>
(or using async
) does not work though.
来源:https://stackoverflow.com/questions/45606050/testing-angular-service-with-httpbackend-with-async-await-using-jasmin