@@ -282,13 +282,61 @@ module.exports = (Commands, Cypress, cy, state, config) => {
282282 // Check if body is Blob.
283283 // construct.name is added because the parent of the Blob is not the same Blob
284284 // if it's generated from the test spec code.
285- if ( requestOpts . body instanceof Blob || requestOpts ? .body ?. constructor . name === 'Blob' ) {
285+ if ( requestOpts . body instanceof Blob || requestOpts . body ?. constructor . name === 'Blob' ) {
286286 requestOpts . bodyIsBase64Encoded = true
287287
288288 return Cypress . Blob . blobToBase64String ( requestOpts . body ) . then ( ( str ) => {
289289 requestOpts . body = str
290290 } )
291291 }
292+
293+ // https://github.com/cypress-io/cypress/issues/1647
294+ // Handle if body is FormData
295+ if ( requestOpts . body instanceof FormData || requestOpts . body ?. constructor . name === 'FormData' ) {
296+ const boundary = '----CypressFormDataBoundary'
297+
298+ // reset content-type
299+ if ( requestOpts . headers ) {
300+ delete requestOpts . headers [ Object . keys ( requestOpts ) . find ( ( key ) => key . toLowerCase ( ) === 'content-type' ) ]
301+ } else {
302+ requestOpts . headers = { }
303+ }
304+
305+ // boundary is required for form data
306+ // @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST
307+ requestOpts . headers [ 'content-type' ] = `multipart/form-data; boundary=${ boundary } `
308+
309+ // socket.io ignores FormData.
310+ // So, we need to encode the data into base64 string format.
311+ const formBody = [ ]
312+
313+ requestOpts . body . forEach ( ( value , key ) => {
314+ // HTTP line break style is \r\n.
315+ // @see https://stackoverflow.com/questions/5757290/http-header-line-break-style
316+ if ( value instanceof File || value ?. constructor . name === 'File' ) {
317+ formBody . push ( `--${ boundary } \r\n` )
318+ formBody . push ( `Content-Disposition: form-data; name="${ key } "; filename="${ value . name } "\r\n` )
319+ formBody . push ( `Content-Type: ${ value . type || 'application/octet-stream' } \r\n` )
320+ formBody . push ( '\r\n' )
321+ formBody . push ( value )
322+ formBody . push ( '\r\n' )
323+ } else {
324+ formBody . push ( `--${ boundary } \r\n` )
325+ formBody . push ( `Content-Disposition: form-data; name="${ key } "\r\n` )
326+ formBody . push ( '\r\n' )
327+ formBody . push ( value )
328+ formBody . push ( '\r\n' )
329+ }
330+ } )
331+
332+ formBody . push ( `--${ boundary } --\r\n` )
333+
334+ requestOpts . bodyIsBase64Encoded = true
335+
336+ return Cypress . Blob . blobToBase64String ( new Blob ( formBody ) ) . then ( ( str ) => {
337+ requestOpts . body = str
338+ } )
339+ }
292340 } )
293341 . then ( ( ) => {
294342 return Cypress . backend ( 'http:request' , requestOpts )
0 commit comments