Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multipart form-data for API Post Request Issue #21173

Open
jenglishPS opened this issue Apr 22, 2022 · 19 comments
Open

Multipart form-data for API Post Request Issue #21173

jenglishPS opened this issue Apr 22, 2022 · 19 comments
Labels
E2E Issue related to end-to-end testing topic: cy.request Issues related to cy.request command Triaged Issue has been routed to backlog. This is not a commitment to have it prioritized by the team.

Comments

@jenglishPS
Copy link

jenglishPS commented Apr 22, 2022

Current behavior

I've tried many different formats/variations to post an API request which includes a multipart form-data request and a csv file to the body of an API request. The from data versions I've tried do not attach any data to the body, and when trying to us a binary to blob conversion, the request does not work. I've also tried custom commands and those do not submit my request. XMLHttpRequest does not work for me either.

I've gotten 400 errors because the file wasn't attached/uploaded and in different versions, "Failed to read the request form. Unexpected end of Stream, the content may have already been read by another component. "

BlobIssue
FailedRead

image
image

Desired behavior

I'm expecting to receive a 200 status with a returned id from the api.

Test code to reproduce

To reproduce aws access would be needed and the call contains private data. Here is layout of the code trying to be run:

        describe("POST import", () => {
            it("should returns the new import run.", () => {
                
                // //Attempt 
                cy.fixture('TestCsvSpreadsheet.csv', 'binary')
                    .then((file) => {
                        const blob = Cypress.Blob.binaryStringToBlob(file,fileType);
                        const formData = new FormData();
                        formData.set('modelJson', jsonModel);                        
                        formData.set("file", blob);

                        cy.request({
                            method: 'POST',
                            url: urlEndpoint,
                            body: formData
                        }).then((response) => {
                            expect(response.status).to.equal(200);
                            importRunId = response.body.id.toString();
                        })
                    });


                // // **** Another Attempt 
                // cy.fixture(fileName, 'binary')
                //     .then(file => {
                //         const blob = Cypress.Blob.binaryStringToBlob(file, 'text/csv');
                //         cy.request({
                //             method: 'POST',
                //             url: urlEndpoint,
                //             headers: {
                //                 "content-type": "multipart/form-data; boundary=----CypressFormDataBoundary",
                //             },
                //             body: {
                //                 file: blob,
                //                 modelJson: jsonModel
                //             }
                //         }).then(response => {
                //             expect(response.status).to.equal(200);
                //             importRunId = response.body.id.toString();
                //         })
                //     });
                
                
                
            })
        })

Cypress Version

9.5.2

Other

No response

@davidmunechika davidmunechika added the topic: cy.request Issues related to cy.request command label Apr 26, 2022
@davidmunechika
Copy link
Contributor

davidmunechika commented Apr 26, 2022

Thanks for opening an issue! There is a related discussion here about improvements we wish to make to handle requests with multipart/form-data. This has been identified as an issue but the work hasn't been prioritized yet

@jenglishPS
Copy link
Author

Has the work on multipart/form-data been prioritized or completed in the latest version?

@github-actions
Copy link
Contributor

This issue has not had any activity in 180 days. Cypress evolves quickly and the reported behavior should be tested on the latest version of Cypress to verify the behavior is still occurring. It will be closed in 14 days if no updates are provided.

@github-actions github-actions bot added the stale no activity on this issue for a long period label May 12, 2023
@liambutler
Copy link

Can confirm that this is still happening as of 12.9.0

@cypress-app-bot cypress-app-bot removed the stale no activity on this issue for a long period label May 15, 2023
@nagash77 nagash77 assigned marktnoonan and unassigned marktnoonan May 15, 2023
@nagash77 nagash77 added E2E Issue related to end-to-end testing Triaged Issue has been routed to backlog. This is not a commitment to have it prioritized by the team. labels May 15, 2023
@Harshithkumar
Copy link

Still the Issue persist in 12.17.1V as well. Can somebody help and fix this issue ?

@justine-santini
Copy link

Do we have a work around for this problem? I am using cypress v13.4.0 and I still have the issue.

