demouser123
demouser123

Reputation: 4264

Organising tests in better way using a token from FE

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

Token Image

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

Answers (2)

dwelle
dwelle

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

Prany
Prany

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

Related Questions