1/** 2 * Copyright 2018 Google Inc. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16import expect from 'expect'; 17import { 18 expectCookieEquals, 19 getTestState, 20 setupTestBrowserHooks, 21 setupTestPageAndContextHooks, 22 itFailsFirefox, 23} from './mocha-utils'; // eslint-disable-line import/extensions 24 25describe('Cookie specs', () => { 26 setupTestBrowserHooks(); 27 setupTestPageAndContextHooks(); 28 29 describe('Page.cookies', function () { 30 it('should return no cookies in pristine browser context', async () => { 31 const { page, server } = getTestState(); 32 await page.goto(server.EMPTY_PAGE); 33 expectCookieEquals(await page.cookies(), []); 34 }); 35 it('should get a cookie', async () => { 36 const { page, server } = getTestState(); 37 await page.goto(server.EMPTY_PAGE); 38 await page.evaluate(() => { 39 document.cookie = 'username=John Doe'; 40 }); 41 42 expectCookieEquals(await page.cookies(), [ 43 { 44 name: 'username', 45 value: 'John Doe', 46 domain: 'localhost', 47 path: '/', 48 sameParty: false, 49 expires: -1, 50 size: 16, 51 httpOnly: false, 52 secure: false, 53 session: true, 54 sourcePort: 8907, 55 sourceScheme: 'NonSecure', 56 }, 57 ]); 58 }); 59 it('should properly report httpOnly cookie', async () => { 60 const { page, server } = getTestState(); 61 server.setRoute('/empty.html', (req, res) => { 62 res.setHeader('Set-Cookie', 'a=b; HttpOnly; Path=/'); 63 res.end(); 64 }); 65 await page.goto(server.EMPTY_PAGE); 66 const cookies = await page.cookies(); 67 expect(cookies.length).toBe(1); 68 expect(cookies[0].httpOnly).toBe(true); 69 }); 70 it('should properly report "Strict" sameSite cookie', async () => { 71 const { page, server } = getTestState(); 72 server.setRoute('/empty.html', (req, res) => { 73 res.setHeader('Set-Cookie', 'a=b; SameSite=Strict'); 74 res.end(); 75 }); 76 await page.goto(server.EMPTY_PAGE); 77 const cookies = await page.cookies(); 78 expect(cookies.length).toBe(1); 79 expect(cookies[0].sameSite).toBe('Strict'); 80 }); 81 it('should properly report "Lax" sameSite cookie', async () => { 82 const { page, server } = getTestState(); 83 server.setRoute('/empty.html', (req, res) => { 84 res.setHeader('Set-Cookie', 'a=b; SameSite=Lax'); 85 res.end(); 86 }); 87 await page.goto(server.EMPTY_PAGE); 88 const cookies = await page.cookies(); 89 expect(cookies.length).toBe(1); 90 expect(cookies[0].sameSite).toBe('Lax'); 91 }); 92 it('should get multiple cookies', async () => { 93 const { page, server } = getTestState(); 94 await page.goto(server.EMPTY_PAGE); 95 await page.evaluate(() => { 96 document.cookie = 'username=John Doe'; 97 document.cookie = 'password=1234'; 98 }); 99 const cookies = await page.cookies(); 100 cookies.sort((a, b) => a.name.localeCompare(b.name)); 101 expectCookieEquals(cookies, [ 102 { 103 name: 'password', 104 value: '1234', 105 domain: 'localhost', 106 path: '/', 107 sameParty: false, 108 expires: -1, 109 size: 12, 110 httpOnly: false, 111 secure: false, 112 session: true, 113 sourcePort: 8907, 114 sourceScheme: 'NonSecure', 115 }, 116 { 117 name: 'username', 118 value: 'John Doe', 119 domain: 'localhost', 120 path: '/', 121 sameParty: false, 122 expires: -1, 123 size: 16, 124 httpOnly: false, 125 secure: false, 126 session: true, 127 sourcePort: 8907, 128 sourceScheme: 'NonSecure', 129 }, 130 ]); 131 }); 132 it('should get cookies from multiple urls', async () => { 133 const { page } = getTestState(); 134 await page.setCookie( 135 { 136 url: 'https://foo.com', 137 name: 'doggo', 138 value: 'woofs', 139 }, 140 { 141 url: 'https://bar.com', 142 name: 'catto', 143 value: 'purrs', 144 }, 145 { 146 url: 'https://baz.com', 147 name: 'birdo', 148 value: 'tweets', 149 } 150 ); 151 const cookies = await page.cookies('https://foo.com', 'https://baz.com'); 152 cookies.sort((a, b) => a.name.localeCompare(b.name)); 153 expectCookieEquals(cookies, [ 154 { 155 name: 'birdo', 156 value: 'tweets', 157 domain: 'baz.com', 158 path: '/', 159 sameParty: false, 160 expires: -1, 161 size: 11, 162 httpOnly: false, 163 secure: true, 164 session: true, 165 sourcePort: 443, 166 sourceScheme: 'Secure', 167 }, 168 { 169 name: 'doggo', 170 value: 'woofs', 171 domain: 'foo.com', 172 path: '/', 173 sameParty: false, 174 expires: -1, 175 size: 10, 176 httpOnly: false, 177 secure: true, 178 session: true, 179 sourcePort: 443, 180 sourceScheme: 'Secure', 181 }, 182 ]); 183 }); 184 }); 185 describe('Page.setCookie', function () { 186 it('should work', async () => { 187 const { page, server } = getTestState(); 188 189 await page.goto(server.EMPTY_PAGE); 190 await page.setCookie({ 191 name: 'password', 192 value: '123456', 193 }); 194 expect(await page.evaluate(() => document.cookie)).toEqual( 195 'password=123456' 196 ); 197 }); 198 it('should isolate cookies in browser contexts', async () => { 199 const { page, server, browser } = getTestState(); 200 201 const anotherContext = await browser.createIncognitoBrowserContext(); 202 const anotherPage = await anotherContext.newPage(); 203 204 await page.goto(server.EMPTY_PAGE); 205 await anotherPage.goto(server.EMPTY_PAGE); 206 207 await page.setCookie({ name: 'page1cookie', value: 'page1value' }); 208 await anotherPage.setCookie({ name: 'page2cookie', value: 'page2value' }); 209 210 const cookies1 = await page.cookies(); 211 const cookies2 = await anotherPage.cookies(); 212 expect(cookies1.length).toBe(1); 213 expect(cookies2.length).toBe(1); 214 expect(cookies1[0].name).toBe('page1cookie'); 215 expect(cookies1[0].value).toBe('page1value'); 216 expect(cookies2[0].name).toBe('page2cookie'); 217 expect(cookies2[0].value).toBe('page2value'); 218 await anotherContext.close(); 219 }); 220 it('should set multiple cookies', async () => { 221 const { page, server } = getTestState(); 222 223 await page.goto(server.EMPTY_PAGE); 224 await page.setCookie( 225 { 226 name: 'password', 227 value: '123456', 228 }, 229 { 230 name: 'foo', 231 value: 'bar', 232 } 233 ); 234 const cookieStrings = await page.evaluate(() => { 235 const cookies = document.cookie.split(';'); 236 return cookies.map((cookie) => cookie.trim()).sort(); 237 }); 238 239 expect(cookieStrings).toEqual(['foo=bar', 'password=123456']); 240 }); 241 it('should have |expires| set to |-1| for session cookies', async () => { 242 const { page, server } = getTestState(); 243 244 await page.goto(server.EMPTY_PAGE); 245 await page.setCookie({ 246 name: 'password', 247 value: '123456', 248 }); 249 const cookies = await page.cookies(); 250 expect(cookies[0].session).toBe(true); 251 expect(cookies[0].expires).toBe(-1); 252 }); 253 it('should set cookie with reasonable defaults', async () => { 254 const { page, server } = getTestState(); 255 256 await page.goto(server.EMPTY_PAGE); 257 await page.setCookie({ 258 name: 'password', 259 value: '123456', 260 }); 261 const cookies = await page.cookies(); 262 expectCookieEquals( 263 cookies.sort((a, b) => a.name.localeCompare(b.name)), 264 [ 265 { 266 name: 'password', 267 value: '123456', 268 domain: 'localhost', 269 path: '/', 270 sameParty: false, 271 expires: -1, 272 size: 14, 273 httpOnly: false, 274 secure: false, 275 session: true, 276 sourcePort: 80, 277 sourceScheme: 'NonSecure', 278 }, 279 ] 280 ); 281 }); 282 it('should set a cookie with a path', async () => { 283 const { page, server } = getTestState(); 284 285 await page.goto(server.PREFIX + '/grid.html'); 286 await page.setCookie({ 287 name: 'gridcookie', 288 value: 'GRID', 289 path: '/grid.html', 290 }); 291 expectCookieEquals(await page.cookies(), [ 292 { 293 name: 'gridcookie', 294 value: 'GRID', 295 domain: 'localhost', 296 path: '/grid.html', 297 sameParty: false, 298 expires: -1, 299 size: 14, 300 httpOnly: false, 301 secure: false, 302 session: true, 303 sourcePort: 80, 304 sourceScheme: 'NonSecure', 305 }, 306 ]); 307 expect(await page.evaluate('document.cookie')).toBe('gridcookie=GRID'); 308 await page.goto(server.EMPTY_PAGE); 309 expectCookieEquals(await page.cookies(), []); 310 expect(await page.evaluate('document.cookie')).toBe(''); 311 await page.goto(server.PREFIX + '/grid.html'); 312 expect(await page.evaluate('document.cookie')).toBe('gridcookie=GRID'); 313 }); 314 it('should not set a cookie on a blank page', async () => { 315 const { page } = getTestState(); 316 317 await page.goto('about:blank'); 318 let error = null; 319 try { 320 await page.setCookie({ name: 'example-cookie', value: 'best' }); 321 } catch (error_) { 322 error = error_; 323 } 324 expect(error.message).toContain( 325 'At least one of the url and domain needs to be specified' 326 ); 327 }); 328 it('should not set a cookie with blank page URL', async () => { 329 const { page, server } = getTestState(); 330 331 let error = null; 332 await page.goto(server.EMPTY_PAGE); 333 try { 334 await page.setCookie( 335 { name: 'example-cookie', value: 'best' }, 336 { url: 'about:blank', name: 'example-cookie-blank', value: 'best' } 337 ); 338 } catch (error_) { 339 error = error_; 340 } 341 expect(error.message).toEqual( 342 `Blank page can not have cookie "example-cookie-blank"` 343 ); 344 }); 345 it('should not set a cookie on a data URL page', async () => { 346 const { page } = getTestState(); 347 348 let error = null; 349 await page.goto('data:,Hello%2C%20World!'); 350 try { 351 await page.setCookie({ name: 'example-cookie', value: 'best' }); 352 } catch (error_) { 353 error = error_; 354 } 355 expect(error.message).toContain( 356 'At least one of the url and domain needs to be specified' 357 ); 358 }); 359 it( 360 'should default to setting secure cookie for HTTPS websites', 361 async () => { 362 const { page, server } = getTestState(); 363 364 await page.goto(server.EMPTY_PAGE); 365 const SECURE_URL = 'https://example.com'; 366 await page.setCookie({ 367 url: SECURE_URL, 368 name: 'foo', 369 value: 'bar', 370 }); 371 const [cookie] = await page.cookies(SECURE_URL); 372 expect(cookie.secure).toBe(true); 373 } 374 ); 375 it('should be able to set unsecure cookie for HTTP website', async () => { 376 const { page, server } = getTestState(); 377 378 await page.goto(server.EMPTY_PAGE); 379 const HTTP_URL = 'http://example.com'; 380 await page.setCookie({ 381 url: HTTP_URL, 382 name: 'foo', 383 value: 'bar', 384 }); 385 const [cookie] = await page.cookies(HTTP_URL); 386 expect(cookie.secure).toBe(false); 387 }); 388 it('should set a cookie on a different domain', async () => { 389 const { page, server } = getTestState(); 390 391 await page.goto(server.EMPTY_PAGE); 392 await page.setCookie({ 393 url: 'https://www.example.com', 394 name: 'example-cookie', 395 value: 'best', 396 }); 397 expect(await page.evaluate('document.cookie')).toBe(''); 398 expectCookieEquals(await page.cookies(), []); 399 expectCookieEquals(await page.cookies('https://www.example.com'), [ 400 { 401 name: 'example-cookie', 402 value: 'best', 403 domain: 'www.example.com', 404 path: '/', 405 sameParty: false, 406 expires: -1, 407 size: 18, 408 httpOnly: false, 409 secure: true, 410 session: true, 411 sourcePort: 443, 412 sourceScheme: 'Secure', 413 }, 414 ]); 415 }); 416 it('should set cookies from a frame', async () => { 417 const { page, server } = getTestState(); 418 419 await page.goto(server.PREFIX + '/grid.html'); 420 await page.setCookie({ name: 'localhost-cookie', value: 'best' }); 421 await page.evaluate<(src: string) => Promise<void>>((src) => { 422 let fulfill; 423 const promise = new Promise<void>((x) => (fulfill = x)); 424 const iframe = document.createElement('iframe'); 425 document.body.appendChild(iframe); 426 iframe.onload = fulfill; 427 iframe.src = src; 428 return promise; 429 }, server.CROSS_PROCESS_PREFIX); 430 await page.setCookie({ 431 name: '127-cookie', 432 value: 'worst', 433 url: server.CROSS_PROCESS_PREFIX, 434 }); 435 expect(await page.evaluate('document.cookie')).toBe( 436 'localhost-cookie=best' 437 ); 438 expect(await page.frames()[1].evaluate('document.cookie')).toBe(''); 439 440 expectCookieEquals(await page.cookies(), [ 441 { 442 name: 'localhost-cookie', 443 value: 'best', 444 domain: 'localhost', 445 path: '/', 446 sameParty: false, 447 expires: -1, 448 size: 20, 449 httpOnly: false, 450 secure: false, 451 session: true, 452 sourcePort: 80, 453 sourceScheme: 'NonSecure', 454 }, 455 ]); 456 457 expectCookieEquals(await page.cookies(server.CROSS_PROCESS_PREFIX), [ 458 { 459 name: '127-cookie', 460 value: 'worst', 461 domain: '127.0.0.1', 462 path: '/', 463 sameParty: false, 464 expires: -1, 465 size: 15, 466 httpOnly: false, 467 secure: false, 468 session: true, 469 sourcePort: 80, 470 sourceScheme: 'NonSecure', 471 }, 472 ]); 473 }); 474 it( 475 'should set secure same-site cookies from a frame', 476 async () => { 477 const { httpsServer, puppeteer, defaultBrowserOptions } = 478 getTestState(); 479 480 const browser = await puppeteer.launch({ 481 ...defaultBrowserOptions, 482 ignoreHTTPSErrors: true, 483 }); 484 485 const page = await browser.newPage(); 486 487 try { 488 await page.goto(httpsServer.PREFIX + '/grid.html'); 489 await page.evaluate<(src: string) => Promise<void>>((src) => { 490 let fulfill; 491 const promise = new Promise<void>((x) => (fulfill = x)); 492 const iframe = document.createElement('iframe'); 493 document.body.appendChild(iframe); 494 iframe.onload = fulfill; 495 iframe.src = src; 496 return promise; 497 }, httpsServer.CROSS_PROCESS_PREFIX); 498 await page.setCookie({ 499 name: '127-same-site-cookie', 500 value: 'best', 501 url: httpsServer.CROSS_PROCESS_PREFIX, 502 sameSite: 'None', 503 }); 504 505 expect(await page.frames()[1].evaluate('document.cookie')).toBe( 506 '127-same-site-cookie=best' 507 ); 508 expectCookieEquals( 509 await page.cookies(httpsServer.CROSS_PROCESS_PREFIX), 510 [ 511 { 512 name: '127-same-site-cookie', 513 value: 'best', 514 domain: '127.0.0.1', 515 path: '/', 516 sameParty: false, 517 expires: -1, 518 size: 24, 519 httpOnly: false, 520 sameSite: 'None', 521 secure: true, 522 session: true, 523 sourcePort: 443, 524 sourceScheme: 'Secure', 525 }, 526 ] 527 ); 528 } finally { 529 await page.close(); 530 await browser.close(); 531 } 532 } 533 ); 534 }); 535 536 describe('Page.deleteCookie', function () { 537 it('should work', async () => { 538 const { page, server } = getTestState(); 539 540 await page.goto(server.EMPTY_PAGE); 541 await page.setCookie( 542 { 543 name: 'cookie1', 544 value: '1', 545 }, 546 { 547 name: 'cookie2', 548 value: '2', 549 }, 550 { 551 name: 'cookie3', 552 value: '3', 553 } 554 ); 555 expect(await page.evaluate('document.cookie')).toBe( 556 'cookie1=1; cookie2=2; cookie3=3' 557 ); 558 await page.deleteCookie({ name: 'cookie2' }); 559 expect(await page.evaluate('document.cookie')).toBe( 560 'cookie1=1; cookie3=3' 561 ); 562 }); 563 }); 564}); 565