@sramshek
Copy link

Do we have a work around for this problem? I am using cypress v13.4.0 and I still have the issue.

++

@BednarOG
Copy link

"Hi! If anyone still has a problem with this type of form, I invite you to discuss. I have a solution that has been working for me for quite some time now."

@damian-sketch
Copy link

@BednarOG could you share the solution that has been working for you ?

@BednarOG
Copy link

BednarOG commented Apr 3, 2024

In the example of what @jenglishPS wrote.

  1. Load fixture file (remember that with cy.fixture, you can only load one file)
    - cy.fixture(fileName, 'binary').then(file =>{})

  2. Create FormData object

  • const payload = new FormData()
  1. Append data with file name
  • payload.append("userName", "jenglishPS")
  1. Create a request :)

My example:

addSomething() {
  cy.fixture("attachFiles/example.png", "binary").then((image) => {
    const payload = new FormData();
    payload.append("userName", "random user name");
    payload.append("email", "random email");
    payload.append("file", new Blob([image], { type: "image/png" }), "example.png");
  });
  cy.request({
    method: "POST",
    url: endpointURL,
    headers: {
      "Content-Type": "multipart/form-data",
    },
    body: payload,
  })
}

If there is something not entirely clear, let me know.

@sairudayaraj
Copy link

sairudayaraj commented Aug 14, 2024

@BednarOG
cypress version v13+

I have tried with PDF attachment still getting error I've gotten 400 errors in response , response body getting empty

   uploadRL(filePath: string): any {
        const accessToken = Cypress.env('accessToken');

        return cy.fixture(filePath, "binary").then((fileContent) => {
            const payload = new FormData();
            payload.append("file", new Blob([fileContent], { type: "application/pdf" }), filePath);

            return cy.request({
                method: 'POST',
                url: `${apiconfig.endpoints.postUploadRL}`,
                headers: {
                    'Authorization': `Bearer ${accessToken}`,
                     'Content-Type': 'multipart/form-data'
                },
                body: payload,
                failOnStatusCode: false
            }).as('uploadRL');
        });
    } 
Response :
    {
    "method": "POST",
    "url": "xyz",
    "headers": {
        "Authorization": "Bearer xxxxx
    },
    "body": {},
    "failOnStatusCode": false
}

@BednarOG
Copy link

BednarOG commented Aug 14, 2024

  1. You don't need to type 'content-type' header - cypress will do it automatically.
  2. Ensure that the file is correctly read as binary and converted to a Blob before appending it to the FormData.
  3. Add encoding: 'binary': This ensures the file is transmitted in binary format, which is necessary for file uploads.

Try this:

uploadRL(filePath: string): any {
    const accessToken = Cypress.env('accessToken');

    return cy.fixture(filePath, "binary").then((fileContent) => {
        const payload = new FormData();
        const blob = new Blob([fileContent], { type: "application/pdf" });
        payload.append("file", blob, filePath);

        return cy.request({
            method: 'POST',
            url: `${apiconfig.endpoints.postUploadRL}`,
            headers: {
                'Authorization': `Bearer ${accessToken}`,
            },
            body: payload,
            encoding: 'binary'
        }).as('uploadRL');
    });
} 

@sairudayaraj
Copy link

sairudayaraj commented Aug 14, 2024

@BednarOG Still getting 400 error with same response like empty in body

i have given the file in this way and converted to a Blob before appending it to the FormData

When(`uploadltr`, () => {
		const filePath = 'xyz.pdf';
		cy.wait(2000);
		API.uploadRL(filePath).then((resp: any) => {
			response = resp;
			cy.log(JSON.stringify(response.body));  // Log response for debugging
			expect(response.status).to.eq(200);
		});
	});

@BednarOG
Copy link

BednarOG commented Aug 14, 2024

First of all, if you only need to upload a .pdf file, you don't need to format it as a Blob. Make sure you have this file in the 'cypress/fixtures/attachFiles' folder, and in the body, provide the path to this file.

cy.request({
  method: "POST",
  url: url.path,
  body: {
    filePath: "attachFiles/yourFile.pdf",
  },
  headers: your headers,
})

