baseURL
is set to: http://localhost:3000
cy.request()
is not setting cookies that comes with a domain.
cy.request()
should set cookies with specific domain.
describe('Cookie', () => {
Cypress.Cookies.debug(true);
it('SHOULD set the cookie if it have domain', () => {
cy.request({
method: 'POST',
url: 'http://localhost:3000/cookie-with-domain'
})
.then(()=> {
cy.getCookie('domain-cookie')
.should('have.property', 'value', '1');
});
});
it('Does set the cookie', () => {
cy.request({
method: 'POST',
url: 'http://localhost:3000/cookie-without-domain'
})
.then(()=> {
cy.getCookie('cookie')
.should('have.property', 'value', '1');
});
});
it('Works fine on both', () => {
cy.visit('http://localhost:3000/cookie-with-domain');
cy.visit('http://localhost:3000/cookie-without-domain');
cy.getCookie('domain-cookie')
.should('have.property', 'value', '1');
cy.getCookie('cookie')
.should('have.property', 'value', '1');
});
});
Using expressjs on the server and this:
app.all('/cookie-with-domain', (req, res)=>{
res.cookie('domain-cookie',1, { maxAge: 900000, httpOnly: true, domain: 'localhost'});
res.send('Hello!');
});
app.all('/cookie-without-domain', (req, res)=>{
res.cookie('cookie',1, { maxAge: 900000, httpOnly: true});
res.send('Hello!');
});
Cypress: 3.1.1
OS: Ubuntu 18.04
Browser: Chrome 71
@seromenho you are not on a domain when you used cy.getCookie()
, since you never used cy.visit()
in that test.
can you try adding cy.visit('/')
above the calls to cy.request?
@Bkucera I found this because on my tests when I was visiting a page the cookie was not set.
But still you can see that the second test passes and I've also never used cy.visit()
on that test.
I've added this to the tests and theres new screen shot and tests:
describe('Cookie', () => {
Cypress.Cookies.debug(true);
it('SHOULD set the cookie if it have domain', () => {
cy.request({
method: 'POST',
url: 'http://localhost:3000/cookie-with-domain'
})
.then(()=> {
cy.visit('http://localhost:3000/');
cy.getCookie('domain-cookie')
.should('have.property', 'value', '1');
});
});
it('Does set the cookie', () => {
cy.request({
method: 'POST',
url: 'http://localhost:3000/cookie-without-domain'
})
.then(()=> {
cy.visit('http://localhost:3000/');
cy.getCookie('cookie')
.should('have.property', 'value', '1');
});
});
it('Works fine on both', () => {
cy.visit('http://localhost:3000/cookie-with-domain');
cy.visit('http://localhost:3000/cookie-without-domain');
cy.getCookie('domain-cookie')
.should('have.property', 'value', '1');
cy.getCookie('cookie')
.should('have.property', 'value', '1');
});
});
@seromenho can you try running those tests independently of one another? you can put a .only
on them like this:
it.only('some test', ()=>{ ...
also can you show the cookie headers on each request?
thanks for the screenshots
@Bkucera same result.
can you show the cookie headers on each request?
i.e the "domain-cookie" vs the cookie without domain? That way we can hopefully reproduce this
@Bkucera
1st
{
"Request Body": null,
"Request Headers": {
"user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
"accept": "*/*",
"accept-encoding": "gzip, deflate",
"content-length": 0
},
"Request URL": "http://localhost:3033/cookie-with-domain",
"Response Body": "Hello!",
"Response Headers": {
"x-powered-by": "Express",
"access-control-allow-origin": "http://localhost:3033",
"access-control-allow-credentials": "true",
"set-cookie": [
"domain-cookie=1; Max-Age=900; Domain=localhost; Path=/; Expires=Tue, 29 Jan 2019 16:18:52 GMT; HttpOnly"
],
"content-type": "text/html; charset=utf-8",
"content-length": "6",
"etag": "W/\"6-aTQsXDnlrl8Ad67MMsD4GBH7gZM\"",
"date": "Tue, 29 Jan 2019 16:03:52 GMT",
"connection": "close",
"vary": "Accept-Encoding"
},
"Response Status": 200
}
2nd:
{
"Request Body": null,
"Request Headers": {
"user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
"accept": "*/*",
"accept-encoding": "gzip, deflate",
"content-length": 0
},
"Request URL": "http://localhost:3033/cookie-without-domain",
"Response Body": "Hello!",
"Response Headers": {
"x-powered-by": "Express",
"access-control-allow-origin": "http://localhost:3033",
"access-control-allow-credentials": "true",
"set-cookie": [
"cookie=1; Max-Age=900; Path=/; Expires=Tue, 29 Jan 2019 16:22:41 GMT; HttpOnly"
],
"content-type": "text/html; charset=utf-8",
"content-length": "6",
"etag": "W/\"6-aTQsXDnlrl8Ad67MMsD4GBH7gZM\"",
"date": "Tue, 29 Jan 2019 16:07:41 GMT",
"connection": "close",
"vary": "Accept-Encoding"
},
"Response Status": 200
}
thanks @seromenho, doesn't seem like a very high priority for us ATM, but I think this will get looked at along with https://github.com/cypress-io/cypress/issues/687
For information, this issue appears to be complete killing my ability to use Cypress against our application (and appreciate that this could be a limitation due to how our app works).
During the tests we need to interact with our API as an Administrator to create specific organizations to isolate tests. Once that's done we shift to a specific tenant domain which responds correctly with a domain cookie in the response header. The tenant domain cookie isn't set, and we end up with unauthenticated errors.
I've tried working around this by parsing the set-cookie header and then setting a cookie with the following code (without any luck so far):
cy.setCookie(name, value, {options}).then( () => {
cy.getCookies(); // The new cookie are shown in the Cypress log
cy.request(somePath); // This call doesn't have the new cookie
})
I figured the above would work...but no luck yet.
Put the use of the emotive "killing" down to a tough weekend banding my head against this. It's certainly made it tougher, and a little more long winded, but killing was a bit extreme.
To add something more constructive to the conversation, I have managed to work around this in my interaction with our backend API by ensuring that during a login call, we set the authorization token for a user, then force cy.request
to use that with appropriate headers.
The final workaround is to set the cookie with JavaScript when the visit yields. It's not quite as the same as the domain part of the cookie isn't honoured but it does at least get us testing without having to login via the interface each time.
Keep up the good work! It's a pleasure working with Cypress, even with these frustrations :)
It looks like I am facing the same problem. However to me it seems that the error only happen if Domain="localhost"
is set. If the Domain=
is present and set to something else cookies are set as expected.
Our work around is setting the cookie without domain
cy
.request({
url: `${backendHost}/api/v2/user`,
method: 'POST',
body: {
email: `${uuid()}@test.ru`,
...details,
},
auth,
})
.then(response => {
return cy.getCookie('session_id')
})
.then(({ headers, body }) => {
const cookieHeader = headers['set-cookie'].map(cookie =>
cookie.split('; ')[0].split('='),
)[0];
return cy.setCookie(cookieHeader[0], cookieHeader[1])
.then(() => body);
})
@rewop It doesn't seems to be only on localhost. Locally we are using custom domains and it doesn't work also. Domain on my sample was just for demo.
Your workaround of manually set the cookies works very well. We are doing that also for the time being.
Ty
I can confirm that this happens not only with localhost but with any custom domains.
I was migrating tests to run on docker, and previously, the domain was lvh.me (a real domain, just has a DNS pointing at 127.0.0.1), which worked.
Any action to fix this yet? :(.
This issue is still in the 'ready for work' stage, which means no work has been done on this issue as of today, so we do not have an estimate on when this will be delivered.
My workaround, which is similar to @rewop 's one:
Cypress.Commands.add('loginNoUi', (email, password) => {
// Regular form POST
cy.request({
method: 'POST',
form: true,
followRedirect: false,
url: '/login',
body: {
username: email,
password: password
}
}).then((response) => {
//Extract cookie value from response's "set-cookie" header.
const token = response.headers['set-cookie'][0].replace('SM_SESSION=', '').split(';')[0];
//Set the cookie explicitly
cy.setCookie('SM_SESSION', token);
// Attach 'Cookie' header manually and go to main page of application. It's possible to navigate everywhere from there.
cy.visit('/', {headers: {'Cookie': `SM_SESSION=${token}`}});
});
});
After that, I use the regular page navigation with a click() function and navigation works correctly.
In my opinion, there are two problems here:
1) cy.request()
does not set cookies automatically (login endpoint responds with HTTP 302 and cookie with domain name set)
2) cy.visit()
does not attach cookies automatically
I hope I saved someone hours of experimenting.
Same problem, but it happens only with .local
domain for me and when I make a cookie accessible for all subdomains (.cypress.local
) but when I set .cypress.biz
(or any another domain) - all ok.
It started from 3.1.1 version and from this version I can't update Cypress.
I record gifs with small tests:
Version 3.1.0
- all ok, I set 2 cookies an get 2 cookies.
Version 3.1.1+
(3.3.0) - I set 2 cookies an get 1 cookie, cookie with domain .cypress.local
removed.
Backend the same, I just type in /etc/hosts
:
127.0.0.1 cypress.local cypress.biz
And tests was:
describe('Cookies bug', function() {
Cypress.Cookies.debug(true)
it('Domain .biz', function() {
cy.visit('http://cypress.biz:8000/?page=set'); // set cookies
cy.wait(2000); // just for me
cy.visit('http://cypress.biz:8000/?page=get'); // get cookies
})
it('Domain .local', function() {
cy.visit('http://cypress.local:8000/?page=set');
cy.wait(2000);
cy.visit('http://cypress.local:8000/?page=get');
})
})
@YaroslavMolchan domain name ending with ".local" may be the cause. In my case, I also use .local domain setup statically in /etc/hosts
@j-gurda its problem for me only if I set cookie for subdomains like .domain.local
(starts from dot), now I create cookie only for current domain domain.local
(without dot) and all works fine.
@YaroslavMolchan Thank you for narrowing this down to a specific version. Changes made in 3.1.1 involving cookies:
Fixed a bug where Cypress would error when a secure cookie flag was set and then expired from an HTTPS url without the subsequent secure flag. Due to the way Cypress was constructing the url, this would fail to actually remove the cookie. Fixes #1264, #1321, #1799.
This boils down to the changes made in this PR https://github.com/cypress-io/cypress/pull/2685 which I think boils down even further to this commit: https://github.com/cypress-io/cypress/pull/2685/commits/b31782d23e5d57ef07d96f049106b8841f849fb5
Hello team,
Do you have any news about this regression?
Unfortunately, the workarounds are not the final solution.
Thanks for information.
I just checked the reproducible example provided in the OP and it appears to be fixed starting with Cypress 3.5.0. Please upgrade your version of Cypress to the latest to get the fix for this issue.
Most helpful comment
Hello team,
Do you have any news about this regression?
Unfortunately, the workarounds are not the final solution.
Thanks for information.