I've got an API built in Express, which I'm testing with Jest. The API is working just fine when I test with Postman, but when I run my test suite I usually get an ECONNABORTED error on my file uploads using .attach(). (Occasionally, it works just fine.) I'm using a suite of middleware to download an array of images referenced by URL, followed by any images passed to the endpoint via form upload. After the images are saved, I'm using a third piece of middleware to resize the images and save them in a subdirectory. Since the error only happens in Jest, it seems like that's where the error would lie, but I'm also not positive I'm handling errors with Multer correctly.
// endpoint.js
const storage = multer.diskStorage({
destination: async (req, file, cb) => {
// Check for product's existence
if (product) {
// Make the directory if necessary
cb(null, /* location */)
} else {
cb(404, null)
}
},
filename: async (req, file, cb) => {
cb(
null, /* location */}`
)
}
})
const upload = multer({ storage }).array("files")
router.post(
"/:id",
async (req, res, next) => {
// Download images from URLs if provided
next()
},
(req, res, next) => {
upload(req, res, err => {
// Handle errors (e.g. return res.status(404).json({ message: "Product not found" })
})
next()
},
async (req, res) => {
// resize and save to subdirectory
}
)
// endpoint.test.js
describe("/endpoint", () => {
describe("POST", () => {
it("saves uploaded images to the server", async () => {
const response = await request(app)
.post(`/endpoint/${id}`)
.attach("files", "assets/img-test-1.jpg")
.attach("files", "assets/img-test-2.jpg")
.set("Content-Type", "multipart/form-data")
expect(response.status).toEqual(201)
}, 30000)
...
})
EDIT: The original error was fixed by moving the next()
call into the Multer handler. However, now the same error is occurring, just on a different test. Again, the error occurs only when running by test scripts; I haven't had any issues when making an identical call via Postman.
// endpoint.js
let errors
router.post(
"/:id",
async (req, res, next) => {
errors = []
...
// This is the problematic call. If I explicitly set
// product = null, the test runs normally
const product = await Product.findById(req.params.id)
if (!product) {
errors.push({ status: 404, message: "Product not found" })
return next()
}
...
return next()
},
// Several more middleware functions
})
// endpoint.test.js
...
beforeAll(done => {
app.on("ready", async () => {
const newProduct = await Product.create(product)
id = newProduct._id
done()
})
})
...
describe("/api/bam/images", () => {
describe("POST", () => {
...
it("returns a 404 error if the associated product is not found", async () => {
const response = await request(app)
.post("/api/bam/images/000000000000000000000000")
.attach("files", "assets/img-test-1.jpg")
.attach("files", "assets/img-test-2.jpg")
expect(response.status).toEqual(404)
})
})
})
I think the problem might just be related to calling next()
before multer is done uploading - try moving next inside the upload callback:
(req, res, next) => {
upload(req, res, err => {
// Handle errors (e.g. return res.status(404).json({ message: "Product not found"
next()
})
})
},
PT2: Related to the edit, if it seems that the problem is related to that await
call then there might be an error being thrown and not caught - when you await a rejected promise it behaves like a normal throw. Throwing here would mean next
never gets called:
// This is the problematic call. If I explicitly set
// product = null, the test runs normally
try {
const product = await Product.findById(req.params.id)
if (!product) {
errors.push({ status: 404, message: "Product not found" })
return next()
}
} catch (err) {
return next(err)
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.