Reputation: 4264
I'm currently testing a couple of microservices using Cypress. To test the REST api's, I need a token to make the requests. This token is available only via a local FE - image given below
I have to access this FE to fetch the token only - there is no other way to access this access token.
Right now I'm doing it like this
describe('Do some test',()=>{
it('first test',()=>{
//this fetches the value of the token from FE.
cy.get('css locator of the access token').invoke('val').then((token)=>{
let tok = token;
cy.request({
method: 'GET' //or POST
url: "http://localhost:3001/v1/api1.json",
headers:{
"Authorization": "Bearer "+token;
"Content-Type":"application/json"
}
}).as('firsttest').then(()=>{
cy.get('@firsttest').its('status').should('eql',200);
})
})
})
})
Now this works and I get the correct status and all, but I know this is not a good way of organising tests and also it leads to a lot of duplication, because I have to fetch the token again and again if I am moving out of the it
block.
How can I organise this in a way that I can fetch the token
value once and then use it in my tests.. some thing like this
describe('Do first test',()=>{
beforeEach(()=>{
cy.get('get locator of the token').invoke('val').then((token)=>{
let tok = token;
})
})
it('fetch and use token',()=>{
cy.request({
method: 'GET' //or POST
url : 'http://someurl/path',
headers :{
"Authorization": "Bearer "+token; (from beforeEach block)
}
})
})
it('do another test using same token',()=>{
//do something
})
})
Or further simply in such a way that the duplicity of getting the the token
is minimised.
Upvotes: 0
Views: 240
Reputation: 7286
Elaborating on the comments, here's a working example. It presupposes that the UI containing the token will always exist in every test.
Trouble with this solution is that putting the token-retrieval logic into beforeEach
will effectively prevent cy.visit
at the start of test. So, either put the cy.visit
into the beforeEach
(above the cy.get()
), or come up with a different solution.
// cypress/support/index.js
// override the `cy.request` to automatically supply the Authorization header
// ----------------------------------------------------------------------
const AuthorizationToken = Symbol();
Cypress.Commands.overwrite('request', (origFn, ...args) => {
// normalize arguments
// --------------------------------------------------------------------
let opts;
if ( args.length === 1 ) {
opts = typeof args[0] === 'string' ? { url: args[0] } : args[0];
} else {
opts = args.length === 2
? { url: args[0], body: args[1] }
: { method: args[0], url: args[1], body: args[2] }
}
// set the Auhtorization header (if exists)
// --------------------------------------------------------------------
if ( cy.request[AuthorizationToken] ) {
opts.headers = {
'Authorization': 'Bearer ' + cy.request[AuthorizationToken],
...opts.headers
};
}
// --------------------------------------------------------------------
return origFn(opts);
});
beforeEach(() => {
// (1) setup (for demonstraion purposes)
// ----------------------------------------------------------------------
cy.document().then( doc => {
doc.body.innerHTML = '<div class="token">2as24flx9</div>';
});
// (2) actual code
// ----------------------------------------------------------------------
cy.get('.token').invoke('text').then( token => {
cy.request[AuthorizationToken] = token;
});
});
Upvotes: 0
Reputation: 2133
you can create a custom method inside support/command.js. for example ,here a custom method named 'Newlogin' has been created
Cypress.Commands.add('Newlogin', (email, password,env) => {
Cypress.log({
name: 'loginViaAuth0',
});
const options = {
method: 'POST',
url: env+'/oauth/token', // Token Url
failOnStatusCode: false,
form:true,
"body":'grant_type=password&userName='+email+'&Password='+password+'
};
cy.request(options)
});
Now you can access this method anywhere chaining with cy. for example
cy.Newlogin(username, password, env) /*Custom method defined in supports/command.js */
.its('body')
.then((resp) => {
resp = JSON.stringify(resp)
cy.log(resp)
const token = JSON.parse(resp).access_token
});
Upvotes: 1