问题
I'm having an argument with a co-worker about done()
in Jest tests.
He's orders of magnitude more experienced with JavaScript than I am, and I came in after async
/await
was generally accepted, plus came from a .NET environment, so I was used to it.
I write my tests like this:
it("should return 200 OK for POST method", async () => {
await request(app).post("SOMEENDPOINT")
.attach("file", "file")
.expect(200);
});
He's more used to promises so will write his tests like this:
it("should return 200 OK for POST method", (done) => {
request(app).post("SOMEENDPOINT")
.attach("file", "file")
.expect(200, done);
});
He's fine with my push to async
/await
, but insists I have to include done
, such that I'm either doing his version modified version:
it("should return 200 OK for POST method", async (done) => {
await request(app).post("SOMEENDPOINT")
.attach("file", "file")
.expect(200, done);
});
Or:
it("should return 200 OK for POST method", async (done) => {
const res = await request(app).post("SOMEENDPOINT")
.attach("file", "file");
expect(res.status).toBe(200);
done();
});
While I recognize calling done()
is entirely necessary when it's included as a parameter, I was under the impression it is wholly unnecessary when using async
/await
in this context.
Request is supertest.request
.
My question is, do I need to use done
at all with async
/await
?
回答1:
There's never a need for done
and async
on the same test function. Pick one or the other, or, in this case, return the promise directly:
it("should return 200 OK for POST method", () =>
request(app).post("SOMEENDPOINT")
.attach("file", "file")
.expect(200)
);
Jest will await
any returned promise which means we can always manually construct and return a promise without async
or done
. This is redundant since we already have a promise at hand, but the following pattern is possible, if only for illustrative purposes:
it("should return 200 OK for POST method", () => {
return new Promise((resolve, reject) => {
request(app).post("SOMEENDPOINT")
.attach("file", "file")
.expect(200, resolve)
.catch(err => reject(err))
;
});
});
done
is typically used for testing asynchronous callbacks (think basic Node library utilities in the fs
module). In these cases, it's more elegant to add the done
parameter and invoke it in the callback than it is to promisify the callback by hand. Essentially, done
is a shortcut to promisification that abstracts out the new Promise
boilerplate shown above.
Note that done
can accept a parameter which is treated as an error (see the docs). This should go into any catch
blocks to avoid a timeout and confusing error when the main line code throws before calling done
:
it("should return 200 OK for POST method", done => {
request(app).post("SOMEENDPOINT")
.attach("file", "file")
.expect(200, done)
.catch(err => done(err))
;
});
来源:https://stackoverflow.com/questions/58713379/is-done-required-in-async-jest-tests