Cypress request method won't decode special characters - javascript

I am writing a few API calls which are intertwined and pass on values to each other, there's a get token and store call then an get list of users and store user_id in order for both of those to be forwarded to the third DELETE user api call. The issue im encountering is with the url forming in the delete request. There's a special character in the user_id which is '|' this one. Notably when i pass the JS function decodeURIComponent on it, i get a proper result and the | character. But when calling the decoded variable inside the Cypress request method url option. It keeps ignoring the decode and encoding the character no matter where i try to put decodeURIComponent.
Heres a few examples of the method i tried using
Cypress.Commands.add('deleteCreatedUser', (token, user_id) => {
var userid = decodeURIComponent(user_id)
cy.log(userid)
cy.request({
method: 'DELETE',
url: "https://companydomain.auth0.com/api/v2/users/" + `${userid}`,
auth: {
bearer: `${token}`
}
})
.then((resp) => {
expect(resp.status).to.eq(204)
})
})
Or
Cypress.Commands.add('deleteCreatedUser', (token, user_id) => {
// var new_url = "https://companydomain.auth0.com/api/v2/users/" + `${decodeURIComponent(user_id)}`
// cy.log(new_url)
cy.request({
method: 'DELETE',
url: "https://companydomain.com/api/v2/users/" + `${decodeURIComponent(user_id)}`,
auth: {
bearer: `${token}`
}
})
.then((resp) => {
expect(resp.status).to.eq(204)
})
})
Or
Cypress.Commands.add('deleteCreatedUser', (token, user_id) => {
var new_url = "https://companydomain.auth0.com/api/v2/users/" + `${decodeURIComponent(user_id)}`
cy.log(new_url)
cy.request({
method: 'DELETE',
url: new_url,
auth: {
bearer: `${token}`
}
})
.then((resp) => {
expect(resp.status).to.eq(204)
})
})
All produce the same error message, the cy.log output is correctly:
https://companydomain.auth0.com/api/v2/users/auth0|63c92d19bc49af9a23ede481
but in the cypress request method that fails the URL is:
https://companydomain.auth0.com/api/v2/users/auth0%7C63c92d19bc49af9a23ede481
I am on Cypress version 12.3.0
So the decoding won't work in the Cypress request method, does anyone have a solution for this?

Related

How to ensure order of Cypress request execution

In my Cypress test, I am trying to make calls to two seperate API endpoints.
I'm able to make the calls, but I need to ensure they execute in the correct order.
Below are simplified versions of my requests:
cy.request('POST', apiUrl + 'Session', {username: merchant_username}
).as('postSession')
cy.request('POST', apiUrl + 'TestCase', {username: merchant_username}
).as('postTestCase')
It's important that the calls execute in this order because some of them depend on values from the others.
I am trying to retrieve sessionId from the postSession response:
cy.request({
method: 'POST',
url: apiUrl + 'session',
}).as('postSession')
cy.get('#postSession').should(response => {
sessionId = response.body.SessionId;
})
And then use it in the request body of postTestCase:
cy.request({
method: 'POST',
url: apiUrl + 'TestCase',
body: {
"SessionId": sessionId
}
})
If I do .then() after postSession & place postTestCase inside that like so, the request works fine, but I would like to avoid doing that if possible.
cy.get('#postToken').should(response => {
sessionId = response.body.SessionId;
}).then(() => {
cy.request({
method: 'POST',
url: apiUrl + 'TestCase',
body: {
"SessionId": sessionId
}
})
})
I've also tried using cy.wait(), but the sessionId is blank in the 2nd request then.
cy.wait('#postSession')
cy.wait('#postTestCase')
Is there a way I can ensure postSession is executed before postTestCase without placing postTestCase inside a .then() after postSession?
Unfortunately, at the time this answer is posted, there is an open issue on the Cypress GitHub repository with a proposal for await, as per this link.
So only the "nested" requests way is possible at the moment.
For example of your snippets:
cy.request({
method: 'POST',
url: apiUrl + 'session',
}).then((response) => {
const sessionId = response.body.SessionId;
cy.request({
method: 'POST',
url: apiUrl + 'TestCase',
body: {
"SessionId": sessionId
},
});
});
You need to do something like this:
cy.request({
method: 'GET',
url: 'https://' + host + '/lending/loan',
headers: default_headers
}).then(res => {
cy.request({})
.then(res => {})
})

how to set axios post parameters as object?

when the SMS is sent using the API in template literal way works smoothly:
axios.post(
`https://api.fooserver.com/${API_KEY}/verify/lookup?receptor=${phone}&token=${code}`
)
.then(resp => resp.data)
whats wrong with the object param?
axios.post(`https://api.kavenegar.com/v1/${API_KEY}/verify/lookup`, {
receptor: phone,
token: code
})
.then(resp => resp.data);
it does send request but the object params.
Lucky I understood your question:), using params Axios will automaticity translate your object in query params.
Use this:
axios.post(`https://api.kavenegar.com/v1/${API_KEY}/verify/lookup`,{}, {
params: {
receptor: phone,
token: code
}})
.then(resp => resp.data);
In the first example, you are sending the data as query parameters, which isn't the same as sending it in the post body, as in the second example.
You can in fact pass your query parameters as an object, you just need to call .post a little differently:
axios
.post(
`https://api.fooserver.com/${API_KEY}/verify/lookup`,
{},
{
params: {
receptor: phone,
token: code
}
}
)
.then(resp => resp.data);
Or, if you so desire:
axios({
method: 'POST',
url: `https://api.fooserver.com/${API_KEY}/verify/lookup`,
params: {
receptor: phone,
token: code
}
})
.then(resp => resp.data);
You'll need to use querystring.stringify
Like this :
const querystring = require('querystring');
axios.post(`https://api.kavenegar.com/v1/${API_KEY}/verify/lookup`, querystring.stringify({
receptor: phone,
token: code
})
.then(resp => resp.data);

How to post query parameters with Axios?

I am trying to post on an API with some query params.
This is working on PostMan / Insomnia when I am trying to by passing mail and firstname as query parameters :
http://localhost:8000/api/mails/users/sendVerificationMail?mail=lol%40lol.com&firstname=myFirstName
However, when I am trying to do it with my react native app, I got a 400 error (Invalid Query Parameters).
This is the post method :
.post(`/mails/users/sendVerificationMail`, {
mail,
firstname
})
.then(response => response.status)
.catch(err => console.warn(err));
(my mail and firstname are console.logged as follow: lol#lol.com and myFirstName).
So I don't know how to pass Query Parameters with Axios in my request (because right now, it's passing data: { mail: "lol#lol.com", firstname: "myFirstName" }.
axios signature for post is axios.post(url[, data[, config]]). So you want to send params object within the third argument:
.post(`/mails/users/sendVerificationMail`, null, { params: {
mail,
firstname
}})
.then(response => response.status)
.catch(err => console.warn(err));
This will POST an empty body with the two query params:
POST
http://localhost:8000/api/mails/users/sendVerificationMail?mail=lol%40lol.com&firstname=myFirstName
As of 2021 insted of null i had to add {} in order to make it work!
axios.post(
url,
{},
{
params: {
key,
checksum
}
}
)
.then(response => {
return success(response);
})
.catch(error => {
return fail(error);
});
In my case, the API responded with a CORS error. I instead formatted the query parameters into query string. It successfully posted data and also avoided the CORS issue.
var data = {};
const params = new URLSearchParams({
contact: this.ContactPerson,
phoneNumber: this.PhoneNumber,
email: this.Email
}).toString();
const url =
"https://test.com/api/UpdateProfile?" +
params;
axios
.post(url, data, {
headers: {
aaid: this.ID,
token: this.Token
}
})
.then(res => {
this.Info = JSON.parse(res.data);
})
.catch(err => {
console.log(err);
});
You can use params and body together in a request with axios
sendAllData (data) {
return axios
.post(API_URL + "receiveData", JSON.stringify(data), {
headers: { "Content-Type": "application/json; charset=UTF-8" },
params: { mail: xyx#example.col }, //Add mail as a param
})
.then((response) => console.log("repsonse", response.status));
}

can't send Array to Controller

let data = new FormData();
payload = JSON.stringify(payload.unitDoctors);
for (var key in payload) {
data.append(key, payload[key]);
}
axios({
method: "put",
url: apiPath + payload.id,
data: data
})
.then(response => {
commit("updateItem", response.data);
})
.catch(e => {
commit("setErrors", e.response.data);
});
}
when i send formData to api controller unitDoctors(array) always null. Any Idea ?
You are attempting to loop over a string, as you've already called JSON.stringify there. Maybe get rid of that stringification call? It's hard to tell what the actual problem is without seeing your data and the desired result.

Axios - DELETE Request With Request Body and Headers?

I'm using Axios while programming in ReactJS and I pretend to send a DELETE request to my server.
To do so I need the headers:
headers: {
'Authorization': ...
}
and the body is composed of
var payload = {
"username": ..
}
I've been searching in the inter webs and only found that the DELETE method requires a "param" and accepts no "data".
I've been trying to send it like so:
axios.delete(URL, payload, header);
or even
axios.delete(URL, {params: payload}, header);
But nothing seems to work...
Can someone tell me if it's possible (I presume it is) to send a DELETE request with both headers and body and how to do so?
So after a number of tries, I found it working.
Please follow the order sequence it's very important else it won't work
axios.delete(URL, {
headers: {
Authorization: authorizationToken
},
data: {
source: source
}
});
axios.delete does supports both request body and headers.
It accepts two parameters: url and optional config. You can use config.data to set the request body and headers as follows:
axios.delete(url, { data: { foo: "bar" }, headers: { "Authorization": "***" } });
See here - https://github.com/axios/axios/issues/897
Here is a brief summary of the formats required to send various http verbs with axios:
GET: Two ways
First method
axios.get('/user?ID=12345')
.then(function (response) {
// Do something
})
Second method
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
// Do something
})
The two above are equivalent. Observe the params keyword in the second method.
POST and PATCH
axios.post('any-url', payload).then(
// payload is the body of the request
// Do something
)
axios.patch('any-url', payload).then(
// payload is the body of the request
// Do something
)
DELETE
axios.delete('url', { data: payload }).then(
// Observe the data keyword this time. Very important
// payload is the request body
// Do something
)
Key take aways
get requests optionally need a params key to properly set query parameters
delete requests with a body need it to be set under a data key
axios.delete is passed a url and an optional configuration.
axios.delete(url[, config])
The fields available to the configuration can include the headers.
This makes it so that the API call can be written as:
const headers = {
'Authorization': 'Bearer paperboy'
}
const data = {
foo: 'bar'
}
axios.delete('https://foo.svc/resource', {headers, data})
For those who tried everything above and still don't see the payload with the request - make sure you have:
"axios": "^0.21.1" (not 0.20.0)
Then, the above solutions work
axios.delete("URL", {
headers: {
Authorization: `Bearer ${token}`,
},
data: {
var1: "var1",
var2: "var2"
},
})
You can access the payload with
req.body.var1, req.body.var2
Here's the issue:
https://github.com/axios/axios/issues/3335
For Delete, you will need to do as per the following
axios.delete("/<your endpoint>", { data:<"payload object">})
It worked for me.
I had the same issue I solved it like that:
axios.delete(url, {data:{username:"user", password:"pass"}, headers:{Authorization: "token"}})
Actually, axios.delete supports a request body.
It accepts two parameters: a URL and an optional config. That is...
axios.delete(url: string, config?: AxiosRequestConfig | undefined)
You can do the following to set the response body for the delete request:
let config = {
headers: {
Authorization: authToken
},
data: { //! Take note of the `data` keyword. This is the request body.
key: value,
... //! more `key: value` pairs as desired.
}
}
axios.delete(url, config)
I hope this helps someone!
If we have:
myData = { field1: val1, field2: val2 }
We could transform the data (JSON) into a string then send it, as a parameter, toward the backend:
axios.delete("http://localhost:[YOUR PORT]/api/delete/" + JSON.stringify(myData),
{ headers: { 'authorization': localStorage.getItem('token') } }
)
In the server side, we get our object back:
app.delete("/api/delete/:dataFromFrontEnd", requireAuth, (req, res) => {
// we could get our object back:
const myData = JSON.parse(req.params.dataFromFrontEnd)
})
Note: the answer from "x4wiz" on Feb 14 at 15:49 is more accurate to the question than mine! My solution is without the "body" (it could be helpful in some situation...)
Update: my solution is NOT working when the object has the weight of 540 Bytes (15*UUIDv4) and more (please, check the documentation for the exact value). The solution of "x4wiz" (and many others above) is way better. So, why not delete my answer? Because, it works, but mostly, it brings me most of my Stackoverflow's reputation ;-)
i found a way that's works:
axios
.delete(URL, {
params: { id: 'IDDataBase'},
headers: {
token: 'TOKEN',
},
})
.then(function (response) {
})
.catch(function (error) {
console.log(error);
});
I hope this work for you too.
To send an HTTP DELETE with some headers via axios I've done this:
const deleteUrl = "http//foo.bar.baz";
const httpReqHeaders = {
'Authorization': token,
'Content-Type': 'application/json'
};
// check the structure here: https://github.com/axios/axios#request-config
const axiosConfigObject = {headers: httpReqHeaders};
axios.delete(deleteUrl, axiosConfigObject);
The axios syntax for different HTTP verbs (GET, POST, PUT, DELETE) is tricky because sometimes the 2nd parameter is supposed to be the HTTP body, some other times (when it might not be needed) you just pass the headers as the 2nd parameter.
However let's say you need to send an HTTP POST request without an HTTP body, then you need to pass undefined as the 2nd parameter.
Bare in mind that according to the definition of the configuration object (https://github.com/axios/axios#request-config) you can still pass an HTTP body in the HTTP call via the data field when calling axios.delete, however for the HTTP DELETE verb it will be ignored.
This confusion between the 2nd parameter being sometimes the HTTP body and some other time the whole config object for axios is due to how the HTTP rules have been implemented. Sometimes an HTTP body is not needed for an HTTP call to be considered valid.
For Axios DELETE Request, you need to include request payload and headers like this under one JSON object:
axios.delete(URL, {
headers: {
'Authorization': ...
},
data: {
"username": ...
}
})
Why can't I do it easily as I do similar to POST requests?
Looking at the Axios documentation, we see that the methods for .get, .post... have a different signature:
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.options(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])
Notice how only post, patch and put have the data parameter. This is because these methods are the ones that usually include a body.
Looking at RFC7231, we see that a DELETE request is not expected to have a body; if you include a body, what it will mean is not defined in the spec, and servers are not expected to understand it.
A payload within a DELETE request message has no defined semantics; sending a payload body on a DELETE request might cause some existing implementations to reject the request.
(From the 5th paragraph here).
In this case, if you are also in control of the server, you could decide to accept this body in the request and give it whatever semantics you want. May be you are working with somebody else's server, and they expect this body.
Because DELETE requests with bodies are not defined in the specs, and because they're not common, Axios didn't include them in those method aliases. But, because they're possible, you can do it, just takes a bit more effort.
I'd argue that it would be more conventional to include the information on the url, so you'd do:
axios.delete(
`https://example.com/user/${encodeURIComponent(username}`,
{ headers: ... }
)
or, if you want to be able to delete the user using different criteria (sometimes by username, or by email, or by id...)
axios.delete(
`https://example.com/user?username=${encodeURIComponent(username)}`,
{ headers: ... }
)
Not realated to axios but might help people tackle the problem they are looking for. PHP doesn't parse post data when preforming a delete call. Axios delete can send body content with a request.
example:
//post example
let url = 'http://local.test/test/test.php';
let formData = new FormData();
formData.append('asdf', 'asdf');
formData.append('test', 'test');
axios({
url: url,
method: 'post',
data: formData,
}).then(function (response) {
console.log(response);
})
result: $_POST Array
(
[asdf] => asdf
[test] => test
)
// delete example
axios({
url: url,
method: 'delete',
data: formData,
}).then(function (response) {
console.log(response);
})
result: $_POST Array
(
)
to get post data on delete call in php use:
file_get_contents('php://input');
axios.post('/myentity/839', {
_method: 'DELETE'
})
.then( response => {
//handle success
})
.catch( error => {
//handle failure
});
Thanks to:
https://www.mikehealy.com.au/deleting-with-axios-and-laravel/
I encountered the same problem...
I solved it by creating a custom axios instance. and using that to make a authenticated delete request..
const token = localStorage.getItem('token');
const request = axios.create({
headers: {
Authorization: token
}
});
await request.delete('<your route>, { data: { <your data> }});
I tried all of the above which did not work for me. I ended up just going with PUT (inspiration found here) and just changed my server side logic to perform a delete on this url call. (django rest framework function override).
e.g.
.put(`http://127.0.0.1:8006/api/updatetoken/20`, bayst)
.then((response) => response.data)
.catch((error) => { throw error.response.data; });
Use {data: {key: value}} JSON object, the example code snippet is given below:
// Frontend Code
axios.delete(`URL`, {
data: {id: "abcd", info: "abcd"},
})
.then(res => {
console.log(res);
});
// Backend Code (express.js)
app.delete("URL", (req, res) => {
const id = req.body.id;
const info = req.body.info;
db.query("DELETE FROM abc_table WHERE id=? AND info=?;", [id, info],
(err, result) => {
if (err) console.log(err);
else res.send(result);
}
);
});
Axios DELETE request does supports similar what POST request does, but comes in different formats.
DELETE request payload sample code:
axios.delete(url, { data: { hello: "world" }, headers: { "Authorization": "Bearer_token_here" } });
POST request payload sample code:
axios.post(url, { hello: "world" }, { headers: { "Authorization": "Bearer_token_here" } });
Noticed that { hello: "world" } is configured in different ways, but both performs same functions.
this code is generated from post man and it's perfectly work for delete api request with body.
var data = JSON.stringify({"profile":"false","cover":"true"});
var config = {
method: 'delete',
url: 'https://api.fox.com/dev/user/image',
headers: {
'Authorization': 'Bearer token',
},
data : data
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});

Categories