@sairudayaraj
Copy link

@jennifer-shehane @BednarOG As per the above input tried i have placed my Pdf file in fixture folder still getting 400 , kindly check the below

	When(` upload file `, () => {
	const filePath = 'xyz.pdf';
	cy.wait(2000);
	API.uploadRL(filePath).then((resp: any) => {
		response = resp;
		cy.log(JSON.stringify(response.body));  // Log response for debugging
		expect(response.status).to.eq(200);
	});
});

            uploadRL(filePath: string): any {
                const accessToken = Cypress.env('accessToken');
            
                cy.request({
                    method: 'POST',
                    url: `${apiconfig.endpoints.postUploadRL}`,
                    body: {
                        filePath: `${filePath}`
                    },
                    headers: {
                        'Authorization': `Bearer ${accessToken}`,
                        'Content-Type': 'application/pdf',
                    },
                    failOnStatusCode: false
                }).as('uploadRL');
            
                return cy.get('@uploadRL');
            }

Here is my request & response :

            {
"method": "POST",
"url": "path",
"body": {
    "filePath": "xyz.pdf"
},
"headers": {
    "Authorization": "Bearer XXX",
    "Content-Type": "application/pdf"
},
"failOnStatusCode": false

}

Response: 400 150ms
null

@BednarOG
Copy link

BednarOG commented Aug 15, 2024

Try something like this:

uploadRL(filePath: string): any {
    const accessToken = Cypress.env('accessToken');

    cy.fixture(filePath, 'binary').then((fileContent) => {
        // Convert binary content to a Blob object
        const blob = Cypress.Blob.binaryStringToBlob(fileContent, 'application/pdf');

        // Create a FormData object to include the file
        const formData = new FormData();
        formData.append('file', blob, filePath);

        cy.request({
            method: 'POST',
            url: `${apiconfig.endpoints.postUploadRL}`,
            body: formData,
            headers: {
                'Authorization': `Bearer ${accessToken}`,
            },
            // Important: Do not set Content-Type here, let the browser set it for the form-data
            failOnStatusCode: false
        }).as('uploadRL');
    });

    return cy.get('@uploadRL');
}

@sairudayaraj
Copy link

@BednarOG I have tried this earlier , not working getting response 400 and on request still the body is empty {}

@BednarOG
Copy link

send me your test file, data file (body) and the API methods that you using.
Try to do this manually and send all of data from payload tab.

@sairudayaraj
Copy link

sairudayaraj commented Aug 16, 2024

@BednarOG I have tried same in Postman tool upload the PDF it is works (simply I'm attaching the PDF file in form data)
image

API i tried this

Adding the xyz.pdf in fixture folder and call the UploadRL

	When(` upload file `, () => {
	const filePath = 'xyz.pdf';
	cy.wait(2000);
	API.uploadRL(filePath).then((resp: any) => {
		response = resp;
		cy.log(JSON.stringify(response.body));  // Log response for debugging
		expect(response.status).to.eq(200);
	});
});

uploadRL(filePath: string): any {
    const accessToken = Cypress.env('accessToken');

    cy.fixture(filePath, 'binary').then((fileContent) => {
        // Convert binary content to a Blob object
        const blob = Cypress.Blob.binaryStringToBlob(fileContent, 'application/pdf');

        // Create a FormData object to include the file
        const formData = new FormData();
        formData.append('file', blob, filePath);

        cy.request({
            method: 'POST',
            url: `${apiconfig.endpoints.postUploadRL}`,
            body: formData,
            headers: {
                'Authorization': `Bearer ${accessToken}`,
            },
            // Important: Do not set Content-Type here, let the browser set it for the form-data
            failOnStatusCode: false
        }).as('uploadRL');
    });

    return cy.get('@uploadRL');
}

printing in console
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
E2E Issue related to end-to-end testing topic: cy.request Issues related to cy.request command Triaged Issue has been routed to backlog. This is not a commitment to have it prioritized by the team.
Projects
None yet
Development

No branches or pull requests