Reputation: 18857
I have the following class:
import * as request from "request-promise-native";
export class publisher {
publish(file : string) : PublisherResponse{
let response = PublisherResponse.EmptyResponse;
let options = {};
let promise = this.executeRequest(file , options);
promise.then( value => response = value );
return response;
}
async executeRequest(file : string, options : any ) : Promise<PublisherResponse>{
let promise = await request.get("http://someAPI", options);
console.debug("we need to wait for this thing to finish ...")
let response = await promise;
let data = response.data;
return new new PublisherResponse(file, data);
}
}
The Jest test is as follows:
test('Should publish a valid single document', async () => {
// Arrange
var documentToPublish = "file1.oas3";
let sut = new publisher();
let expectedResponse = new PublisherResponse(documentToPublish, "some-data");
// Act
let actualResponse = sut.publish(documentToPublish);
// Assert
expect(actualResponse).toEqual(expectedResponse);
});
The test fails because execution does not appear to stop in the async method executeRequest until the awaitable lines have been completed.
What I end up getting is an error indicating that
Cannot log after tests are done. Did you forget to wait for something async in your test? Attempted to log "we need to wait for this thing to finish ...".
I'll prefer not to make the publish API return a promise for now if I can get away with this. Any ideas on what I could be missing here?
Upvotes: 1
Views: 478
Reputation: 141542
The test fails because execution does not appear to stop in the
async
methodexecuteRequest
until the awaitable lines have been completed.
You are absolutely right. Execution does not stop in the async
method; instead, execution returns to the caller until the Promise completes. Here is what happens:
jest
calls publish
publish
calls executeRequest
executeRequest
calls await request.get...
executeRequest
returns control to publish
publish
returns control to jest
jest
runs its expectationawait request.get...
returnsexecuteRequest
calls console.log...
This is the way async
/await
(and Promise
/then
) works.
I'll prefer not to make the publish API return a promise for now if I can get away with this. Any ideas on what I could be missing here?
My suggestion: don't try to get away with calling an async function from a synchronous function. Instead, have publish
return a Promise
. Any code that wants publish
to be fire-and-forget can choose not to wait for the Promise
.
That would change your code to something like this:
export class publisher {
async publish(file: string): Promise<PublisherResponse> {
let response = PublisherResponse.EmptyResponse;
let options = {};
let promise = this.executeRequest(file , options);
await promise.then(value => response = value); // return control to caller
return response;
}
async executeRequest(file: string, options: any): Promise<PublisherResponse> {
let promise = request.get("http://someAPI", options);
console.debug("we need to wait for this thing to finish ...")
let response = await promise; // return control to caller
let data = response.data;
return new new PublisherResponse(file, data);
}
}
test('Should publish a valid single document', async () => {
// Arrange
var documentToPublish = "file1.oas3";
let sut = new publisher();
let expectedResponse = new PublisherResponse(documentToPublish, "some-data");
// Act (return control to caller)
let actualResponse = await sut.publish(documentToPublish);
// Assert
expect(actualResponse).toEqual(expectedResponse);
});
Upvotes: 1