How to Upload txt file with Cypress for API Testing - XMLHTTPRequest? - javascript

I'm trying to test an endpoint which will upload a file and give 200 response status code in cypress. As per some research cy.request cannot be used to upload a file for multipart/form-data so we need to use XMLHttp to upload such files. I have created below file to test the api but it doesn't work. Can someone please help what's wrong with my code ? Thank you.
Added below code under support/commands.ts(I will require a header to pass token from auth endpoint)
// Performs an XMLHttpRequest instead of a cy.request (able to send data as FormData - multipart/form-data)
Cypress.Commands.add('multipartFormRequest', (method,URL, formData,headers, done) => {
const xhr = new XMLHttpRequest();
xhr.open(method, URL);
xhr.setRequestHeader("accept", "application/json");
xhr.setRequestHeader("Content-Type", "multipart/form-data");
if (headers) {
headers.forEach(function(header) {
xhr.setRequestHeader(header.name, header.value);
});
}
xhr.onload = function (){
done(xhr);
};
xhr.onerror = function (){
done(xhr);
};
xhr.send(formData);
})
Test file to call multipartFormRequest:
const fileName = 'test_file.txt';
const method = 'POST';
const URL = "https://fakeurl.com/upload-file";
const headers = api.headersWithAuth(`${authToken}`);
const fileType = "application/text";
cy.fixture(fileName, 'binary').then((res) => {
const blob = Cypress.Blob.binaryStringToBlob(res, fileType);
const formData = new FormData();
formData.append('file', blob, fileName);
cy.multipartFormRequest(method, URL, headers, formData, function (response) {
expect(response.status).to.equal(200);
})
})
I'm getting this error message:-
Now, I'm getting status code as 0.

describe("Upload image", () => {
it("upload first image", () => {
const fileName = "image.jpeg";
const method = "POST";
const url = "https://api-demo.com/1";
const fileType = "image/jpeg";
cy.fixture(fileName, "binary")
.then((txtBin) => Cypress.Blob.binaryStringToBlob(txtBin))
.then((blob) => {
const formData = new FormData();
formData.append("image_data", blob, fileName);
formData.append("image_format", "jpeg");
cy.form_request(method, url, formData, function (response) {
expect(response.status).to.eq(200)
}
);
})
});
});
Cypress.Commands.add('form_request', (method, url, formData, done) => {
const xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.setRequestHeader("device", "331231");
xhr.setRequestHeader("city", "bangalore");
xhr.onload = function () {
done(xhr);
};
xhr.onerror = function () {
done(xhr);
};
xhr.send(formData);
})

Use
const blob = Cypress.Blob.binaryStringToBlob(res, fileType);
and remove the .then().
See Cypress.Blob
History
Version 5.0.0
Changes:
Return type of arrayBufferToBlob, base64StringToBlob, binaryStringToBlob, and dataURLToBlob methods changed from Promise<Blob> to Blob

Related

GET Request with JS

