2020-08-03 13:41:48 -07:00
/ * *
* Copyright 2018 Google Inc . All rights reserved .
* Modifications copyright ( c ) Microsoft Corporation .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* /
2020-09-02 21:43:38 -07:00
2022-03-25 15:05:50 -08:00
import { contextTest as it , expect } from '../config/browserTest' ;
2020-08-03 13:41:48 -07:00
2021-09-27 18:58:08 +02:00
it ( 'should return no cookies in pristine browser context' , async ( { context , page , server } ) = > {
2020-08-03 13:41:48 -07:00
expect ( await context . cookies ( ) ) . toEqual ( [ ] ) ;
} ) ;
2022-03-10 19:42:52 +01:00
it ( 'should get a cookie @smoke' , async ( { context , page , server , defaultSameSiteCookieValue } ) = > {
2020-08-03 13:41:48 -07:00
await page . goto ( server . EMPTY_PAGE ) ;
const documentCookie = await page . evaluate ( ( ) = > {
document . cookie = 'username=John Doe' ;
return document . cookie ;
} ) ;
expect ( documentCookie ) . toBe ( 'username=John Doe' ) ;
expect ( await context . cookies ( ) ) . toEqual ( [ {
name : 'username' ,
value : 'John Doe' ,
domain : 'localhost' ,
path : '/' ,
expires : - 1 ,
httpOnly : false ,
secure : false ,
2021-12-15 17:33:09 -08:00
sameSite : defaultSameSiteCookieValue ,
2020-08-03 13:41:48 -07:00
} ] ) ;
} ) ;
2022-06-16 10:36:37 -07:00
it ( 'should get a non-session cookie' , async ( { context , page , server , defaultSameSiteCookieValue } ) = > {
2020-08-03 13:41:48 -07:00
await page . goto ( server . EMPTY_PAGE ) ;
// @see https://en.wikipedia.org/wiki/Year_2038_problem
const date = + ( new Date ( '1/1/2038' ) ) ;
const documentCookie = await page . evaluate ( timestamp = > {
const date = new Date ( timestamp ) ;
document . cookie = ` username=John Doe;expires= ${ date . toUTCString ( ) } ` ;
return document . cookie ;
} , date ) ;
expect ( documentCookie ) . toBe ( 'username=John Doe' ) ;
2022-05-19 10:29:44 -06:00
const cookies = await context . cookies ( ) ;
expect ( cookies . length ) . toBe ( 1 ) ;
expect ( cookies [ 0 ] ) . toEqual ( {
2020-08-03 13:41:48 -07:00
name : 'username' ,
value : 'John Doe' ,
domain : 'localhost' ,
path : '/' ,
2022-05-19 10:29:44 -06:00
// We will check this separately.
expires : expect.anything ( ) ,
2020-08-03 13:41:48 -07:00
httpOnly : false ,
secure : false ,
2021-12-15 17:33:09 -08:00
sameSite : defaultSameSiteCookieValue ,
2022-05-19 10:29:44 -06:00
} ) ;
// Browsers start to cap cookies with 400 days max expires value.
// See https://github.com/httpwg/http-extensions/pull/1732
// Chromium patch: https://chromium.googlesource.com/chromium/src/+/aaa5d2b55478eac2ee642653dcd77a50ac3faff6
// We want to make sure that expires date is at least 400 days in future.
const FOUR_HUNDRED_DAYS = 1000 * 60 * 60 * 24 * 400 ;
const FIVE_MINUTES = 1000 * 60 * 5 ; // relax condition a bit to make sure test is not flaky.
expect ( cookies [ 0 ] . expires ) . toBeGreaterThan ( ( Date . now ( ) + FOUR_HUNDRED_DAYS - FIVE_MINUTES ) / 1000 ) ;
2020-08-03 13:41:48 -07:00
} ) ;
2021-09-27 18:58:08 +02:00
it ( 'should properly report httpOnly cookie' , async ( { context , page , server } ) = > {
2020-08-03 13:41:48 -07:00
server . setRoute ( '/empty.html' , ( req , res ) = > {
res . setHeader ( 'Set-Cookie' , 'name=value;HttpOnly; Path=/' ) ;
res . end ( ) ;
} ) ;
await page . goto ( server . EMPTY_PAGE ) ;
const cookies = await context . cookies ( ) ;
expect ( cookies . length ) . toBe ( 1 ) ;
expect ( cookies [ 0 ] . httpOnly ) . toBe ( true ) ;
} ) ;
2021-09-27 18:58:08 +02:00
it ( 'should properly report "Strict" sameSite cookie' , async ( { context , page , server , browserName , platform } ) = > {
2021-04-02 21:07:45 -07:00
it . fail ( browserName === 'webkit' && platform === 'win32' ) ;
2020-08-03 13:41:48 -07:00
server . setRoute ( '/empty.html' , ( req , res ) = > {
res . setHeader ( 'Set-Cookie' , 'name=value;SameSite=Strict' ) ;
res . end ( ) ;
} ) ;
await page . goto ( server . EMPTY_PAGE ) ;
const cookies = await context . cookies ( ) ;
expect ( cookies . length ) . toBe ( 1 ) ;
expect ( cookies [ 0 ] . sameSite ) . toBe ( 'Strict' ) ;
} ) ;
2021-09-27 18:58:08 +02:00
it ( 'should properly report "Lax" sameSite cookie' , async ( { context , page , server , browserName , platform } ) = > {
2021-04-02 21:07:45 -07:00
it . fail ( browserName === 'webkit' && platform === 'win32' ) ;
2020-08-03 13:41:48 -07:00
server . setRoute ( '/empty.html' , ( req , res ) = > {
res . setHeader ( 'Set-Cookie' , 'name=value;SameSite=Lax' ) ;
res . end ( ) ;
} ) ;
await page . goto ( server . EMPTY_PAGE ) ;
const cookies = await context . cookies ( ) ;
expect ( cookies . length ) . toBe ( 1 ) ;
expect ( cookies [ 0 ] . sameSite ) . toBe ( 'Lax' ) ;
} ) ;
2022-03-01 01:17:33 -07:00
it ( 'should get multiple cookies' , async ( { context , page , server , defaultSameSiteCookieValue } ) = > {
2020-08-03 13:41:48 -07:00
await page . goto ( server . EMPTY_PAGE ) ;
const documentCookie = await page . evaluate ( ( ) = > {
document . cookie = 'username=John Doe' ;
document . cookie = 'password=1234' ;
return document . cookie . split ( '; ' ) . sort ( ) . join ( '; ' ) ;
} ) ;
2021-02-19 11:50:59 -08:00
const cookies = new Set ( await context . cookies ( ) ) ;
2020-08-03 13:41:48 -07:00
expect ( documentCookie ) . toBe ( 'password=1234; username=John Doe' ) ;
2021-02-19 11:50:59 -08:00
expect ( cookies ) . toEqual ( new Set ( [
2020-08-03 13:41:48 -07:00
{
name : 'password' ,
value : '1234' ,
domain : 'localhost' ,
path : '/' ,
expires : - 1 ,
httpOnly : false ,
secure : false ,
2021-12-15 17:33:09 -08:00
sameSite : defaultSameSiteCookieValue ,
2020-08-03 13:41:48 -07:00
} ,
{
name : 'username' ,
value : 'John Doe' ,
domain : 'localhost' ,
path : '/' ,
expires : - 1 ,
httpOnly : false ,
secure : false ,
2021-12-15 17:33:09 -08:00
sameSite : defaultSameSiteCookieValue ,
2020-08-03 13:41:48 -07:00
} ,
2021-02-19 11:50:59 -08:00
] ) ) ;
2020-08-03 13:41:48 -07:00
} ) ;
2024-10-28 20:34:08 +01:00
it ( 'should get cookies from multiple urls' , async ( { context , browserName , isWindows } ) = > {
2020-08-03 13:41:48 -07:00
await context . addCookies ( [ {
url : 'https://foo.com' ,
name : 'doggo' ,
value : 'woofs' ,
2021-08-09 23:57:17 +03:00
sameSite : 'None' ,
2020-08-03 13:41:48 -07:00
} , {
url : 'https://bar.com' ,
name : 'catto' ,
value : 'purrs' ,
2021-08-09 23:57:17 +03:00
sameSite : 'Lax' ,
2020-08-03 13:41:48 -07:00
} , {
url : 'https://baz.com' ,
name : 'birdo' ,
value : 'tweets' ,
2021-08-09 23:57:17 +03:00
sameSite : 'Lax' ,
2020-08-03 13:41:48 -07:00
} ] ) ;
2021-02-19 11:50:59 -08:00
const cookies = new Set ( await context . cookies ( [ 'https://foo.com' , 'https://baz.com' ] ) ) ;
expect ( cookies ) . toEqual ( new Set ( [ {
2020-08-03 13:41:48 -07:00
name : 'birdo' ,
value : 'tweets' ,
domain : 'baz.com' ,
path : '/' ,
expires : - 1 ,
httpOnly : false ,
secure : true ,
2021-08-11 10:27:41 -07:00
sameSite : ( browserName === 'webkit' && isWindows ) ? 'None' : 'Lax' ,
2020-08-03 13:41:48 -07:00
} , {
name : 'doggo' ,
value : 'woofs' ,
domain : 'foo.com' ,
path : '/' ,
expires : - 1 ,
httpOnly : false ,
secure : true ,
2024-10-28 20:34:08 +01:00
sameSite : 'None' ,
2021-02-19 11:50:59 -08:00
} ] ) ) ;
2020-08-03 13:41:48 -07:00
} ) ;
2021-01-12 15:56:29 -08:00
2021-09-27 18:58:08 +02:00
it ( 'should work with subdomain cookie' , async ( { context , browserName , isWindows } ) = > {
2021-01-12 15:56:29 -08:00
await context . addCookies ( [ {
domain : '.foo.com' ,
path : '/' ,
name : 'doggo' ,
value : 'woofs' ,
2021-08-09 23:57:17 +03:00
sameSite : 'Lax' ,
2021-01-12 15:56:29 -08:00
secure : true
} ] ) ;
expect ( await context . cookies ( 'https://foo.com' ) ) . toEqual ( [ {
name : 'doggo' ,
value : 'woofs' ,
domain : '.foo.com' ,
path : '/' ,
expires : - 1 ,
httpOnly : false ,
secure : true ,
2021-08-11 10:27:41 -07:00
sameSite : ( browserName === 'webkit' && isWindows ) ? 'None' : 'Lax' ,
2021-01-12 15:56:29 -08:00
} ] ) ;
expect ( await context . cookies ( 'https://sub.foo.com' ) ) . toEqual ( [ {
name : 'doggo' ,
value : 'woofs' ,
domain : '.foo.com' ,
path : '/' ,
expires : - 1 ,
httpOnly : false ,
secure : true ,
2021-08-11 10:27:41 -07:00
sameSite : ( browserName === 'webkit' && isWindows ) ? 'None' : 'Lax' ,
2021-01-12 15:56:29 -08:00
} ] ) ;
} ) ;
2021-01-25 16:37:33 -08:00
2021-10-07 15:37:47 -07:00
it ( 'should return cookies with empty value' , async ( { context , page , server } ) = > {
2021-01-25 16:37:33 -08:00
server . setRoute ( '/empty.html' , ( req , res ) = > {
res . setHeader ( 'Set-Cookie' , 'name=;Path=/' ) ;
res . end ( ) ;
} ) ;
await page . goto ( server . EMPTY_PAGE ) ;
const cookies = await context . cookies ( ) ;
2021-10-07 15:37:47 -07:00
expect ( cookies ) . toEqual ( [
expect . objectContaining ( {
name : 'name' ,
value : ''
} )
] ) ;
2021-01-25 16:37:33 -08:00
} ) ;
2021-09-27 18:58:08 +02:00
it ( 'should return secure cookies based on HTTP(S) protocol' , async ( { context , browserName , isWindows } ) = > {
2021-02-19 11:50:59 -08:00
await context . addCookies ( [ {
url : 'https://foo.com' ,
name : 'doggo' ,
value : 'woofs' ,
2021-08-09 23:57:17 +03:00
sameSite : 'Lax' ,
2021-02-19 11:50:59 -08:00
secure : true
} , {
url : 'http://foo.com' ,
name : 'catto' ,
value : 'purrs' ,
2021-08-09 23:57:17 +03:00
sameSite : 'Lax' ,
2021-02-19 11:50:59 -08:00
secure : false
} ] ) ;
const cookies = new Set ( await context . cookies ( 'https://foo.com' ) ) ;
expect ( cookies ) . toEqual ( new Set ( [ {
name : 'catto' ,
value : 'purrs' ,
domain : 'foo.com' ,
path : '/' ,
expires : - 1 ,
httpOnly : false ,
secure : false ,
2021-08-11 10:27:41 -07:00
sameSite : ( browserName === 'webkit' && isWindows ) ? 'None' : 'Lax' ,
2021-02-19 11:50:59 -08:00
} , {
name : 'doggo' ,
value : 'woofs' ,
domain : 'foo.com' ,
path : '/' ,
expires : - 1 ,
httpOnly : false ,
secure : true ,
2021-08-11 10:27:41 -07:00
sameSite : ( browserName === 'webkit' && isWindows ) ? 'None' : 'Lax' ,
2021-02-19 11:50:59 -08:00
} ] ) ) ;
expect ( await context . cookies ( 'http://foo.com/' ) ) . toEqual ( [ {
name : 'catto' ,
value : 'purrs' ,
domain : 'foo.com' ,
path : '/' ,
expires : - 1 ,
httpOnly : false ,
secure : false ,
2021-08-11 10:27:41 -07:00
sameSite : ( browserName === 'webkit' && isWindows ) ? 'None' : 'Lax' ,
2021-02-19 11:50:59 -08:00
} ] ) ;
} ) ;
2022-02-25 23:00:51 +01:00
2024-10-28 20:34:08 +01:00
it ( 'should add cookies with an expiration' , async ( { context } ) = > {
2022-03-02 23:10:40 +01:00
const expires = Math . floor ( ( Date . now ( ) / 1000 ) ) + 3600 ;
2022-02-25 23:00:51 +01:00
await context . addCookies ( [ {
url : 'https://foo.com' ,
name : 'doggo' ,
value : 'woofs' ,
sameSite : 'None' ,
expires ,
} ] ) ;
const cookies = await context . cookies ( [ 'https://foo.com' ] ) ;
expect ( cookies . length ) . toBe ( 1 ) ;
expect ( cookies ) . toEqual ( [ {
name : 'doggo' ,
value : 'woofs' ,
domain : 'foo.com' ,
path : '/' ,
expires ,
httpOnly : false ,
secure : true ,
2024-10-28 20:34:08 +01:00
sameSite : 'None' ,
2022-02-25 23:00:51 +01:00
} ] ) ;
2022-03-02 23:10:40 +01:00
{
// Rollover to 5-digit year
await context . addCookies ( [ {
url : 'https://foo.com' ,
name : 'doggo' ,
value : 'woofs' ,
sameSite : 'None' ,
expires : 253402300799 , // Fri, 31 Dec 9999 23:59:59 +0000 (UTC)
} ] ) ;
await expect ( context . addCookies ( [ {
url : 'https://foo.com' ,
name : 'doggo' ,
value : 'woofs' ,
sameSite : 'None' ,
expires : 253402300800 , // Sat, 1 Jan 1000 00:00:00 +0000 (UTC)
} ] ) ) . rejects . toThrow ( /Cookie should have a valid expires/ ) ;
}
await expect ( context . addCookies ( [ {
url : 'https://foo.com' ,
name : 'doggo' ,
value : 'woofs' ,
sameSite : 'None' ,
expires : - 42 ,
} ] ) ) . rejects . toThrow ( /Cookie should have a valid expires/ ) ;
2022-02-25 23:00:51 +01:00
} ) ;
2022-09-02 20:00:55 +02:00
2024-09-27 07:06:37 -07:00
it ( 'should support requestStorageAccess' , async ( { page , server , channel , browserName , isMac , isLinux , isWindows , macVersion } ) = > {
2022-09-30 18:56:05 -07:00
it . info ( ) . annotations . push ( { type : 'issue' , description : 'https://github.com/microsoft/playwright/issues/17285' } ) ;
it . skip ( browserName === 'chromium' , 'requestStorageAccess API is not available in Chromium' ) ;
2023-01-27 21:52:34 -08:00
it . skip ( channel === 'firefox-beta' , 'hasStorageAccess returns true, but no cookie is sent' ) ;
2022-10-06 10:11:59 -07:00
2022-09-30 18:56:05 -07:00
server . setRoute ( '/set-cookie.html' , ( req , res ) = > {
res . setHeader ( 'Set-Cookie' , 'name=value; Path=/' ) ;
res . end ( ) ;
} ) ;
// Navigate once to the domain as top level.
await page . goto ( server . CROSS_PROCESS_PREFIX + '/set-cookie.html' ) ;
await page . goto ( server . EMPTY_PAGE ) ;
await page . setContent ( ` <iframe src=" ${ server . CROSS_PROCESS_PREFIX + '/empty.html' } "></iframe> ` ) ;
const frame = page . frames ( ) [ 1 ] ;
if ( browserName === 'firefox' ) {
expect ( await frame . evaluate ( ( ) = > document . hasStorageAccess ( ) ) ) . toBeTruthy ( ) ;
{
const [ serverRequest ] = await Promise . all ( [
server . waitForRequest ( '/title.html' ) ,
frame . evaluate ( ( ) = > fetch ( '/title.html' ) )
] ) ;
expect ( serverRequest . headers . cookie ) . toBe ( 'name=value' ) ;
}
} else {
2022-10-03 20:46:47 -07:00
if ( isLinux && browserName === 'webkit' )
expect ( await frame . evaluate ( ( ) = > document . hasStorageAccess ( ) ) ) . toBeTruthy ( ) ;
else
expect ( await frame . evaluate ( ( ) = > document . hasStorageAccess ( ) ) ) . toBeFalsy ( ) ;
2022-09-30 18:56:05 -07:00
{
const [ serverRequest ] = await Promise . all ( [
server . waitForRequest ( '/title.html' ) ,
frame . evaluate ( ( ) = > fetch ( '/title.html' ) )
] ) ;
2024-05-29 17:20:38 -07:00
if ( isWindows && browserName === 'webkit' )
2022-10-03 20:46:47 -07:00
expect ( serverRequest . headers . cookie ) . toBe ( 'name=value' ) ;
else
expect ( serverRequest . headers . cookie ) . toBeFalsy ( ) ;
2022-09-30 18:56:05 -07:00
}
expect ( await frame . evaluate ( ( ) = > document . requestStorageAccess ( ) . then ( ( ) = > true , e = > false ) ) ) . toBeTruthy ( ) ;
expect ( await frame . evaluate ( ( ) = > document . hasStorageAccess ( ) ) ) . toBeTruthy ( ) ;
{
const [ serverRequest ] = await Promise . all ( [
server . waitForRequest ( '/title.html' ) ,
frame . evaluate ( ( ) = > fetch ( '/title.html' ) )
] ) ;
2024-10-28 20:34:08 +01:00
if ( isLinux && browserName === 'webkit' )
2024-05-29 17:20:38 -07:00
expect ( serverRequest . headers . cookie ) . toBe ( undefined ) ;
else
expect ( serverRequest . headers . cookie ) . toBe ( 'name=value' ) ;
2022-09-30 18:56:05 -07:00
}
}
} ) ;
2024-04-10 22:13:01 +02:00
it ( 'should parse cookie with large Max-Age correctly' , async ( { server , page , defaultSameSiteCookieValue , browserName , platform } ) = > {
it . info ( ) . annotations . push ( { type : 'issue' , description : 'https://github.com/microsoft/playwright/issues/30305' } ) ;
server . setRoute ( '/foobar' , ( req , res ) = > {
res . setHeader ( 'set-cookie' , [
'cookie1=value1; Path=/; Expires=Thu, 08 Sep 2270 15:06:12 GMT; Max-Age=7776000000'
] ) ;
res . statusCode = 200 ;
res . end ( ) ;
} ) ;
await page . goto ( server . PREFIX + '/foobar' ) ;
expect ( await page . evaluate ( ( ) = > document . cookie ) ) . toBe ( 'cookie1=value1' ) ;
expect ( await page . context ( ) . cookies ( ) ) . toEqual ( [
{
name : 'cookie1' ,
value : 'value1' ,
domain : 'localhost' ,
path : '/' ,
expires : expect.any ( Number ) ,
httpOnly : false ,
secure : false ,
sameSite : defaultSameSiteCookieValue ,
} ,
] ) ;
} ) ;
2025-04-08 11:33:18 +02:00
it ( 'iframe should inherit cookies from parent' , { annotation : { type : 'issue' , description : 'https://github.com/microsoft/playwright/issues/35439' } } , async ( { page , isLinux , browserName } ) = > {
it . fixme ( browserName === 'webkit' && isLinux , 'https://bugs.webkit.org/show_bug.cgi?id=291194' ) ;
await page . route ( '**/*' , async ( route , request ) = > {
if ( request . url ( ) . includes ( 'sub.example.test' ) ) {
await route . fulfill ( {
body : `
< p id = "result" > < / p >
< script > document . getElementById ( 'result' ) . textContent = document . cookie || 'no cookies' ; < / script >
` ,
contentType : 'text/html' ,
} ) ;
return ;
}
await route . fulfill ( {
headers : { 'set-cookie' : 'testCookie=value; SameSite=Lax; Domain=example.test' } ,
contentType : 'text/html' ,
body : `
< p id = "result" > < / p >
< script > document . getElementById ( 'result' ) . textContent = document . cookie || 'no cookies' ; < / script >
< iframe src = "http://sub.example.test" > < / iframe >
`
} ) ;
} ) ;
await page . goto ( 'http://example.test' ) ;
await expect ( page . locator ( 'body' ) ) . toContainText ( 'testCookie=value' ) ;
await expect ( page . frameLocator ( 'iframe' ) . locator ( 'body' ) ) . toContainText ( 'testCookie=value' ) ;
} ) ;