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

Cookies not being set after cy.request() even though set-cookie is present in response header #1074

Closed
DanielSwain opened this issue Dec 14, 2017 · 8 comments

Comments

@DanielSwain
Copy link

DanielSwain commented Dec 14, 2017

  • Operating System: Win10
  • Cypress Version: 1.1.4
  • Browser Version: Chrome 63
  • Server: Ubuntu 14/Apache hosted on a Vagrant-based VirtualBox
  • Server App Language: Django

Current behavior:

I have the following custom command to perform a login and am running it from a simple test (with username/password being supplied from Cypress.env variables):

Cypress.Commands.add("login", (username, password) => {
    cy.request({
        method: 'POST',
        form: true,
        url: `${Cypress.env("host")}${Cypress.env("login_url")}`,
        body: {'username': username, 'password': password}
    })
})
    it('tests login', function() {
        cy.login(Cypress.env("username"), Cypress.env("password"))
        cy.getCookie('csrftoken')
        .then((csrftoken) => {
            console.log(csrftoken)
        })
    })

A 200 status is returned, and in both the request and response in Chrome Dev Tools, the cookies appear as expected:

image

However, the cookies are not being set in the browser even though they're coming back in the response header. I'm console logging the cookie value after cy.login() executes in order to verify the absence/presence of cookies:

image

image

In the Django backend I have verified that the user is, in fact, being logged in. This Django logged-in state is verified by the presence of the sessionid that Django includes with the response after a successful login along with the csrftoken that it always passes (whether logged in or not).

I have a smoke test set up to test login functionality using cy.visit(), and cookies are set fine after execution of cy.visit():
image

Am I missing something, or is cy.request() perhaps not always handling the setting of cookies correctly?

@brian-mann
Copy link
Member

cy.request() definitely sets cookies correctly - so there must be an edge case here.

I'm going to guess and say that the URL you are making the cy.request to DOES NOT MATCH the current origin you're testing - which would explain why the browser wouldn't display them.

Whenever you look at the Cookies in the browser it is always partitioned by origin policy.

What is the URL that you are cy.visit() ? That will determine whether or not there should be cookies.

Also you can use Cypress.Cookies.debug(true) before you run any of your tests and Cypress will log out every single cookie mutation in your console. You will see everything that gets modified there.

@brian-mann
Copy link
Member

Actually yes I can tell in your image this is exactly what is happening. You are inspecting cookies for localhost:61712 and yet you are visiting localhost:8090.

These origins do not match and cookies are not applied between them. However cy.request does correctly set cookies for the origin of ITS request. So those cookies are in the jar, but until you visit that origin in the browser you will not see them.

@brian-mann
Copy link
Member

cy.request() will always set cookies to the origin it was sent to.

cy.request('https://google.com') will set cookies for that origin. So if you are visiting http://localhost:1234 you will not see those cookies in the browser where the Application dev tools tab is.

@brian-mann
Copy link
Member

However if you were to then visit https://google.com in your browser, you would see the cookies that were set from cy.request because Cypress correctly sets these on the browser session for the origin they would be applied to.

@brian-mann
Copy link
Member

Also - this is likely happening to you because when Cypress starts it starts on a random port if you have not set baseUrl.

What you're likely doing is immediately making a request to programmatically log in a user. This works, you just wont "see" the cookies until you then visit your origin.

If you set baseUrl then Cypress starts there and then you'll immediately see cookies.

@DanielSwain
Copy link
Author

Your last comment describes the problem exactly. Seems like my situation fell somewhere BETWEEN points 2 and 3 here though - the first command I issue is cy.request() in order to do a login, and my cy.request() as called includes the host, so Cypress didn't error out. However, I did not have a baseUrl set, and so my call to getCookie() was fruitless (cookieless?). Setting baseUrl fixed the issue, but I would like to propose a small addition to the docs in order to spare other users the quandary I experienced here.

@DanielSwain
Copy link
Author

Also, I did have host set in cypress.env.json, but that setting is apparently being ignored by cy.request(). Should cy.request() look at cypress.env.json when trying to determine the host? However, I know you've talked about just eliminating cypress.env.json here.

@brian-mann
Copy link
Member

Cypress does not do anything meaningful or ever look at environment variables you've set.

So host is just as meaningless to Cypress as foo is. What you're describing literally is the use case of baseUrl - which does have significant meaning.

It's actually an antipattern to use something like host in replacement of baseUrl. One is configuration, the other is an environment variable - and Cypress does special things with baseUrl.

We recently updated the docs to note that here: https://docs.cypress.io/guides/guides/environment-variables.html#

I'm going to move that section into Best Practices soon, and call this out explicitly. We've seen other users do the same anti pattern.

As a final note - you didn't ever really need the cy.getCookie(...) in the first place. Because cy.request() yields you the response data - you could just pluck out the cookie value yourself directly out of the response headers, thus avoiding the need to be on the same origin as the request.

Setting baseUrl is definitely the much better approach - but if this comes up in the future and you need access to cookies from another origin, that's the way you should do it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants