-
Notifications
You must be signed in to change notification settings - Fork 3.3k
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
Posting formData using cypress doesn't work #1647
Comments
You likely just want to read in a fixtures data and set it as the body. I'm not seeing a reason to construct an arbitrary formdata object in the browser when you can bypass these restrictions directly... I guess maybe it would change your server's implementation? Do I have that right? |
Yes correct, the server is expecting |
@ahmehri Were you able to find a way to work around this? Please do let me know. Thanks |
cy.fixture('FF_ViewAllActiveSites_20180503_102650').then((sites) => {
cy.request({
url: '/api/sites',
method: 'post',
form: true,
headers: {
'content-type': 'multipart/form-data',
},
files: {
file: sites
}
}).then((res) => {
console.log(res);
})
}) I have added the file to fixtures. I should be able to call my API which expects req.files.file to be set.
This is how the files parameter looks when I do the request from a browser |
@srinivasrk no I didn't. |
Is there anyway we can get help on this ? |
cc: @srinivasrk @ahmehri I was able to get a formData submitted with a combination of a mix of answers I found. I hope this helps you. Add this to support/commands.js: Cypress.Commands.add("form_request", (url, formData) => {
return cy
.server()
.route("POST", url)
.as("formRequest")
.window()
.then(win => {
var xhr = new win.XMLHttpRequest();
xhr.open(method, url);
xhr.send(formData);
})
.wait("@formRequest");
}); Then you'd be able to do the following in your tests: cy
.form_request(url, formData)
.then(response => {
// do stuff with your response
}); |
@drewbrend doesn't work fo me :( |
I googled your error, I'm guessing you're using TypeScript? Maybe this will work? |
Has there been resolution to this? Ive tried your "form_request" function to no avail. taking the window() route and using fetch, no go. |
this is what the command looks like currently, My server gives me an error saying the stream ended unexpectedly. The error from Cypress is:
let body = new FormData();
body.append("email", email || Cypress.env("validEmail"));
body.append("password", password || Cypress.env("validPassword"));
cy.request({
method: "POST",
url: `${Cypress.env("API_AUTH")}/login`,
headers: {
"content-type":
"multipart/form-data; boundary=----WebKitFormBoundaryoh3GYY6WEwLKtV1k"
},
body
}); |
Followup, I worked around this by using fetch() it still seems to accomplish the goal of setting the cookie in the browser. |
I tried this solution, this works on chrome browser but not in electron both in --headed and headless moe. Somehow @drewbrend any suggestion on this? |
@chit786 |
@drewbrend doesn't work for me, either.
Looks like it happens somewhere in the Cypress.on('uncaught:exception', (err, runnable) => {
Cy.log("Hi Mark Uncaught Exception");
debugger;
// returning false here prevents Cypress from
// failing the test
// return false;
throw error;
}) in |
Whoops... when I changed, |
I would hope this issue can get fixed the right way. |
@ahmehri How did you end up working around this to POST with formData? I'm having the same issue. |
based on this thread, i have ended up so far with: Cypress.Commands.add('createFile', (file, type) => {
const formData = new FormData();
formData.set('type', type);
return cy.fixture(file).then(fileData => {
formData.set('file', new File([JSON.stringify(fileData)], file), file);
return cy
.server().route('POST', '/api/files').as('formRequest').window()
.then(win => {
return new Promise((resolve, reject) => {
const xhr = new win.XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
resolve(xhr.response);
}
};
xhr.open('POST', '/api/files');
xhr.send(formData);
});
})
.wait('@formRequest').then((xhr) => {
return cy.wrap({ status: xhr.status, body: xhr.response.body });
});
});
}); ... The unfortunate side of this, is that I have absolutely no idea what it's doing. On the bright side, though, at least it works. |
Good day, the workaround described above does not work for me because I try to send a file to another subdomain, that why I got 404 error because I need to set correct Referrer( that is forbidden for xhr requests) Cypress.Commands.add('form_request', (method, url, formData, accountName, tokens, done) => {
const xhr = new XMLHttpRequest();
xhr.open(method, url, false);
xhr.setRequestHeader('Access-Control-Allow-Origin',`https://${accountName}.condogenie-app.brocoders.xyz`);
xhr.setRequestHeader('Accept', 'application/json, text/plain, */*');
xhr.setRequestHeader('Access-Control-Request-Method', 'POST');
xhr.setRequestHeader('Access-Control-Allow-Credentials', 'true');
xhr.setRequestHeader('access-token', tokens['access-token']);
xhr.setRequestHeader('token-type', tokens['token-type']);
xhr.setRequestHeader('client', tokens['client']);
xhr.setRequestHeader('uid', tokens['uid']);
xhr.onload = function () {
done(xhr);
};
xhr.onerror = function () {
done(xhr);
};
xhr.send(formData);
}); |
I was able to do this by sending a form request using jQuery off of the window. I chose to use a synchronous request here just to keep the code simple. cy.window().then(({$}) => {
const fd = new FormData();
fd.append('foo', 'bar');
$.ajax({
type: 'POST',
url: '/some/api/url',
data: fd,
dataType: 'json',
async: false, // send as synchronous request, to keep this simple
cache: false,
contentType: false,
processData: false,
});
}); |
If XHR request is part of your test setup and you need its response later on, here is the solution I worked out: In a helper file you can define a function to execute the request: export function formRequest(method, url, formData, headers) {
const request = new XMLHttpRequest();
request.open(method, url, false);
if (headers) {
headers.forEach(function(header) {
request.setRequestHeader(header.name, header.value);
});
}
request.send(formData);
return JSON.parse(request.response);
} Using helper function you can define a specific request to your API as: export function customerUploadFile(accessToken, file, fileName, fileType) {
return cy.fixture(file, 'binary').then(function(binary) {
return Cypress.Blob.binaryStringToBlob(binary, fileType).then(function(blob) {
const targetUrl = `${apiUrl}/${apiVersion}/customer/action/upload_file?license_id=${licenseId}`;
const headers = [{ name: 'Authorization', value: `Bearer ${accessToken}` }];
const formData = new FormData();
formData.set('file', blob, fileName);
return formRequest('POST', targetUrl, formData, headers);
});
});
} And your custom command: Cypress.Commands.add('customerUploadFile', function(customerToken, fixtureName) {
return cy.fixture(fixtureName).then(function(fixture) {
const { file, fileName, fileType } = fixture;
return customerUploadFile(customerToken, file, fileName, fileType);
});
}); Now in your fixtures you can prepare following files:
And in your test you can easily handle such image upload: it('test', function() {
const fixtureName = 'image';
const constAuthToken = 'however you obtain it';
cy.customerUploadFile(constAuthToken, fixtureName).then(function(uploadResponse) {
cy.log(uploadResponse);
});
});
}); This will get necessary information about image from the json fixture and then get the binary and upload it. |
As far as I can see, all this code in here is way too complicated and uses too many "custom" Cypress.Commands.add('fileRequest', (filePath, requestOptions) => {
return cy
.fixture(filePath, 'binary')
.then(binary => Cypress.Blob.binaryStringToBlob(binary))
.then(blob => {
const formData = new FormData();
formData.set('file', blob);
return cy.request({ ...requestOptions, form: true, body: formData });
});
}); The typescript signature for this function is like this: and it can be called like this: cy.fileRequest(filePath, {
method: 'POST',
url: `/attachments/files/my-new-file`,
headers: {
authorization: `Bearer ${peterReaderAad.token}`
}
}); Since the second parameter is |
@Nasicus your solution doesn't result in request with correct multipart/form-data; boundary=--- header |
This worked for me with cypress 4.8.0 cy.request({
url: "https:/....",
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
form: true,
body:{ some body}
}).then(response => {
console.log("response", response);
}); |
Thanks @shwarcu this is pretty much everything you need. There are a couple of little things you need to make sure you do with this.
It would really be ideal for Cypress to add support for multipart/form-data requests using their cy.request() command, but this is a reasonable workaround for the moment. This is very picky on how everything is set up and executed, so it is likely to break with future Cypress updates. |
Hi, I'm facing same issue on Electron Browser.. Any solution on this so far ? |
lmfao is all I can say. |
Hi everyone! |
workaround which work with .net controller IFormFile:
|
The code for this is done in cypress-io/cypress#16576, but has yet to be released. |
Released in This comment thread has been locked. If you are still experiencing this issue after upgrading to |
Current behavior:
Uploading file via
POST
request offormData
doesn't work.Desired behavior:
Being able to post
formData
using cypressPOST
request.Steps to reproduce:
The following code doesn't work.
Versions
cypress@2.1.0
ubuntu 16.04 LTS
Chrome 66.0.3359
The text was updated successfully, but these errors were encountered: