How to ensure order of Cypress request execution - javascript

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 => {})
})

Related

Cypress request method won't decode special characters

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?

send post and get request on click using NEXT JS

i need to post and get my data when clicking on the same button [like write and show comment] , but when i click the button everything is going well but a request with 304 status code is running with infinite loop, can someone help ?
const addCommentHandler = (commentData) => {
axios({
url: `/api/comment/${eventId}`,
method: "post",
data: commentData,
headers: {
"Content-type": "application/json",
},
}).then((res) => {
const data = res.data;
console.log(data);
});
axios({
url: `/api/comment/${eventId}`,
method: "get",
}).then((res) => {
const data = res.data;
setComments(data.comments);
});
};
useEffect(() => {
addCommentHandler();
}, []);
It seems like You want to Post the Data and then want to get the Updated Comments.But you are creating Two Asynchronous Api Calls..
304 Status Code Means " The requested resource has not been modified since the last time you accessed it "
Please Refresh Cache and try Again..
const addCommentHandler = async (commentData) => {
// add Try Catch for Errors..
const responseData = await axios({
url: `/api/comment/${eventId}`,
method: "post",
data: commentData,
headers: {
"Content-type": "application/json",
},
})
const resData = await axios({
url: `/api/comment/${eventId}`,
method: "get",
})
setComments(resData.data.comments);
};
useEffect(() => {
// Pass CommentData as Params in addCommentHandler
addCommentHandler();
}, []);`

CypressIO make a request then use the response to pass to another function to call another request, wrap inside a re-usable function

So the issue i have is i want to be able to call a module function, that will then call cy.request() get the response and feed this to another cy.request() in a nice way.
I want to make this code nicer:
Cypress.Commands.add('createUser', (user) => {
cy.request({
method: 'POST',
url: 'https://www.example.com/tokens',
body: {
email: 'admin_username',
password: 'admin_password'
}
}).then((resp) => {
cy.request({
method: 'POST',
url: 'https://www.example.com/users',
headers: ({ Authorization: 'Bearer ' + resp.body.token }),
body: user
})
})
})
I'd like to to have the two cy.requests within their own functions, e.g getAuthToken() and createUser(), so i can wrap that in either a Cypress.Command, or just a module function and call within the test file
const seedUser = (userObject) => {
getAuthToken().then((token) => {
return createUser(token); //where this would return the created user.
}
}
then used like so in the test file
before(()=>{
let user = seedUser();
//or
let user = cy.seedUser();
}
You can use cy.wrap() to wrap the response of your first request and then you can use it anywhere.
Custom commands:
Cypress.Commands.add('getAuthToken', () => {
cy.request({
method: 'POST',
url: 'https://www.example.com/tokens',
body: {
email: 'admin_username',
password: 'admin_password'
}
}).then((response) => {
cy.wrap(response).as('getAuthTokenResponse')
})
})
Cypress.Commands.add('createUser', (user) => {
cy.get('#getAuthTokenResponse').then((resp) => {
cy.request({
method: 'POST',
url: 'https://www.example.com/users',
headers: ({ Authorization: 'Bearer ' + resp.token }),
body: user
})
})
})
In your Test file you can just add:
cy.getAuthToken()
cy.createUser(user)

Cypress send multiple requests and doesn't allow to login

I am using Cypress 4.3.0 version, the baseUrl = "https://tenant-demo.somesitedev.net" has been set in cypress.json file. While I am sending the cy.request() command, it is sending multiple request (please see Fig:1) . Also, when I observed the visit command I could see following Original Url, Resolved Url and Redirects. In this scenario, how do I login to the site using cy.request() command.
before(()=>{
cy.visit('/').then(()=>{
cy.get('input[type="hidden"]').invoke('val').then((val)=>{
const token = val;
cy.login(token);
})
})
})
Cypress.Commands.add('login', (token) => {
const username= 'test1.user';
const password= 'somepassword';
const accessToken = localStorage.getItem('tokens');
const cookieValue = document.cookie.split(';');
const configCat = localStorage.getItem('ConfigCat_');
cy.request({
method: 'GET',
url: '/dashboard',
failOnStatusCode: false,
form: true,
body:{
_token: token,
username,
password
},
headers: {
'accept': 'text/html',
'content-type': 'application/x-www-form-urlencoded',
'authorization': `bearer ${accessToken}`,
'ConfigCat_': `${configCat}`,
'cookie': `${cookieValue}`
}
}).then((res)=>{
visitDashboard();
})
})
const visitDashboard = () => {
cy.visit('dashboard')
}
Fig:1
Fig:2
Somehow I managed to find a way to resolve the problem. Since the baseUrl has got some path extension /auth/login, whenever I trigger a cy.request() it was always redirecting back to login page even though the credentials was correct. Also there were two requests in the console.
So the way I did was to send another cy.request() with GET method with body params immediately after the first POST cy.request() with qs parameters. From the request headers I find out there was a 'token' submitted every time when the user login.
If there is another easy way let me know.
Cypress version : 4.4.0
Inside beforeEach(), grab the 'token' value;
beforeEach(() => {
cy.visit('/');
cy.loadTokens();
cy.get('input[name="_token"]').invoke('val').then((val)=>{
const tokenValue = val;
cy.loginRequest(tokenValue);
})
})
Following is the commands.js file:
Cypress.Commands.add('loginRequest', function (tokenValue) {
return cy.request({
method: 'POST',
url: Cypress.config('baseUrl'),
followRedirect: true,
headers: {
'content-type': 'text/html; charset=UTF-8'
},
qs:{
_token: tokenValue,
username: 'your_username',
password:'your_password'
}
}).then(()=>{
return cy.request({
method: 'GET',
url: 'https://tenant-demo.somesitedev.net/dashboard',
followRedirect: false,
headers: {
'content-type': 'text/html; charset=UTF-8'
},
body:{
_token: tokenValue,
username: 'your_username',
password:'your_password'
}
})
})
});

How to send x-csrf-token in a GET request?

I need to send the x-csrf-token along with the URL in a GET request. I am using request-promise nodejs package for this purpose, but I don't know how to do.
I need to do something like this:
return rp({
method: 'GET',
url: "https://alabbo.to/joiner?fid=5ba900635da0a&page=check",
CSRF: "Y5KLHznEcspsqDHgmy63UHvKZT8s48EuQ1bfv34n"
})
.then(function (html) {
}
CSRF is sent inside headers with key name X-CSRF-Token as shown below
return rp({
method: 'GET',
url: "https://alabbo.to/joiner?fid=5ba900635da0a&page=check",
headers: {
'X-CSRF-Token': "Y5KLHznEcspsqDHgmy63UHvKZT8s48EuQ1bfv34n"
}
}).then(function (html) {
})
Atishay is right, X-CSRF-Token is a header.
Otherway, is you use Node v8, you can use async / await instead of .then.
const response = await rp({
method: 'GET',
url: "https://alabbo.to/joiner?fid=5ba900635da0a&page=check",
headers: {
'X-CSRF-Token': "Y5KLHznEcspsqDHgmy63UHvKZT8s48EuQ1bfv34n"
}
})

Categories