2020-08-03 16:30:37 -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 .
* /
2021-05-06 07:08:22 -07:00
import { test as it , expect } from './pageTest' ;
2021-05-05 19:10:28 -07:00
import { attachFrame } from '../config/utils' ;
2020-08-03 16:30:37 -07:00
2021-09-27 18:58:08 +02:00
it ( 'should fire for navigation requests' , async ( { page , server } ) = > {
2020-08-03 16:30:37 -07:00
const requests = [ ] ;
page . on ( 'request' , request = > requests . push ( request ) ) ;
await page . goto ( server . EMPTY_PAGE ) ;
expect ( requests . length ) . toBe ( 1 ) ;
} ) ;
2021-09-27 18:58:08 +02:00
it ( 'should fire for iframes' , async ( { page , server } ) = > {
2020-08-03 16:30:37 -07:00
const requests = [ ] ;
page . on ( 'request' , request = > requests . push ( request ) ) ;
await page . goto ( server . EMPTY_PAGE ) ;
2020-09-18 15:52:14 -07:00
await attachFrame ( page , 'frame1' , server . EMPTY_PAGE ) ;
2020-08-03 16:30:37 -07:00
expect ( requests . length ) . toBe ( 2 ) ;
} ) ;
2021-09-27 18:58:08 +02:00
it ( 'should fire for fetches' , async ( { page , server } ) = > {
2020-08-03 16:30:37 -07:00
const requests = [ ] ;
page . on ( 'request' , request = > requests . push ( request ) ) ;
await page . goto ( server . EMPTY_PAGE ) ;
await page . evaluate ( ( ) = > fetch ( '/empty.html' ) ) ;
expect ( requests . length ) . toBe ( 2 ) ;
} ) ;
2021-10-01 19:40:47 -07:00
it ( 'should report requests and responses handled by service worker' , async ( { page , server , isAndroid , isElectron } ) = > {
2021-04-09 07:59:09 -07:00
it . fixme ( isAndroid ) ;
2021-10-01 19:40:47 -07:00
it . fixme ( isElectron ) ;
2021-04-02 14:23:42 -07:00
2020-08-03 16:30:37 -07:00
await page . goto ( server . PREFIX + '/serviceworkers/fetchdummy/sw.html' ) ;
2020-08-28 04:20:29 -07:00
await page . evaluate ( ( ) = > window [ 'activationPromise' ] ) ;
2023-09-27 14:09:56 -07:00
const [ request , swResponse ] = await Promise . all ( [
2020-08-03 16:30:37 -07:00
page . waitForEvent ( 'request' ) ,
2023-09-27 14:09:56 -07:00
page . evaluate ( ( ) = > window [ 'fetchDummy' ] ( 'foo' ) ) ,
2020-08-03 16:30:37 -07:00
] ) ;
expect ( swResponse ) . toBe ( 'responseFromServiceWorker:foo' ) ;
expect ( request . url ( ) ) . toBe ( server . PREFIX + '/serviceworkers/fetchdummy/foo' ) ;
2023-06-08 10:33:28 -07:00
expect ( request . serviceWorker ( ) ) . toBe ( null ) ;
2020-08-03 16:30:37 -07:00
const response = await request . response ( ) ;
expect ( response . url ( ) ) . toBe ( server . PREFIX + '/serviceworkers/fetchdummy/foo' ) ;
expect ( await response . text ( ) ) . toBe ( 'responseFromServiceWorker:foo' ) ;
2023-06-08 10:33:28 -07:00
expect ( response . fromServiceWorker ( ) ) . toBe ( true ) ;
const [ failedRequest ] = await Promise . all ( [
page . waitForEvent ( 'requestfailed' ) ,
page . evaluate ( ( ) = > window [ 'fetchDummy' ] ( 'error' ) ) . catch ( e = > e ) ,
] ) ;
expect ( failedRequest . url ( ) ) . toBe ( server . PREFIX + '/serviceworkers/fetchdummy/error' ) ;
expect ( failedRequest . failure ( ) ) . not . toBe ( null ) ;
expect ( failedRequest . serviceWorker ( ) ) . toBe ( null ) ;
expect ( await failedRequest . response ( ) ) . toBe ( null ) ;
} ) ;
2023-12-04 13:02:00 -08:00
it ( 'should report requests and responses handled by service worker with routing' , async ( { page , server , isAndroid , isElectron , mode , browserName , platform } ) = > {
2023-06-08 10:33:28 -07:00
it . fixme ( isAndroid ) ;
it . fixme ( isElectron ) ;
2023-07-31 11:24:04 -07:00
it . fixme ( mode . startsWith ( 'service' ) && platform === 'linux' , 'Times out for no clear reason' ) ;
2023-06-08 10:33:28 -07:00
2023-12-04 13:02:00 -08:00
const interceptedUrls = [ ] ;
await page . route ( '**/*' , route = > {
interceptedUrls . push ( route . request ( ) . url ( ) ) ;
void route . continue ( ) ;
} ) ;
2023-06-08 10:33:28 -07:00
await page . goto ( server . PREFIX + '/serviceworkers/fetchdummy/sw.html' ) ;
await page . evaluate ( ( ) = > window [ 'activationPromise' ] ) ;
const [ swResponse , request ] = await Promise . all ( [
page . evaluate ( ( ) = > window [ 'fetchDummy' ] ( 'foo' ) ) ,
page . waitForEvent ( 'request' ) ,
] ) ;
expect ( swResponse ) . toBe ( 'responseFromServiceWorker:foo' ) ;
expect ( request . url ( ) ) . toBe ( server . PREFIX + '/serviceworkers/fetchdummy/foo' ) ;
expect ( request . serviceWorker ( ) ) . toBe ( null ) ;
const response = await request . response ( ) ;
expect ( response . url ( ) ) . toBe ( server . PREFIX + '/serviceworkers/fetchdummy/foo' ) ;
expect ( await response . text ( ) ) . toBe ( 'responseFromServiceWorker:foo' ) ;
const [ failedRequest ] = await Promise . all ( [
page . waitForEvent ( 'requestfailed' ) ,
page . evaluate ( ( ) = > window [ 'fetchDummy' ] ( 'error' ) ) . catch ( e = > e ) ,
] ) ;
expect ( failedRequest . url ( ) ) . toBe ( server . PREFIX + '/serviceworkers/fetchdummy/error' ) ;
expect ( failedRequest . failure ( ) ) . not . toBe ( null ) ;
expect ( failedRequest . serviceWorker ( ) ) . toBe ( null ) ;
expect ( await failedRequest . response ( ) ) . toBe ( null ) ;
2023-12-04 13:02:00 -08:00
const expectedUrls = [ server . PREFIX + '/serviceworkers/fetchdummy/sw.html' ] ;
if ( browserName === 'webkit' )
expectedUrls . push ( server . PREFIX + '/serviceworkers/fetchdummy/sw.js' ) ;
expect ( interceptedUrls ) . toEqual ( expectedUrls ) ;
2023-06-08 10:33:28 -07:00
} ) ;
it ( 'should report navigation requests and responses handled by service worker' , async ( { page , server , isAndroid , isElectron , browserName } ) = > {
it . fixme ( isAndroid ) ;
it . fixme ( isElectron ) ;
await page . goto ( server . PREFIX + '/serviceworkers/stub/sw.html' ) ;
await page . evaluate ( ( ) = > window [ 'activationPromise' ] ) ;
const reloadResponse = await page . reload ( ) ;
expect ( await page . evaluate ( 'window.fromSW' ) ) . toBe ( true ) ;
expect ( reloadResponse . url ( ) ) . toBe ( server . PREFIX + '/serviceworkers/stub/sw.html' ) ;
await page . evaluate ( ( ) = > window [ 'activationPromise' ] ) ;
if ( browserName !== 'firefox' ) {
// When SW fetch throws, Firefox does not fail the navigation,
// but rather falls back to the real network.
const [ , failedRequest ] = await Promise . all ( [
page . evaluate ( ( ) = > {
window . location . href = '/serviceworkers/stub/error.html' ;
} ) ,
page . waitForEvent ( 'requestfailed' ) ,
] ) ;
expect ( failedRequest . url ( ) ) . toBe ( server . PREFIX + '/serviceworkers/stub/error.html' ) ;
expect ( failedRequest . failure ( ) . errorText ) . toContain ( browserName === 'chromium' ? 'net::ERR_FAILED' : 'uh oh' ) ;
expect ( failedRequest . serviceWorker ( ) ) . toBe ( null ) ;
expect ( await failedRequest . response ( ) ) . toBe ( null ) ;
}
} ) ;
it ( 'should report navigation requests and responses handled by service worker with routing' , async ( { page , server , isAndroid , isElectron , browserName } ) = > {
it . fixme ( isAndroid ) ;
it . fixme ( isElectron ) ;
await page . route ( '**/*' , route = > route . continue ( ) ) ;
await page . goto ( server . PREFIX + '/serviceworkers/stub/sw.html' ) ;
await page . evaluate ( ( ) = > window [ 'activationPromise' ] ) ;
const reloadResponse = await page . reload ( ) ;
expect ( await page . evaluate ( 'window.fromSW' ) ) . toBe ( true ) ;
expect ( reloadResponse . url ( ) ) . toBe ( server . PREFIX + '/serviceworkers/stub/sw.html' ) ;
await page . evaluate ( ( ) = > window [ 'activationPromise' ] ) ;
if ( browserName !== 'firefox' ) {
// When SW fetch throws, Firefox does not fail the navigation,
// but rather falls back to the real network.
const [ , failedRequest ] = await Promise . all ( [
page . evaluate ( ( ) = > {
window . location . href = '/serviceworkers/stub/error.html' ;
2023-07-26 06:50:38 -07:00
// eslint-disable-next-line
undefined
2023-06-08 10:33:28 -07:00
} ) ,
page . waitForEvent ( 'requestfailed' ) ,
] ) ;
expect ( failedRequest . url ( ) ) . toBe ( server . PREFIX + '/serviceworkers/stub/error.html' ) ;
expect ( failedRequest . failure ( ) . errorText ) . toContain ( browserName === 'chromium' ? 'net::ERR_FAILED' : 'uh oh' ) ;
expect ( failedRequest . serviceWorker ( ) ) . toBe ( null ) ;
expect ( await failedRequest . response ( ) ) . toBe ( null ) ;
}
2020-08-03 16:30:37 -07:00
} ) ;
2021-09-28 09:54:05 -07:00
it ( 'should return response body when Cross-Origin-Opener-Policy is set' , async ( { page , server , browserName } ) = > {
server . setRoute ( '/empty.html' , ( req , res ) = > {
res . setHeader ( 'Cross-Origin-Opener-Policy' , 'same-origin' ) ;
res . end ( 'Hello there!' ) ;
} ) ;
const response = await page . goto ( server . EMPTY_PAGE ) ;
expect ( page . url ( ) ) . toBe ( server . EMPTY_PAGE ) ;
await response . finished ( ) ;
expect ( response . request ( ) . failure ( ) ) . toBeNull ( ) ;
expect ( await response . text ( ) ) . toBe ( 'Hello there!' ) ;
} ) ;
2021-11-12 19:06:53 -08:00
it ( 'should fire requestfailed when intercepting race' , async ( { page , server , browserName } ) = > {
2021-12-02 07:44:13 -08:00
it . skip ( browserName !== 'chromium' , 'This test is specifically testing Chromium race' ) ;
2023-10-04 22:56:42 -04:00
const promise = new Promise < void > ( resolve = > {
2021-11-12 19:06:53 -08:00
let counter = 0 ;
const failures = new Set ( ) ;
const alive = new Set ( ) ;
page . on ( 'request' , request = > {
expect ( alive . has ( request ) ) . toBe ( false ) ;
expect ( failures . has ( request ) ) . toBe ( false ) ;
alive . add ( request ) ;
} ) ;
page . on ( 'requestfailed' , request = > {
expect ( failures . has ( request ) ) . toBe ( false ) ;
expect ( alive . has ( request ) ) . toBe ( true ) ;
alive . delete ( request ) ;
failures . add ( request ) ;
if ( ++ counter === 10 )
resolve ( ) ;
} ) ;
} ) ;
// Stall requests to make sure we don't get requestfinished.
2023-12-15 09:00:12 -08:00
await page . route ( '**' , route = > { } ) ;
2021-11-12 19:06:53 -08:00
await page . setContent ( `
< iframe src = "${server.EMPTY_PAGE}" > < / iframe >
< iframe src = "${server.EMPTY_PAGE}" > < / iframe >
< iframe src = "${server.EMPTY_PAGE}" > < / iframe >
< iframe src = "${server.EMPTY_PAGE}" > < / iframe >
< iframe src = "${server.EMPTY_PAGE}" > < / iframe >
< iframe src = "${server.EMPTY_PAGE}" > < / iframe >
< iframe src = "${server.EMPTY_PAGE}" > < / iframe >
< iframe src = "${server.EMPTY_PAGE}" > < / iframe >
< iframe src = "${server.EMPTY_PAGE}" > < / iframe >
< iframe src = "${server.EMPTY_PAGE}" > < / iframe >
< script >
function abortAll() {
const frames = document . querySelectorAll ( "iframe" ) ;
for ( const frame of frames )
frame . src = "about:blank" ;
}
2021-12-02 07:44:13 -08:00
abortAll ( ) ;
2021-11-12 19:06:53 -08:00
< / script >
` );
2023-10-04 22:56:42 -04:00
await promise ;
2021-11-12 19:06:53 -08:00
} ) ;
2023-05-19 17:59:17 -07:00
2023-05-25 09:43:41 -07:00
it ( 'main resource xhr should have type xhr' , async ( { page , server } ) = > {
2023-05-19 17:59:17 -07:00
it . info ( ) . annotations . push ( { type : 'issue' , description : 'https://github.com/microsoft/playwright/issues/22812' } ) ;
await page . goto ( server . EMPTY_PAGE ) ;
const [ request ] = await Promise . all ( [
page . waitForEvent ( 'request' ) ,
page . evaluate ( ( ) = > {
const x = new XMLHttpRequest ( ) ;
x . open ( 'GET' , location . href , false ) ;
x . send ( ) ;
} )
] ) ;
expect ( request . isNavigationRequest ( ) ) . toBe ( false ) ;
expect ( request . resourceType ( ) ) . toBe ( 'xhr' ) ;
} ) ;