I am playing around with Cypress for e2e testing and want to execute login flow on each of the spec file.
I know that we can do it by storing it locally by writing custom commands like this :
Cypress.Commands.add('login', ()=> {
cy.request({
method : 'POST',
url : 'url',
...
}
}).then((resp) => {
window.localStorage.setItem('jwt',resp.body.user.token)
})
})
and then calling this function in our actual spec file.
But with my application, there are multiple api calls to be made one after the other in order to actually land up inside the application. How can I achieve this in custom commands? My application actually takes username and password in step-1, and then from the jwt received it executes another api call, and then a final one. I want to store the last jwt value so that I can continue with the rest of the application.
You can parameterize your cypress custom commands, so from the test spec file you can just pass the URL.
Custom Command:
Cypress.Commands.add('login', (url) => {
cy.request({
method: 'POST',
url: URL,
...
}).then((resp) => {
window.localStorage.setItem('jwt', resp.body.user.token)
})
})
In your test write:
cy.login('https://example1.com')
cy.login('https://example2.com')
....
The requests can be nested,
Cypress.Commands.add('login', () => {
cy.request({
method : 'POST',
url : 'url1',
...
})
.then((resp1) => {
cy.request({
method : 'POST',
url : 'url2',
body : { token: resp1.body.user.token }
})
.then((resp2) => {
cy.request({
method : 'POST',
url : 'url3',
body : { token: resp2.body.user.token }
})
.then((resp3) => {
window.localStorage.setItem('jwt', resp3.body.user.token)
})
})
})
})
Related
after hook doesnt work for the first time in cypress but when i retry, it works. in the after hook i call a cy.request and i get a token from another request . i run the token request in before all the tests to make sure i got the token here is the code in the main tests
describe('test', () => {
before(() => {
Login.userLg();
});
it('first test', () => {
cy.visit('`url`);
// some code to test
});
// delete user
afterEach(() => {
user.delete();
});
});
here is the code of the user function in another file (tokenFile)
delete() {
failOnStatusCode: false
cy.request({
method: 'PATCH',
url: `url`,
headers: {
Authorization: 'Bearer ' + Cypress.env('token'),
},
body: {
name: user,
},
});
}
here is the code to get the token in a third file
describe('token', () => {
it('get operator token', () => {
cy.request({
method: 'POST',
url: 'url',
form: true,
body: {
grant_type: 'password',
username: 'user',
password: 'pass',
},
}).then((response) => {
Cypress.env('token', response.body.token);
});
});
});
i call the token request in support/e2e.ts
import './tokenFile';
i tried to put the fucntion in after hook ,put in before hook before login , also i tried afterEach and it didn'T work , i tried to put the token request in command file . nothing works
You should really clear state before tests run rather than after. This is in the official Cypress docs:
https://docs.cypress.io/guides/references/best-practices#Using-after-or-afterEach-hooks
One other benefit of doing this is that if you have a test failure you preserve all the data that the test failed with meaning you can debug the issue.
Hello so am relatively new to using intercept on cypress.
Clicking a button sends a request. Intercepting and not stubbing (//1) lets me retrieve the date value in the response seen in cy.log($resp.response), but I need to stub a response too (//2) this fails to return a date value in the cy.log($resp.response). The data value is generated as it is seen in the UI
How can I retrieve the response and still stub?
cy.intercept({method: 'POST', url: '**/myURL'}).as('successfulAction') //1
cy.intercept({method: 'POST', url: '**/myURL'},{stubbed data}).as('successfulAction') //2
cy.get('button').click()
cy.wait('#successfulAction').then(($resp) => {
cy.log($resp.response)
})
On the first intercept, add the middleware flag.
This allows the true request to be caught, but pass the request on to the 2nd intercept which applies stubbed data.
cy.intercept({
method: 'POST',
url: '**/myURL',
middleware: true
}).as('successfulAction')
cy.intercept({method: 'POST', url: '**/myURL'}, {stubbed data}) // no alias needed
cy.wait('#successfulAction')
.then(($resp) => {
cy.log($resp.response)
})
You can also use a single intercept
cy.intercept({
method: 'POST',
url: '**/myURL',
middleware: true
}).(req => {
req.continue(resp => {
cy.log($resp.response)
res = stubbedData
})
})
.as('successfulAction')
Thanks for the answers I definitely gave me an idea and the below works.
cy.intercept({
method: 'POST',
url: `**/${parentAlarmsAssetsData[0].AssetNumber}`,
middleware: true
},(req) => {
req.continue((res) => {
res.send({ //add stubbed data
statusCode: 200,
body: {
"status":true,
"responseMessage":null
}
})
})
}).as('successfulAction')
cy.get(manualCheckButton).click()
cy.wait('#successfulAction').then(($resp) => {
acknowledgedDateTime = $resp.response.headers.date //set global var
})
How can I access the token parsed from JSON response
const getToken = () =>
cy.request({
method: 'GET',
url: '/generateToken'
});
.its('body')
.then((response) => {
JSON.parse(response)
token = token['accessToken'] //How can I access this token value to use in other It tests?
})
You could use this approach:
const getToken = () => {
cy.request({
method: 'GET',
url: '/generateToken'
}).its('body').then(function(response) {
json = JSON.parse(response)
this.token = json['accessToken']
})
}
// Afterwards...
it('should xxxxxxxx xxx xxx', () => {
console.log(this.token)
});
Please note that accessing aliases as properties with this.* will not work if you use arrow functions =>, this is the reason why I used function.
For one of my web service testing, I need to read an xml file and assign the contents of the same to cy.request body.
How can I achieve this?
I tried the below method and was not able to successfully pass the XML to the body.
Please let me know.
eg:
cy.readFile('Desktop/Testing/W1.xml')
.then(text1 => {
console.log(text1);
cy
.request({
url: 'my URL',
method: 'POST',
body: {text1},
headers: {
'Authorization':'Basic ........',
'content-type': 'application/......-v1.0+xml',
'Accept':'application/...v1.0+json,application/....-v1.0+json'
}
})
.then((response) => {
assert.equal(response.status, 200, "status was 200");
cy.log("Response Body",response.body);
console.log("Response Body",response.body);
})
})
I suggest something like this:
Prepare function for fetching XML
function fetchXML(text) {
return cy.request({
url: 'my URL',
method: 'POST',
body: text,
headers: { ... }
})
}
Then call readFile and pass to promise callback result
cy
.readFile('Desktop/Testing/W1.xml')
.then(text => fetchXML(text)) // or just .then(fetchXML)
.then(responseFromXML => { ... })
and i second callback you can use response from XML fetch
Link to docs about Cypress.Promise LINK
I've got a react/d3 project where I'm using axios.get to retrieve my data passed into a local url with express. Here is my code :
return axios.get("http://localhost:3000/gadata")
.then(response => {
dispatch({
type: 'FETCH_DATA_SUCCESS',
isFetching: false,
data: response.data.rows
});
})
Instead of axios, I would like to be able to use d3-request. How should I refactor my code ?