i need to send a GET request from my JavaScript function to my python flask app. However, i tried to type the URL with the parameters manually and it worked. But i can't send the same request in a JS function. Response type is HTML.
This is how the URL should look like:
http://127.0.0.1:5000/books?rank=2&topic=Self improvement
I tried this, but it didn't work:
function sendRequest() {
const xhr = new XMLHttpRequest();
xhr.open('GET', '/books', {
rank: rank,
topic: topic
});
xhr.onload = function() {
console.log(xhr.response);
}
xhr.send();
}
What the URL looked like with this try:
http://127.0.0.1:5000/books
Please help!
You're trying to pass the parameters in a POST body (the third argument to open). That won't work for a GET, they have to be in the URL.
The easiest and least error-prone way is to use URLSearchParams (thank you Christopher for pointing that out when I forgot!):
const url = "/books?" + new URLSearchParams({rank, title});
Live Example:
const rank = 42;
const title = "Life, the Universe, and Everything";
const url = "/books?" + new URLSearchParams({rank, title});
console.log(url);
These days, you'd usually use the more modern fetch rather than XMLHttpRequest:
function sendRequest() {
const url = "/books?" + new URLSearchParams({rank, title});
fetch(url)
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP error ${response.status}`);
}
return response.text(); // Or `.json()` or one of the others
})
.then((data) => {
console.log(data);
})
.catch((error) => {
// ...handle/report error...
});
}
But if you prefer to use XMLHttpRequest, put the parameters in the URL (and handle errors):
function sendRequest() {
const xhr = new XMLHttpRequest();
const url = "/books?" + new URLSearchParams({rank, title});
xhr.open("GET", url);
xhr.onload = function () {
console.log(xhr.response);
};
xhr.onerror = function () {
// ...handle/report error...
};
xhr.send();
}
(You can also use string concatenation and encodeURIComponent to build the URL, but it's more work and more error-prone. :-) )
I made a code with fetch() based on the comments above, let me know if you get any errors. Hope this helps, XMLHttpRequest() is not used much due to its complexity.
async function sendRequest(){
const url = 'your URL';
await fetch(url,{
method: "GET",
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
}
}).then(response=>{
if(response.status !=200) {
throw new Error(`HTTP ERROR:${response.status}`);
}
return response.text()
}
).then(data => {
console.log(data);
// convert to html
}).catch(err => {
console.log(err);
})
}

How can i apply callback to get the http response in a method

I am attempting to write a method so that i pass the url and application name and it return the response. I read that I can apply callback to resolve this but I am not able to resolve the issue. Any help would be appreciated.
Please find below my code snippet.
var response = getResponse(url,applicationName)
console.log("response from getResponse \n" +response);
function getResponse(url,applicationName){
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
"application": applicationName
}));
xhr.onload = function() {
console.log(this.responseText);
}
return xhr.responseText;
}
You can use the onreadystatechange method to handle XHR responses, try this:
//XHR POST
const xhr = new XMLHttpRequest; // creates new object
const url = 'https://api-to-call.com/endpoint';
const data = JSON.stringify({"application": applicationName}); // converts data to a string
xhr.responseType = 'json';
xhr.onreadystatechange = () => {
if(xhr.readyState === XMLHttpRequest.DONE) {
return xhr.response;
}
}
xhr.open('POST', url); // opens request
xhr.send(data); // sends object
you should use promise instead of callback and do something like that.
const url = "https://httpbin.org/post";
const applicationName = "test";
getResponse(url, applicationName)
.then(response => {
//work here, not outside
console.log(response);
})
.catch(error => {
console.log(error);
})
function getResponse(url, applicationName) {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
"application": applicationName
}));
xhr.onload = function() {
// print JSON response
if (xhr.status >= 200 && xhr.status < 300) { // if valid
// work here
const response = JSON.parse(xhr.response.replace(/"/g, '"'));
const data = JSON.parse(response.data.replace(/"/g, '"'));
resolve(data);
}
reject(xhr.response); // reject and return the response if not valid
}
})
}
If you want to learn more about asynchronous https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Concepts, I invite you to go to this website to learn a little more about the promise.
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Promises
The callback is executed after the code returned xhr.responseText. So that means xhr.responseText returns null.
I would recommend using the fetch API opposed to the older XMLHttpRequest you are using now. The fetch API is basically a Promise based XMLHttpRequest.
Your function would look something like:
async function getResponse( url, applicationName ) {
const json = JSON.stringify({
"application": applicationName
});
return fetch( url, {method: 'POST', headers: { 'Content-Type':'application/json'}, body: json} );
}
// access like this
getResponse( url, applicationName)
.then( response => { console.log(response) });
async function someFunction( url, applicationName ) {
// or pause the code while the request is fetched by using await, note that you need to be in a function that is declared async to use this approach.
const response = await getResponse( url, applicationName );
}
Fetch documentation can be found at MDN: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

How to fetch from graphql server using XMLHttpRequest?

How I can get response from graphql server using pure js without libraries?
For example how I can do that using XMLHttpRequest?
Query and serverUrl are below:
const serverUrl = 'http://example.com/graphql/'
const query = {
query: `{
viewer {
date
}
}`
};
Use POST request with 'Content-Type', 'application/json'
const yourServerUrl = 'http://example.com/graphql'
const yourQuery = {
query: `{
users {
firstName
}
}`
};
// below ordinary XHR request with console.log
const xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.open('POST', yourServerUrl);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function () {
console.log('data returned:', xhr.response);
};
xhr.send(JSON.stringify(yourQuery));
source

Can't fetch file with XMLHttpRequest in React Native

I'm trying to retrieve a local file on an iOS device which is saved from Expo Camera and ImageManipulator. The Image shows up in a View. However, when I run this code to get a blob and then upload to Firebase Storage, I get the 'Network request failed error', it seems random and I don't know what causes it.
The code is from here: https://github.com/expo/expo/issues/2402#issuecomment-443726662
const blob = yield new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = function() {
resolve(xhr.response);
};
xhr.onerror = function(e) {
//console.log(e);
reject('Network request failed.');
};
xhr.responseType = 'blob';
xhr.open('GET', uri, true);
xhr.send(null);
})
.catch(e => console.log(e));

Javascript fetch is not working, postman works fine

I have route where I can upload images, and it works fine with postman.
I`m using multer as middleware.
var data = new FormData();
data.append("file", "");
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function () {
if (this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("POST", "http://localhost:8080/file");
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.setRequestHeader("cache-control", "no-cache");
xhr.setRequestHeader("Postman-Token", "a6e7543e-ef94-4d17-813d-a0a1fb4aa2b2");
xhr.send(data);
but when I`m using fetch in my react app it just return undefined
uploadImage = async (image) => {
const imageData = new FormData()
imageData.append('file', image)
const address = '/file'
const body = imageData
const response = await fetch(`http://localhost:8080${address}`, {
method: 'POST',
credentials: 'include',
body: body
})
const result = await response.json()
return result
}
Any ideas how to fix it?
I copy paste request from postman to my react app, it still doesn`t work.

Categories