Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default headers for cy.request command #726

Open
MaxNamazov opened this issue Oct 11, 2017 · 15 comments
Open

Default headers for cy.request command #726

MaxNamazov opened this issue Oct 11, 2017 · 15 comments
Labels
pkg/driver This is due to an issue in the packages/driver directory stage: proposal 💡 No work has been done of this issue type: enhancement Requested enhancement of existing feature

Comments

@MaxNamazov
Copy link

MaxNamazov commented Oct 11, 2017

Current behavior:

There is no possibility to add default headers for the cy.request command. The only way to add such headers is to overwrite this command

Desired behavior:

The possibility to set default headers (and maybe some other default options) for the cy.request command.
For example, we use SessionId header for authenticated requests in our app. And I would like to implement custom login command for my tests, so it would set this header as default for all subsequent requests.

@jennifer-shehane jennifer-shehane added the type: feature New feature that does not currently exist label Oct 11, 2017
@jennifer-shehane jennifer-shehane added the pkg/driver This is due to an issue in the packages/driver directory label Nov 14, 2017
@wawhal
Copy link

wawhal commented May 25, 2018

Any update about this? @jennifer-shehane?

@jennifer-shehane
Copy link
Member

Let me make sure I accurately understand your feature request.

You are able to set headers within the cy.request() options object as documented here, but you would like 1 place to set the headers to affect all cy.request() done, similar to how cy.server() options affect routes and requests?

If this is the case, there is already a headers key on cy.server() that is solely used on stubbed cy.route(), we'd have to resolve this conflict somehow or implement some other way.

@mattvb91
Copy link

👍 for this. Would like to also have the option to globally set headers for all cy.visit() requests.

@Qwal
Copy link

Qwal commented Nov 30, 2018

As a workaround I overwrite cy.request method with my custom command:

Cypress.Commands.overwrite('request', (originalFn, ...options) => {
  const optionsObject = options[0];

  if (optionsObject === Object(optionsObject)) {
    optionsObject.headers = {
      authorization: 'Bearer YOUR_TOKEN',
      ...optionsObject.headers,
    };

    return originalFn(optionsObject);
  }

  return originalFn(...options);
});

Please note it only works if you use cy.request with options object.

@jennifer-shehane jennifer-shehane added stage: proposal 💡 No work has been done of this issue type: enhancement Requested enhancement of existing feature external: documentation and removed type: feature New feature that does not currently exist labels Feb 19, 2019
@GuilhermeAOliveira
Copy link

GuilhermeAOliveira commented Jul 12, 2019

I did my request like this, and it works very well(GET request):

it('myFunction()', function(){
        cy.request(
            {
                url: 'https://url-you-want-to-request',
                headers : {
                    'Service-Provider-Id' : 'name-etc',
                    'Client-Realm-Id': 'bla bla bla-',
                    'Application-Id': 'bla bla bla',
                    'Frontend-Id': 'XXX',
                    'Device-Id': 'device-id-number-etc',
                    'CID': 'co-relation-id-number-',
                }
            }
        )
    })

@andywarren86
Copy link

andywarren86 commented Aug 19, 2019

Similar to @Qwal's comment, I created a custom request() command by overwriting the original, so I could set default options on the request (in this case basic auth headers).

This implementation supports the following usage patterns:
cy.request( options )
cy.request( url )
cy.request( method, url )
cy.request( method, url, body )

import _ from 'lodash';

// Overwrite cy.request() to set default options
Cypress.Commands.overwrite('request', (originalFn, ...args) => {
  const defaults = {
    auth: {
      user: 'admin',
      pass: 'password1'
    }
  };

  let options = {};
  if (_.isObject(args[0])) {
    options = Object.assign({}, args[0]);
  } else if (args.length === 1) {
    [options.url] = args;
  } else if (args.length === 2) {
    [options.method, options.url] = args;
  } else if (args.length === 3) {
    [options.method, options.url, options.body] = args;
  }

  return originalFn(Object.assign({}, defaults, options));
});

I copied the logic from the base implementation of cy.request():
https://github.com/cypress-io/cypress/blob/develop/packages/driver/src/cy/commands/request.coffee#L61

@justin808
Copy link

Similar to this feature request, is there some way to set default headers for cy.visit?

@san-slysz
Copy link

san-slysz commented Mar 20, 2020

As I use the cucumber plugin, I did the following within a hooks.js file (next to your given.js, ... files)

import {ENV} from "../../../env";

const {
    Before,
} = require("cypress-cucumber-preprocessor/steps");

const headers = {
    'My-header-username': 'plop',
    'My-header-Id': 1
};

//Before all
Before( () => {
    Cypress.config('baseUrl', Cypress.env(`${ENV}BaseUrl`));
    cy.wrap(headers).as('defaultHeaders'); // See usage below, in the step
});

Before({tags: '@oauth2'}, () => {
    headers['My-Oauth2-Header'] = 'oauth2';
    headers['My-Needed-Key'] = Cypress.env(`${ENV}Key`);
});

Before({tags: '@jwt'}, () => {
    headers['My-Jwt-Header'] = 'jwt';
});
When(/^I do something$/, function () { // Don't use fat arrow here, as we use this. below
    
    cy.request({
        method: GET,
        url: /myurl,
        headers: this.defaultHeaders // Here is why I used cy.wrap() in the global before hook
    }).then( (response) => {
        cy.wrap(response).its('status').as('responseStatusCode');
        cy.wrap(response).its('headers').as('responseHeaders');
        cy.wrap(response).its('body').as('responseBody');
        cy.wrap(response).its('duration').as('responseDuration');
    })
});

Depending of the scenario tags, we'll either get the oauth2 or jwt headers. We'll always get the baseUrl one.

This is a dumb exemple of what can be done using global or tag-related befores. Hope this helps someone. This can work with cy.request(), cy.visit(), ... and does not need to redefine any of those. Which is great. But it does require cucumber.

@shahiddev
Copy link

shahiddev commented Sep 17, 2020

We're using Cypress for some API testing and not having an easy way of setting a bearer token globally to the cy.request is a pain. I'll look at @Qwals approach as a stop gap but it feels like a missing feature to be able to specify this somewhere once rather than having to add the header to every cy.request.

@hamidgh
Copy link

hamidgh commented Oct 27, 2020

I found a workaround for it:

cy.server({
       onAnyRequest:   function (route,  proxy) {
           proxy.xhr.setRequestHeader('CUSTOM-HEADER',  'Header value');
     }
});

@pitpit
Copy link

pitpit commented Jan 12, 2021

here's an updated version of #726 (comment)
without lodash and deepmerging headers

// Overwrite cy.request() to set default options
Cypress.Commands.overwrite('request', (originalFn, ...args) => {
  const defaults = {
    headers: {
      'Accept': 'application/json'
    }
  };

  let options = {};
  if (typeof args[0] === 'object' && args[0] !== null) {
    options = args[0];
  } else if (args.length === 1) {
    [options.url] = args;
  } else if (args.length === 2) {
    [options.method, options.url] = args;
  } else if (args.length === 3) {
    [options.method, options.url, options.body] = args;
  }

  return originalFn({...defaults, ...options, ...{headers: {...defaults.headers, ...options.headers}}});
});

@maneeshpal
Copy link

Based on @pitpit 's cy.request() example, here is one for cy.visit()

 Cypress.Commands.overwrite('visit', (originalFn, ...args) => {
    const defaults = {
        headers: {
            'Accept': 'application/json'
        }
    };
  
    let options = {};
    if (typeof args[0] === 'object' && args[0] !== null) {
        // cy.visit(options)
        options = args[0];
    } else if (args.length === 1) {
        // cy.visit(url)
        [options.url] = args;
    } else if (args.length === 2) {
        // cy.visit(url, options)
        options = { ...args[1], url: args[0] };
    }
  
    return originalFn({...defaults, ...options, ...{headers: {...defaults.headers, ...options.headers}}});
});

@uebayasi
Copy link

uebayasi commented Jul 7, 2021

Not tried yet, but according to the following, cy.intercept() might help.

https://docs.cypress.io/api/commands/intercept#Request-Response-Modification-with-routeHandler

@spatwardhan-tcs
Copy link

@jennifer-shehane Any update on this?

@sruffing-te
Copy link

Not tried yet, but according to the following, cy.intercept() might help.

https://docs.cypress.io/api/commands/intercept#Request-Response-Modification-with-routeHandler

https://docs.cypress.io/api/commands/request#cyintercept

cy.request does not go through intercept

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pkg/driver This is due to an issue in the packages/driver directory stage: proposal 💡 No work has been done of this issue type: enhancement Requested enhancement of existing feature
Projects
None yet
Development

No branches or pull requests