I want to upload a file to endpoint with PUT request using Jest + Supertest.
I have following request constructor:
export async function uploadFileForJob(
uploadUrl: string,
accessToken: string,
filePath: string
) {
const upload_file_for_job = await request(uploadUrl)
.put("")
.set("Authorization", `Bearer ${accessToken}`)
.set("Content-Type", "model/gltf-binary")
.attach('file', filePath)
return upload_file_for_job;
}
and the request in test file itself:
const UploadFileForJob = await uploadFileForJob(
uploadUrl,
accessToken,
'C:/Job/Simulations/TestTshirt_04.glb'
);
expect(UploadFileForJob.status).toEqual(200);
The endpoint always returns 200 to me and has no body in response, so I have another way of checking if file was actually correctly uploaded:
export async function getJobView(jobId: string, accessToken: string) {
const get_job_view = await request(`https://${config.url}`)
.get(`/products-v0/_objects/${jobId}/Views/File`)
.set("Authorization", `Bearer ${accessToken}`)
.send();
return get_job_view;
}
const GetJobView = await getJobView(jobId, accessToken);
expect(GetJobView.status).toEqual(200);
expect(GetJobView.body.view).toBeTruthy();
and here I already get 404 error which indicates that file wasn't correctly accepted by previous endpoint. I am sure that the error lies in a way how jest takes the route which I point to it and there are no errors in any variables, if I use all the same with Postman (using binary body file selector) everything works perfectly. What should be the way of writing this .attach in a correct way?
Finally solution is found. There were two problems. First was that uploading of a file takes some time, so next request should be sent after uploading of the file is finished, for it I used do...while loop with some retries checking that file is finally attached.
// Wait for the file to be attached to the job
let JobViewResponse;
const maxRetries = 20; // Number of retries before giving up
let retries = 0;
do {
// Introduce a small delay between each retry (e.g., 2 seconds)
await sleep(2000);
JobViewResponse = await getJobView(jobId, accessToken);
retries++;
} while (JobViewResponse.status !== 200 && retries < maxRetries);
// Check if the file is attached to the job
if (JobViewResponse.status === 200 && JobViewResponse.body.view) {
const viewData = JSON.parse(JobViewResponse.body.view);
expect(JobViewResponse.status).toEqual(200);
expect(JobViewResponse.body.view).toBeTruthy();
expect(viewData.Size).toBeGreaterThan(0);
console.log("File is attached to the job.");
} else {
console.error("File attachment to the job failed or took too long.");
}
Second problem was that attach() tries to send the file as multipart form data. But in our case, the request body should only contain the raw bytes. To solve it, I used fs.readFileSync to read the file in memory first.
export async function uploadFileForJob(
uploadUrl: string,
accessToken: string,
filePath: string
) {
const fileContents = fs.readFileSync(filePath);
const upload_file_for_job = await request(uploadUrl)
.put("")
.set("Authorization", `Bearer ${accessToken}`)
.set("Content-Type", "model/gltf-binary")
.send(fileContents);
return upload_file_for_job;
}