Description
Support plan
- Which support plan is this issue covered by? (Community, Sponsor, Enterprise): Community
- Currently blocking your project/work? (yes/no): no
- Affecting a production system? (yes/no): no
Context
- Node.js version:
18.18.2
- Release Line of Formidable (Legacy, Current, Next):
next
- Formidable exact version:
v3.5.1
- Environment (node, browser, native, OS): Node 18.18.2, Linux (though likely all runtimes are affected)
- Used with (popular names of modules):
node-mocks-https
,form-data
Note this issue appears to only be present in tests as it is dependent on how promises get queued, but it could lead to a bug in live code.
What are you trying to achieve or the steps to reproduce?
A (somewhat) minimal reproducible test.
import FormData from "form-data";
import formidable from "formidable";
import { createMocks } from "node-mocks-http";
test("Can parse files from node-mocks-http", async () => {
let formData = new FormData();
formData.append("file", "File data", "data.txt");
const getLengthAsync: () => Promise<number> = async () => {
return new Promise((res, rej) => {
formData.getLength((err, length) => {
if (err) {
rej(err);
} else {
res(length);
}
});
});
};
const { req, res } = createMocks({
headers: {
'content-type': `multipart/form-data;boundary="${formData.getBoundary()}"`,
'content-length': (await getLengthAsync()).toString(),
},
});
let form = formidable({});
let promise = form.parse(req);
req.send(formData.getBuffer());
let [fields, files] = await promise;
console.log({fields, files});
})
What was the result you got?
The test times out at 5000ms because the await form.parse(req)
never resolves.
What result did you expect?
The test passes.
Cause
The issue is caused as the callback handlers are set after an await of a promise.
Line 232 in 1699ec6
This means the function returns, then data is sent which formidable is not listening for, then the await
within parse
is resolved and the handlers are set, but the events have already been missed, so the handlers just do nothing until Jest stops the test.
Workaround
It's possible to call req.send
in a promise with a slight delay, e.g.
let promiseParse = form.parse(req);
let promiseSend = new Promise((resolve, reject) => {
setTimeout(() => {
req.send(formData.getBuffer());
resolve(undefined);
}, 50)
}
Promise.all([promiseParse, promiseSend]);
Breaking change
This is also a breaking change as it seems to have been introduced since v3.2.4
. While the Promise style of parse
didn't exist in that version, this bug also affects the callback style in the same manor.