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 */ 16 17import fs from 'fs'; 18import path from 'path'; 19import utils from './utils.js'; 20import expect from 'expect'; 21import { 22 getTestState, 23 setupTestBrowserHooks, 24 setupTestPageAndContextHooks, 25 itFailsFirefox, 26 describeFailsFirefox, 27} from './mocha-utils'; // eslint-disable-line import/extensions 28import { HTTPResponse } from '../lib/cjs/puppeteer/api-docs-entry.js'; 29 30describe('network', function () { 31 setupTestBrowserHooks(); 32 setupTestPageAndContextHooks(); 33 34 describe('Page.Events.Request', function () { 35 it('should fire for navigation requests', async () => { 36 const { page, server } = getTestState(); 37 38 const requests = []; 39 page.on( 40 'request', 41 (request) => !utils.isFavicon(request) && requests.push(request) 42 ); 43 await page.goto(server.EMPTY_PAGE); 44 expect(requests.length).toBe(1); 45 }); 46 it('should fire for iframes', async () => { 47 const { page, server } = getTestState(); 48 49 const requests = []; 50 page.on( 51 'request', 52 (request) => !utils.isFavicon(request) && requests.push(request) 53 ); 54 await page.goto(server.EMPTY_PAGE); 55 await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE); 56 expect(requests.length).toBe(2); 57 }); 58 it('should fire for fetches', async () => { 59 const { page, server } = getTestState(); 60 61 const requests = []; 62 page.on( 63 'request', 64 (request) => !utils.isFavicon(request) && requests.push(request) 65 ); 66 await page.goto(server.EMPTY_PAGE); 67 await page.evaluate(() => fetch('/empty.html')); 68 expect(requests.length).toBe(2); 69 }); 70 }); 71 describe('Request.frame', function () { 72 it('should work for main frame navigation request', async () => { 73 const { page, server } = getTestState(); 74 75 const requests = []; 76 page.on( 77 'request', 78 (request) => !utils.isFavicon(request) && requests.push(request) 79 ); 80 await page.goto(server.EMPTY_PAGE); 81 expect(requests.length).toBe(1); 82 expect(requests[0].frame()).toBe(page.mainFrame()); 83 }); 84 it('should work for subframe navigation request', async () => { 85 const { page, server } = getTestState(); 86 87 await page.goto(server.EMPTY_PAGE); 88 const requests = []; 89 page.on( 90 'request', 91 (request) => !utils.isFavicon(request) && requests.push(request) 92 ); 93 await utils.attachFrame(page, 'frame1', server.EMPTY_PAGE); 94 expect(requests.length).toBe(1); 95 expect(requests[0].frame()).toBe(page.frames()[1]); 96 }); 97 it('should work for fetch requests', async () => { 98 const { page, server } = getTestState(); 99 100 await page.goto(server.EMPTY_PAGE); 101 let requests = []; 102 page.on( 103 'request', 104 (request) => !utils.isFavicon(request) && requests.push(request) 105 ); 106 await page.evaluate(() => fetch('/digits/1.png')); 107 requests = requests.filter( 108 (request) => !request.url().includes('favicon') 109 ); 110 expect(requests.length).toBe(1); 111 expect(requests[0].frame()).toBe(page.mainFrame()); 112 }); 113 }); 114 115 describe('Request.headers', function () { 116 it('should work', async () => { 117 const { page, server, isChrome } = getTestState(); 118 119 const response = await page.goto(server.EMPTY_PAGE); 120 if (isChrome) 121 expect(response.request().headers()['user-agent']).toContain('Chrome'); 122 else 123 expect(response.request().headers()['user-agent']).toContain('Firefox'); 124 }); 125 }); 126 127 describe('Response.headers', function () { 128 it('should work', async () => { 129 const { page, server } = getTestState(); 130 131 server.setRoute('/empty.html', (req, res) => { 132 res.setHeader('foo', 'bar'); 133 res.end(); 134 }); 135 const response = await page.goto(server.EMPTY_PAGE); 136 expect(response.headers()['foo']).toBe('bar'); 137 }); 138 }); 139 140 describe('Request.initiator', () => { 141 it('shoud return the initiator', async () => { 142 const { page, server } = getTestState(); 143 144 const initiators = new Map(); 145 page.on('request', (request) => 146 initiators.set(request.url().split('/').pop(), request.initiator()) 147 ); 148 await page.goto(server.PREFIX + '/initiator.html'); 149 150 expect(initiators.get('initiator.html').type).toBe('other'); 151 expect(initiators.get('initiator.js').type).toBe('parser'); 152 expect(initiators.get('initiator.js').url).toBe( 153 server.PREFIX + '/initiator.html' 154 ); 155 expect(initiators.get('frame.html').type).toBe('parser'); 156 expect(initiators.get('frame.html').url).toBe( 157 server.PREFIX + '/initiator.html' 158 ); 159 expect(initiators.get('script.js').type).toBe('parser'); 160 expect(initiators.get('script.js').url).toBe( 161 server.PREFIX + '/frames/frame.html' 162 ); 163 expect(initiators.get('style.css').type).toBe('parser'); 164 expect(initiators.get('style.css').url).toBe( 165 server.PREFIX + '/frames/frame.html' 166 ); 167 expect(initiators.get('initiator.js').type).toBe('parser'); 168 expect(initiators.get('injectedfile.js').type).toBe('script'); 169 expect(initiators.get('injectedfile.js').stack.callFrames[0].url).toBe( 170 server.PREFIX + '/initiator.js' 171 ); 172 expect(initiators.get('injectedstyle.css').type).toBe('script'); 173 expect(initiators.get('injectedstyle.css').stack.callFrames[0].url).toBe( 174 server.PREFIX + '/initiator.js' 175 ); 176 expect(initiators.get('initiator.js').url).toBe( 177 server.PREFIX + '/initiator.html' 178 ); 179 }); 180 }); 181 182 describe('Response.fromCache', function () { 183 it('should return |false| for non-cached content', async () => { 184 const { page, server } = getTestState(); 185 186 const response = await page.goto(server.EMPTY_PAGE); 187 expect(response.fromCache()).toBe(false); 188 }); 189 190 it('should work', async () => { 191 const { page, server } = getTestState(); 192 193 const responses = new Map(); 194 page.on( 195 'response', 196 (r) => 197 !utils.isFavicon(r.request()) && 198 responses.set(r.url().split('/').pop(), r) 199 ); 200 201 // Load and re-load to make sure it's cached. 202 await page.goto(server.PREFIX + '/cached/one-style.html'); 203 await page.reload(); 204 205 expect(responses.size).toBe(2); 206 expect(responses.get('one-style.css').status()).toBe(200); 207 expect(responses.get('one-style.css').fromCache()).toBe(true); 208 expect(responses.get('one-style.html').status()).toBe(304); 209 expect(responses.get('one-style.html').fromCache()).toBe(false); 210 }); 211 }); 212 213 describe('Response.fromServiceWorker', function () { 214 it('should return |false| for non-service-worker content', async () => { 215 const { page, server } = getTestState(); 216 217 const response = await page.goto(server.EMPTY_PAGE); 218 expect(response.fromServiceWorker()).toBe(false); 219 }); 220 221 it('Response.fromServiceWorker', async () => { 222 const { page, server } = getTestState(); 223 224 const responses = new Map(); 225 page.on('response', (r) => responses.set(r.url().split('/').pop(), r)); 226 227 // Load and re-load to make sure serviceworker is installed and running. 228 await page.goto(server.PREFIX + '/serviceworkers/fetch/sw.html', { 229 waitUntil: 'networkidle2', 230 }); 231 await page.evaluate(async () => await globalThis.activationPromise); 232 await page.reload(); 233 234 expect(responses.size).toBe(2); 235 expect(responses.get('sw.html').status()).toBe(200); 236 expect(responses.get('sw.html').fromServiceWorker()).toBe(true); 237 expect(responses.get('style.css').status()).toBe(200); 238 expect(responses.get('style.css').fromServiceWorker()).toBe(true); 239 }); 240 }); 241 242 describe('Request.postData', function () { 243 it('should work', async () => { 244 const { page, server } = getTestState(); 245 246 await page.goto(server.EMPTY_PAGE); 247 server.setRoute('/post', (req, res) => res.end()); 248 let request = null; 249 page.on('request', (r) => (request = r)); 250 await page.evaluate(() => 251 fetch('./post', { 252 method: 'POST', 253 body: JSON.stringify({ foo: 'bar' }), 254 }) 255 ); 256 expect(request).toBeTruthy(); 257 expect(request.postData()).toBe('{"foo":"bar"}'); 258 }); 259 it('should be |undefined| when there is no post data', async () => { 260 const { page, server } = getTestState(); 261 262 const response = await page.goto(server.EMPTY_PAGE); 263 expect(response.request().postData()).toBe(undefined); 264 }); 265 }); 266 267 describe('Response.text', function () { 268 it('should work', async () => { 269 const { page, server } = getTestState(); 270 271 const response = await page.goto(server.PREFIX + '/simple.json'); 272 const responseText = (await response.text()).trimEnd(); 273 expect(responseText).toBe('{"foo": "bar"}'); 274 }); 275 it('should return uncompressed text', async () => { 276 const { page, server } = getTestState(); 277 278 server.enableGzip('/simple.json'); 279 const response = await page.goto(server.PREFIX + '/simple.json'); 280 expect(response.headers()['content-encoding']).toBe('gzip'); 281 const responseText = (await response.text()).trimEnd(); 282 expect(responseText).toBe('{"foo": "bar"}'); 283 }); 284 it('should throw when requesting body of redirected response', async () => { 285 const { page, server } = getTestState(); 286 287 server.setRedirect('/foo.html', '/empty.html'); 288 const response = await page.goto(server.PREFIX + '/foo.html'); 289 const redirectChain = response.request().redirectChain(); 290 expect(redirectChain.length).toBe(1); 291 const redirected = redirectChain[0].response(); 292 expect(redirected.status()).toBe(302); 293 let error = null; 294 await redirected.text().catch((error_) => (error = error_)); 295 expect(error.message).toContain( 296 'Response body is unavailable for redirect responses' 297 ); 298 }); 299 it('should wait until response completes', async () => { 300 const { page, server } = getTestState(); 301 302 await page.goto(server.EMPTY_PAGE); 303 // Setup server to trap request. 304 let serverResponse = null; 305 server.setRoute('/get', (req, res) => { 306 serverResponse = res; 307 // In Firefox, |fetch| will be hanging until it receives |Content-Type| header 308 // from server. 309 res.setHeader('Content-Type', 'text/plain; charset=utf-8'); 310 res.write('hello '); 311 }); 312 // Setup page to trap response. 313 let requestFinished = false; 314 page.on( 315 'requestfinished', 316 (r) => (requestFinished = requestFinished || r.url().includes('/get')) 317 ); 318 // send request and wait for server response 319 const [pageResponse] = await Promise.all([ 320 page.waitForResponse((r) => !utils.isFavicon(r.request())), 321 page.evaluate(() => fetch('./get', { method: 'GET' })), 322 server.waitForRequest('/get'), 323 ]); 324 325 expect(serverResponse).toBeTruthy(); 326 expect(pageResponse).toBeTruthy(); 327 expect(pageResponse.status()).toBe(200); 328 expect(requestFinished).toBe(false); 329 330 const responseText = pageResponse.text(); 331 // Write part of the response and wait for it to be flushed. 332 await new Promise((x) => serverResponse.write('wor', x)); 333 // Finish response. 334 await new Promise((x) => serverResponse.end('ld!', x)); 335 expect(await responseText).toBe('hello world!'); 336 }); 337 }); 338 339 describe('Response.json', function () { 340 it('should work', async () => { 341 const { page, server } = getTestState(); 342 343 const response = await page.goto(server.PREFIX + '/simple.json'); 344 expect(await response.json()).toEqual({ foo: 'bar' }); 345 }); 346 }); 347 348 describe('Response.buffer', function () { 349 it('should work', async () => { 350 const { page, server } = getTestState(); 351 352 const response = await page.goto(server.PREFIX + '/pptr.png'); 353 const imageBuffer = fs.readFileSync( 354 path.join(__dirname, 'assets', 'pptr.png') 355 ); 356 const responseBuffer = await response.buffer(); 357 expect(responseBuffer.equals(imageBuffer)).toBe(true); 358 }); 359 it('should work with compression', async () => { 360 const { page, server } = getTestState(); 361 362 server.enableGzip('/pptr.png'); 363 const response = await page.goto(server.PREFIX + '/pptr.png'); 364 const imageBuffer = fs.readFileSync( 365 path.join(__dirname, 'assets', 'pptr.png') 366 ); 367 const responseBuffer = await response.buffer(); 368 expect(responseBuffer.equals(imageBuffer)).toBe(true); 369 }); 370 it('should throw if the response does not have a body', async () => { 371 const { page, server } = getTestState(); 372 373 await page.goto(server.PREFIX + '/empty.html'); 374 375 server.setRoute('/test.html', (req, res) => { 376 res.setHeader('Access-Control-Allow-Origin', '*'); 377 res.setHeader('Access-Control-Allow-Headers', 'x-ping'); 378 res.end('Hello World'); 379 }); 380 const url = server.CROSS_PROCESS_PREFIX + '/test.html'; 381 const responsePromise = new Promise<HTTPResponse>((resolve) => { 382 page.on('response', (response) => { 383 // Get the preflight response. 384 if ( 385 response.request().method() === 'OPTIONS' && 386 response.url() === url 387 ) { 388 resolve(response); 389 } 390 }); 391 }); 392 393 // Trigger a request with a preflight. 394 await page.evaluate<(src: string) => void>(async (src) => { 395 const response = await fetch(src, { 396 method: 'POST', 397 headers: { 'x-ping': 'pong' }, 398 }); 399 return response; 400 }, url); 401 402 const response = await responsePromise; 403 await expect(response.buffer()).rejects.toThrowError( 404 'Could not load body for this request. This might happen if the request is a preflight request.' 405 ); 406 }); 407 }); 408 409 describe('Response.statusText', function () { 410 it('should work', async () => { 411 const { page, server } = getTestState(); 412 413 server.setRoute('/cool', (req, res) => { 414 res.writeHead(200, 'cool!'); 415 res.end(); 416 }); 417 const response = await page.goto(server.PREFIX + '/cool'); 418 expect(response.statusText()).toBe('cool!'); 419 }); 420 421 it('handles missing status text', async () => { 422 const { page, server } = getTestState(); 423 424 server.setRoute('/nostatus', (req, res) => { 425 res.writeHead(200, ''); 426 res.end(); 427 }); 428 const response = await page.goto(server.PREFIX + '/nostatus'); 429 expect(response.statusText()).toBe(''); 430 }); 431 }); 432 433 describe('Network Events', function () { 434 it('Page.Events.Request', async () => { 435 const { page, server } = getTestState(); 436 437 const requests = []; 438 page.on('request', (request) => requests.push(request)); 439 await page.goto(server.EMPTY_PAGE); 440 expect(requests.length).toBe(1); 441 expect(requests[0].url()).toBe(server.EMPTY_PAGE); 442 expect(requests[0].resourceType()).toBe('document'); 443 expect(requests[0].method()).toBe('GET'); 444 expect(requests[0].response()).toBeTruthy(); 445 expect(requests[0].frame() === page.mainFrame()).toBe(true); 446 expect(requests[0].frame().url()).toBe(server.EMPTY_PAGE); 447 }); 448 it('Page.Events.RequestServedFromCache', async () => { 449 const { page, server } = getTestState(); 450 451 const cached = []; 452 page.on('requestservedfromcache', (r) => 453 cached.push(r.url().split('/').pop()) 454 ); 455 456 await page.goto(server.PREFIX + '/cached/one-style.html'); 457 expect(cached).toEqual([]); 458 459 await page.reload(); 460 expect(cached).toEqual(['one-style.css']); 461 }); 462 it('Page.Events.Response', async () => { 463 const { page, server } = getTestState(); 464 465 const responses = []; 466 page.on('response', (response) => responses.push(response)); 467 await page.goto(server.EMPTY_PAGE); 468 expect(responses.length).toBe(1); 469 expect(responses[0].url()).toBe(server.EMPTY_PAGE); 470 expect(responses[0].status()).toBe(200); 471 expect(responses[0].ok()).toBe(true); 472 expect(responses[0].request()).toBeTruthy(); 473 const remoteAddress = responses[0].remoteAddress(); 474 // Either IPv6 or IPv4, depending on environment. 475 expect( 476 remoteAddress.ip.includes('::1') || remoteAddress.ip === '127.0.0.1' 477 ).toBe(true); 478 expect(remoteAddress.port).toBe(server.PORT); 479 }); 480 481 it('Page.Events.RequestFailed', async () => { 482 const { page, server, isChrome } = getTestState(); 483 484 await page.setRequestInterception(true); 485 page.on('request', (request) => { 486 if (request.url().endsWith('css')) request.abort(); 487 else request.continue(); 488 }); 489 const failedRequests = []; 490 page.on('requestfailed', (request) => failedRequests.push(request)); 491 await page.goto(server.PREFIX + '/one-style.html'); 492 expect(failedRequests.length).toBe(1); 493 expect(failedRequests[0].url()).toContain('one-style.css'); 494 expect(failedRequests[0].response()).toBe(null); 495 expect(failedRequests[0].resourceType()).toBe('stylesheet'); 496 if (isChrome) 497 expect(failedRequests[0].failure().errorText).toBe('net::ERR_FAILED'); 498 else 499 expect(failedRequests[0].failure().errorText).toBe('NS_ERROR_FAILURE'); 500 expect(failedRequests[0].frame()).toBeTruthy(); 501 }); 502 it('Page.Events.RequestFinished', async () => { 503 const { page, server } = getTestState(); 504 505 const requests = []; 506 page.on('requestfinished', (request) => requests.push(request)); 507 await page.goto(server.EMPTY_PAGE); 508 expect(requests.length).toBe(1); 509 expect(requests[0].url()).toBe(server.EMPTY_PAGE); 510 expect(requests[0].response()).toBeTruthy(); 511 expect(requests[0].frame() === page.mainFrame()).toBe(true); 512 expect(requests[0].frame().url()).toBe(server.EMPTY_PAGE); 513 }); 514 it('should fire events in proper order', async () => { 515 const { page, server } = getTestState(); 516 517 const events = []; 518 page.on('request', () => events.push('request')); 519 page.on('response', () => events.push('response')); 520 page.on('requestfinished', () => events.push('requestfinished')); 521 await page.goto(server.EMPTY_PAGE); 522 expect(events).toEqual(['request', 'response', 'requestfinished']); 523 }); 524 it('should support redirects', async () => { 525 const { page, server } = getTestState(); 526 527 const events = []; 528 page.on('request', (request) => 529 events.push(`${request.method()} ${request.url()}`) 530 ); 531 page.on('response', (response) => 532 events.push(`${response.status()} ${response.url()}`) 533 ); 534 page.on('requestfinished', (request) => 535 events.push(`DONE ${request.url()}`) 536 ); 537 page.on('requestfailed', (request) => 538 events.push(`FAIL ${request.url()}`) 539 ); 540 server.setRedirect('/foo.html', '/empty.html'); 541 const FOO_URL = server.PREFIX + '/foo.html'; 542 const response = await page.goto(FOO_URL); 543 expect(events).toEqual([ 544 `GET ${FOO_URL}`, 545 `302 ${FOO_URL}`, 546 `DONE ${FOO_URL}`, 547 `GET ${server.EMPTY_PAGE}`, 548 `200 ${server.EMPTY_PAGE}`, 549 `DONE ${server.EMPTY_PAGE}`, 550 ]); 551 552 // Check redirect chain 553 const redirectChain = response.request().redirectChain(); 554 expect(redirectChain.length).toBe(1); 555 expect(redirectChain[0].url()).toContain('/foo.html'); 556 expect(redirectChain[0].response().remoteAddress().port).toBe( 557 server.PORT 558 ); 559 }); 560 }); 561 562 describe('Request.isNavigationRequest', () => { 563 it('should work', async () => { 564 const { page, server } = getTestState(); 565 566 const requests = new Map(); 567 page.on('request', (request) => 568 requests.set(request.url().split('/').pop(), request) 569 ); 570 server.setRedirect('/rrredirect', '/frames/one-frame.html'); 571 await page.goto(server.PREFIX + '/rrredirect'); 572 expect(requests.get('rrredirect').isNavigationRequest()).toBe(true); 573 expect(requests.get('one-frame.html').isNavigationRequest()).toBe(true); 574 expect(requests.get('frame.html').isNavigationRequest()).toBe(true); 575 expect(requests.get('script.js').isNavigationRequest()).toBe(false); 576 expect(requests.get('style.css').isNavigationRequest()).toBe(false); 577 }); 578 it('should work with request interception', async () => { 579 const { page, server } = getTestState(); 580 581 const requests = new Map(); 582 page.on('request', (request) => { 583 requests.set(request.url().split('/').pop(), request); 584 request.continue(); 585 }); 586 await page.setRequestInterception(true); 587 server.setRedirect('/rrredirect', '/frames/one-frame.html'); 588 await page.goto(server.PREFIX + '/rrredirect'); 589 expect(requests.get('rrredirect').isNavigationRequest()).toBe(true); 590 expect(requests.get('one-frame.html').isNavigationRequest()).toBe(true); 591 expect(requests.get('frame.html').isNavigationRequest()).toBe(true); 592 expect(requests.get('script.js').isNavigationRequest()).toBe(false); 593 expect(requests.get('style.css').isNavigationRequest()).toBe(false); 594 }); 595 // This `itFailsFirefox` should be preserved in mozilla-central (Firefox). 596 // See https://bugzilla.mozilla.org/show_bug.cgi?id=1748254 597 // or https://github.com/puppeteer/puppeteer/pull/7846 598 itFailsFirefox('should work when navigating to image', async () => { 599 const { page, server } = getTestState(); 600 601 const requests = []; 602 page.on('request', (request) => requests.push(request)); 603 await page.goto(server.PREFIX + '/pptr.png'); 604 expect(requests[0].isNavigationRequest()).toBe(true); 605 }); 606 }); 607 608 describe('Page.setExtraHTTPHeaders', function () { 609 it('should work', async () => { 610 const { page, server } = getTestState(); 611 612 await page.setExtraHTTPHeaders({ 613 foo: 'bar', 614 }); 615 const [request] = await Promise.all([ 616 server.waitForRequest('/empty.html'), 617 page.goto(server.EMPTY_PAGE), 618 ]); 619 expect(request.headers['foo']).toBe('bar'); 620 }); 621 it('should throw for non-string header values', async () => { 622 const { page } = getTestState(); 623 624 let error = null; 625 try { 626 // @ts-expect-error purposeful bad input 627 await page.setExtraHTTPHeaders({ foo: 1 }); 628 } catch (error_) { 629 error = error_; 630 } 631 expect(error.message).toBe( 632 'Expected value of header "foo" to be String, but "number" is found.' 633 ); 634 }); 635 }); 636 637 describe('Page.authenticate', function () { 638 it('should work', async () => { 639 const { page, server } = getTestState(); 640 641 server.setAuth('/empty.html', 'user', 'pass'); 642 let response = await page.goto(server.EMPTY_PAGE); 643 expect(response.status()).toBe(401); 644 await page.authenticate({ 645 username: 'user', 646 password: 'pass', 647 }); 648 response = await page.reload(); 649 expect(response.status()).toBe(200); 650 }); 651 it('should fail if wrong credentials', async () => { 652 const { page, server } = getTestState(); 653 654 // Use unique user/password since Chrome caches credentials per origin. 655 server.setAuth('/empty.html', 'user2', 'pass2'); 656 await page.authenticate({ 657 username: 'foo', 658 password: 'bar', 659 }); 660 const response = await page.goto(server.EMPTY_PAGE); 661 expect(response.status()).toBe(401); 662 }); 663 it('should allow disable authentication', async () => { 664 const { page, server } = getTestState(); 665 666 // Use unique user/password since Chrome caches credentials per origin. 667 server.setAuth('/empty.html', 'user3', 'pass3'); 668 await page.authenticate({ 669 username: 'user3', 670 password: 'pass3', 671 }); 672 let response = await page.goto(server.EMPTY_PAGE); 673 expect(response.status()).toBe(200); 674 await page.authenticate(null); 675 // Navigate to a different origin to bust Chrome's credential caching. 676 response = await page.goto(server.CROSS_PROCESS_PREFIX + '/empty.html'); 677 expect(response.status()).toBe(401); 678 }); 679 it('should not disable caching', async () => { 680 const { page, server } = getTestState(); 681 682 // Use unique user/password since Chrome caches credentials per origin. 683 server.setAuth('/cached/one-style.css', 'user4', 'pass4'); 684 server.setAuth('/cached/one-style.html', 'user4', 'pass4'); 685 await page.authenticate({ 686 username: 'user4', 687 password: 'pass4', 688 }); 689 690 const responses = new Map(); 691 page.on('response', (r) => responses.set(r.url().split('/').pop(), r)); 692 693 // Load and re-load to make sure it's cached. 694 await page.goto(server.PREFIX + '/cached/one-style.html'); 695 await page.reload(); 696 697 expect(responses.get('one-style.css').status()).toBe(200); 698 expect(responses.get('one-style.css').fromCache()).toBe(true); 699 expect(responses.get('one-style.html').status()).toBe(304); 700 expect(responses.get('one-style.html').fromCache()).toBe(false); 701 }); 702 }); 703 704 describe('raw network headers', async () => { 705 it('Same-origin set-cookie navigation', async () => { 706 const { page, server } = getTestState(); 707 708 const setCookieString = 'foo=bar'; 709 server.setRoute('/empty.html', (req, res) => { 710 res.setHeader('set-cookie', setCookieString); 711 res.end('hello world'); 712 }); 713 const response = await page.goto(server.EMPTY_PAGE); 714 expect(response.headers()['set-cookie']).toBe(setCookieString); 715 }); 716 717 it('Same-origin set-cookie subresource', async () => { 718 const { page, server } = getTestState(); 719 await page.goto(server.EMPTY_PAGE); 720 721 const setCookieString = 'foo=bar'; 722 server.setRoute('/foo', (req, res) => { 723 res.setHeader('set-cookie', setCookieString); 724 res.end('hello world'); 725 }); 726 727 const responsePromise = new Promise<HTTPResponse>((resolve) => 728 page.on('response', (response) => resolve(response)) 729 ); 730 page.evaluate(() => { 731 const xhr = new XMLHttpRequest(); 732 xhr.open('GET', '/foo'); 733 xhr.send(); 734 }); 735 const subresourceResponse = await responsePromise; 736 expect(subresourceResponse.headers()['set-cookie']).toBe(setCookieString); 737 }); 738 739 it('Cross-origin set-cookie', async () => { 740 const { httpsServer, puppeteer, defaultBrowserOptions } = getTestState(); 741 742 const browser = await puppeteer.launch({ 743 ...defaultBrowserOptions, 744 ignoreHTTPSErrors: true, 745 }); 746 747 const page = await browser.newPage(); 748 749 try { 750 await page.goto(httpsServer.PREFIX + '/empty.html'); 751 752 const setCookieString = 'hello=world'; 753 httpsServer.setRoute('/setcookie.html', (req, res) => { 754 res.setHeader('Access-Control-Allow-Origin', '*'); 755 res.setHeader('set-cookie', setCookieString); 756 res.end(); 757 }); 758 await page.goto(httpsServer.PREFIX + '/setcookie.html'); 759 760 const response = await new Promise<HTTPResponse>((resolve) => { 761 page.on('response', resolve); 762 const url = httpsServer.CROSS_PROCESS_PREFIX + '/setcookie.html'; 763 page.evaluate<(src: string) => void>((src) => { 764 const xhr = new XMLHttpRequest(); 765 xhr.open('GET', src); 766 xhr.send(); 767 }, url); 768 }); 769 expect(response.headers()['set-cookie']).toBe(setCookieString); 770 } finally { 771 await page.close(); 772 await browser.close(); 773 } 774 }); 775 }); 776}); 777