chore: move interception API into features/ (#43)

This commit is contained in:
Pavel Feldman 2019-11-21 14:41:38 -08:00 committed by GitHub
parent 43836c9178
commit e3dcac1d46
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 294 additions and 217 deletions

View file

@ -116,6 +116,7 @@
* [page.goForward([options])](#pagegoforwardoptions) * [page.goForward([options])](#pagegoforwardoptions)
* [page.goto(url[, options])](#pagegotourl-options) * [page.goto(url[, options])](#pagegotourl-options)
* [page.hover(selector[, options])](#pagehoverselector-options) * [page.hover(selector[, options])](#pagehoverselector-options)
* [page.interception](#pageinterception)
* [page.isClosed()](#pageisclosed) * [page.isClosed()](#pageisclosed)
* [page.keyboard](#pagekeyboard) * [page.keyboard](#pagekeyboard)
* [page.mainFrame()](#pagemainframe) * [page.mainFrame()](#pagemainframe)
@ -133,7 +134,6 @@
* [page.setExtraHTTPHeaders(headers)](#pagesetextrahttpheadersheaders) * [page.setExtraHTTPHeaders(headers)](#pagesetextrahttpheadersheaders)
* [page.setJavaScriptEnabled(enabled)](#pagesetjavascriptenabledenabled) * [page.setJavaScriptEnabled(enabled)](#pagesetjavascriptenabledenabled)
* [page.setOfflineMode(enabled)](#pagesetofflinemodeenabled) * [page.setOfflineMode(enabled)](#pagesetofflinemodeenabled)
* [page.setRequestInterception(value)](#pagesetrequestinterceptionvalue)
* [page.setUserAgent(userAgent)](#pagesetuseragentuseragent) * [page.setUserAgent(userAgent)](#pagesetuseragentuseragent)
* [page.setViewport(viewport)](#pagesetviewportviewport) * [page.setViewport(viewport)](#pagesetviewportviewport)
* [page.target()](#pagetarget) * [page.target()](#pagetarget)
@ -233,6 +233,12 @@
* [executionContext.evaluate(pageFunction[, ...args])](#executioncontextevaluatepagefunction-args) * [executionContext.evaluate(pageFunction[, ...args])](#executioncontextevaluatepagefunction-args)
* [executionContext.evaluateHandle(pageFunction[, ...args])](#executioncontextevaluatehandlepagefunction-args) * [executionContext.evaluateHandle(pageFunction[, ...args])](#executioncontextevaluatehandlepagefunction-args)
* [executionContext.frame()](#executioncontextframe) * [executionContext.frame()](#executioncontextframe)
- [class: Interception](#class-interception)
* [interception.abort(request, [errorCode])](#interceptionabortrequest-errorcode)
* [interception.continue(request, [overrides])](#interceptioncontinuerequest-overrides)
* [interception.disable()](#interceptiondisable)
* [interception.enable()](#interceptionenable)
* [interception.fulfill(request, response)](#interceptionfulfillrequest-response)
- [class: JSHandle](#class-jshandle) - [class: JSHandle](#class-jshandle)
* [jsHandle.asElement()](#jshandleaselement) * [jsHandle.asElement()](#jshandleaselement)
* [jsHandle.dispose()](#jshandledispose) * [jsHandle.dispose()](#jshandledispose)
@ -272,8 +278,6 @@
* [elementHandle.type(text[, options])](#elementhandletypetext-options) * [elementHandle.type(text[, options])](#elementhandletypetext-options)
* [elementHandle.uploadFile(...filePaths)](#elementhandleuploadfilefilepaths) * [elementHandle.uploadFile(...filePaths)](#elementhandleuploadfilefilepaths)
- [class: Request](#class-request) - [class: Request](#class-request)
* [request.abort([errorCode])](#requestaborterrorcode)
* [request.continue([overrides])](#requestcontinueoverrides)
* [request.failure()](#requestfailure) * [request.failure()](#requestfailure)
* [request.frame()](#requestframe) * [request.frame()](#requestframe)
* [request.headers()](#requestheaders) * [request.headers()](#requestheaders)
@ -282,7 +286,6 @@
* [request.postData()](#requestpostdata) * [request.postData()](#requestpostdata)
* [request.redirectChain()](#requestredirectchain) * [request.redirectChain()](#requestredirectchain)
* [request.resourceType()](#requestresourcetype) * [request.resourceType()](#requestresourcetype)
* [request.respond(response)](#requestrespondresponse)
* [request.response()](#requestresponse) * [request.response()](#requestresponse)
* [request.url()](#requesturl) * [request.url()](#requesturl)
- [class: Response](#class-response) - [class: Response](#class-response)
@ -1035,7 +1038,7 @@ const [popup] = await Promise.all([
- <[Request]> - <[Request]>
Emitted when a page issues a request. The [request] object is read-only. Emitted when a page issues a request. The [request] object is read-only.
In order to intercept and mutate requests, see `page.setRequestInterception`. In order to intercept and mutate requests, see `page.interception.enable()`.
#### event: 'requestfailed' #### event: 'requestfailed'
- <[Request]> - <[Request]>
@ -1604,6 +1607,9 @@ If there's no element matching `selector`, the method throws an error.
Shortcut for [page.mainFrame().hover(selector)](#framehoverselector). Shortcut for [page.mainFrame().hover(selector)](#framehoverselector).
#### page.interception
- returns: <[Interception]>
#### page.isClosed() #### page.isClosed()
- returns: <[boolean]> - returns: <[boolean]>
@ -1763,36 +1769,6 @@ The extra HTTP headers will be sent with every request the page initiates.
- `enabled` <[boolean]> When `true`, enables offline mode for the page. - `enabled` <[boolean]> When `true`, enables offline mode for the page.
- returns: <[Promise]> - returns: <[Promise]>
#### page.setRequestInterception(value)
- `value` <[boolean]> Whether to enable request interception.
- returns: <[Promise]>
Activating request interception enables `request.abort`, `request.continue` and
`request.respond` methods. This provides the capability to modify network requests that are made by a page.
Once request interception is enabled, every request will stall unless it's continued, responded or aborted.
An example of a naïve request interceptor that aborts all image requests:
```js
const playwright = require('playwright');
(async () => {
const browser = await playwright.launch();
const page = await browser.newPage();
await page.setRequestInterception(true);
page.on('request', interceptedRequest => {
if (interceptedRequest.url().endsWith('.png') || interceptedRequest.url().endsWith('.jpg'))
interceptedRequest.abort();
else
interceptedRequest.continue();
});
await page.goto('https://example.com');
await browser.close();
})();
```
> **NOTE** Enabling request interception disables page caching.
#### page.setUserAgent(userAgent) #### page.setUserAgent(userAgent)
- `userAgent` <[string]> Specific user agent to use in this page - `userAgent` <[string]> Specific user agent to use in this page
- returns: <[Promise]> Promise which resolves when the user agent is set. - returns: <[Promise]> Promise which resolves when the user agent is set.
@ -3150,6 +3126,115 @@ await resultHandle.dispose();
> **NOTE** Not every execution context is associated with a frame. For example, workers and extensions have execution contexts that are not associated with frames. > **NOTE** Not every execution context is associated with a frame. For example, workers and extensions have execution contexts that are not associated with frames.
### class: Interception
#### interception.abort(request, [errorCode])
- `request` <[Request]>
- `errorCode` <[string]> Optional error code. Defaults to `failed`, could be
one of the following:
- `aborted` - An operation was aborted (due to user action)
- `accessdenied` - Permission to access a resource, other than the network, was denied
- `addressunreachable` - The IP address is unreachable. This usually means
that there is no route to the specified host or network.
- `blockedbyclient` - The client chose to block the request.
- `blockedbyresponse` - The request failed because the response was delivered along with requirements which are not met ('X-Frame-Options' and 'Content-Security-Policy' ancestor checks, for instance).
- `connectionaborted` - A connection timed out as a result of not receiving an ACK for data sent.
- `connectionclosed` - A connection was closed (corresponding to a TCP FIN).
- `connectionfailed` - A connection attempt failed.
- `connectionrefused` - A connection attempt was refused.
- `connectionreset` - A connection was reset (corresponding to a TCP RST).
- `internetdisconnected` - The Internet connection has been lost.
- `namenotresolved` - The host name could not be resolved.
- `timedout` - An operation timed out.
- `failed` - A generic failure occurred.
- returns: <[Promise]>
Aborts request. To use this, request interception should be enabled with `page.interception.enable()`.
Exception is immediately thrown if the request interception is not enabled.
#### interception.continue(request, [overrides])
- `request` <[Request]>
- `overrides` <[Object]> Optional request overwrites, which can be one of the following:
- `url` <[string]> If set, the request url will be changed. This is not a redirect. The request will be silently forwarded to the new url. For example, the address bar will show the original url.
- `method` <[string]> If set changes the request method (e.g. `GET` or `POST`)
- `postData` <[string]> If set changes the post data of request
- `headers` <[Object]> If set changes the request HTTP headers. Header values will be converted to a string.
- returns: <[Promise]>
Continues request with optional request overrides. To use this, request interception should be enabled with `page.interception.enable()`.
Exception is immediately thrown if the request interception is not enabled.
```js
await page.interception.enable();
page.on('request', request => {
// Override headers
const headers = Object.assign({}, request.headers(), {
foo: 'bar', // set "foo" header
origin: undefined, // remove "origin" header
});
page.interception.continue(request, {headers});
});
```
#### interception.disable()
Disables network request interception.
#### interception.enable()
Once request interception is enabled, every request will stall unless it's continued, responded or aborted.
An example of a naïve request interceptor that aborts all image requests:
```js
const playwright = require('playwright');
(async () => {
const browser = await playwright.launch();
const page = await browser.newPage();
await page.interception.enable();
page.on('request', interceptedRequest => {
if (interceptedRequest.url().endsWith('.png') || interceptedRequest.url().endsWith('.jpg'))
page.interception.abort(interceptedRequest);
else
page.interception.continue(interceptedRequest);
});
await page.goto('https://example.com');
await browser.close();
})();
```
> **NOTE** Enabling request interception disables page caching.
#### interception.fulfill(request, response)
- `request` <[Request]>
- `response` <[Object]> Response that will fulfill this request
- `status` <[number]> Response status code, defaults to `200`.
- `headers` <[Object]> Optional response headers. Header values will be converted to a string.
- `contentType` <[string]> If set, equals to setting `Content-Type` response header
- `body` <[string]|[Buffer]> Optional response body
- returns: <[Promise]>
Fulfills request with given response. To use this, request interception should
be enabled with `page.interception.enable()`. Exception is thrown if
request interception is not enabled.
An example of fulfilling all requests with 404 responses:
```js
await page.interception.enable();
page.on('request', request => {
page.interception.respond(request, {
status: 404,
contentType: 'text/plain',
body: 'Not Found!'
});
});
```
> **NOTE** Mocking responses for dataURL requests is not supported.
> Calling `request.respond` for a dataURL request is a noop.
### class: JSHandle ### class: JSHandle
JSHandle represents an in-page JavaScript object. JSHandles can be created with the [page.evaluateHandle](#pageevaluatehandlepagefunction-args) method. JSHandle represents an in-page JavaScript object. JSHandles can be created with the [page.evaluateHandle](#pageevaluatehandlepagefunction-args) method.
@ -3544,52 +3629,6 @@ If request fails at some point, then instead of `'requestfinished'` event (and p
If request gets a 'redirect' response, the request is successfully finished with the 'requestfinished' event, and a new request is issued to a redirected url. If request gets a 'redirect' response, the request is successfully finished with the 'requestfinished' event, and a new request is issued to a redirected url.
#### request.abort([errorCode])
- `errorCode` <[string]> Optional error code. Defaults to `failed`, could be
one of the following:
- `aborted` - An operation was aborted (due to user action)
- `accessdenied` - Permission to access a resource, other than the network, was denied
- `addressunreachable` - The IP address is unreachable. This usually means
that there is no route to the specified host or network.
- `blockedbyclient` - The client chose to block the request.
- `blockedbyresponse` - The request failed because the response was delivered along with requirements which are not met ('X-Frame-Options' and 'Content-Security-Policy' ancestor checks, for instance).
- `connectionaborted` - A connection timed out as a result of not receiving an ACK for data sent.
- `connectionclosed` - A connection was closed (corresponding to a TCP FIN).
- `connectionfailed` - A connection attempt failed.
- `connectionrefused` - A connection attempt was refused.
- `connectionreset` - A connection was reset (corresponding to a TCP RST).
- `internetdisconnected` - The Internet connection has been lost.
- `namenotresolved` - The host name could not be resolved.
- `timedout` - An operation timed out.
- `failed` - A generic failure occurred.
- returns: <[Promise]>
Aborts request. To use this, request interception should be enabled with `page.setRequestInterception`.
Exception is immediately thrown if the request interception is not enabled.
#### request.continue([overrides])
- `overrides` <[Object]> Optional request overwrites, which can be one of the following:
- `url` <[string]> If set, the request url will be changed. This is not a redirect. The request will be silently forwarded to the new url. For example, the address bar will show the original url.
- `method` <[string]> If set changes the request method (e.g. `GET` or `POST`)
- `postData` <[string]> If set changes the post data of request
- `headers` <[Object]> If set changes the request HTTP headers. Header values will be converted to a string.
- returns: <[Promise]>
Continues request with optional request overrides. To use this, request interception should be enabled with `page.setRequestInterception`.
Exception is immediately thrown if the request interception is not enabled.
```js
await page.setRequestInterception(true);
page.on('request', request => {
// Override headers
const headers = Object.assign({}, request.headers(), {
foo: 'bar', // set "foo" header
origin: undefined, // remove "origin" header
});
request.continue({headers});
});
```
#### request.failure() #### request.failure()
- returns: <?[Object]> Object describing request failure, if any - returns: <?[Object]> Object describing request failure, if any
- `errorText` <[string]> Human-readable error message, e.g. `'net::ERR_FAILED'`. - `errorText` <[string]> Human-readable error message, e.g. `'net::ERR_FAILED'`.
@ -3655,34 +3694,6 @@ console.log(chain.length); // 0
Contains the request's resource type as it was perceived by the rendering engine. Contains the request's resource type as it was perceived by the rendering engine.
ResourceType will be one of the following: `document`, `stylesheet`, `image`, `media`, `font`, `script`, `texttrack`, `xhr`, `fetch`, `eventsource`, `websocket`, `manifest`, `other`. ResourceType will be one of the following: `document`, `stylesheet`, `image`, `media`, `font`, `script`, `texttrack`, `xhr`, `fetch`, `eventsource`, `websocket`, `manifest`, `other`.
#### request.respond(response)
- `response` <[Object]> Response that will fulfill this request
- `status` <[number]> Response status code, defaults to `200`.
- `headers` <[Object]> Optional response headers. Header values will be converted to a string.
- `contentType` <[string]> If set, equals to setting `Content-Type` response header
- `body` <[string]|[Buffer]> Optional response body
- returns: <[Promise]>
Fulfills request with given response. To use this, request interception should
be enabled with `page.setRequestInterception`. Exception is thrown if
request interception is not enabled.
An example of fulfilling all requests with 404 responses:
```js
await page.setRequestInterception(true);
page.on('request', request => {
request.respond({
status: 404,
contentType: 'text/plain',
body: 'Not Found!'
});
});
```
> **NOTE** Mocking responses for dataURL requests is not supported.
> Calling `request.respond` for a dataURL request is a noop.
#### request.response() #### request.response()
- returns: <?[Response]> A matching [Response] object, or `null` if the response has not been received yet. - returns: <?[Response]> A matching [Response] object, or `null` if the response has not been received yet.

View file

@ -21,7 +21,7 @@ const playwright = require('playwright');
(async() => { (async() => {
const browser = await playwright.launch(); const browser = await playwright.launch();
const page = await browser.newPage(); const page = await browser.newPage();
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => { page.on('request', request => {
if (request.resourceType() === 'image') if (request.resourceType() === 'image')
request.abort(); request.abort();

View file

@ -334,7 +334,7 @@ export class Request {
}; };
} }
async continue(overrides: { url?: string; method?: string; postData?: string; headers?: {[key: string]: string}; } = {}) { async _continue(overrides: { url?: string; method?: string; postData?: string; headers?: {[key: string]: string}; } = {}) {
// Request interception is not supported for data: urls. // Request interception is not supported for data: urls.
if (this._url.startsWith('data:')) if (this._url.startsWith('data:'))
return; return;
@ -360,7 +360,7 @@ export class Request {
}); });
} }
async respond(response: { status: number; headers: {[key: string]: string}; contentType: string; body: (string | Buffer); }) { async _fulfill(response: { status: number; headers: {[key: string]: string}; contentType: string; body: (string | Buffer); }) {
// Mocking responses for dataURL requests is not currently supported. // Mocking responses for dataURL requests is not currently supported.
if (this._url.startsWith('data:')) if (this._url.startsWith('data:'))
return; return;
@ -393,7 +393,7 @@ export class Request {
}); });
} }
async abort(errorCode: string = 'failed') { async _abort(errorCode: string = 'failed') {
// Request interception is not supported for data: urls. // Request interception is not supported for data: urls.
if (this._url.startsWith('data:')) if (this._url.startsWith('data:'))
return; return;

View file

@ -42,6 +42,7 @@ import { TaskQueue } from './TaskQueue';
import { Geolocation } from './features/geolocation'; import { Geolocation } from './features/geolocation';
import { Tracing } from './features/tracing'; import { Tracing } from './features/tracing';
import { Workers } from './features/workers'; import { Workers } from './features/workers';
import { Interception } from './features/interception';
const writeFileAsync = helper.promisify(fs.writeFile); const writeFileAsync = helper.promisify(fs.writeFile);
@ -66,6 +67,7 @@ export class Page extends EventEmitter {
readonly accessibility: Accessibility; readonly accessibility: Accessibility;
readonly coverage: Coverage; readonly coverage: Coverage;
readonly geolocation: Geolocation; readonly geolocation: Geolocation;
readonly interception: Interception;
readonly pdf: PDF; readonly pdf: PDF;
readonly workers: Workers; readonly workers: Workers;
readonly tracing: Tracing; readonly tracing: Tracing;
@ -100,6 +102,7 @@ export class Page extends EventEmitter {
this.pdf = new PDF(client); this.pdf = new PDF(client);
this.workers = new Workers(client, this._addConsoleMessage.bind(this), this._handleException.bind(this)); this.workers = new Workers(client, this._addConsoleMessage.bind(this), this._handleException.bind(this));
this.geolocation = new Geolocation(client); this.geolocation = new Geolocation(client);
this.interception = new Interception(this._frameManager.networkManager());
this._screenshotTaskQueue = screenshotTaskQueue; this._screenshotTaskQueue = screenshotTaskQueue;
@ -213,10 +216,6 @@ export class Page extends EventEmitter {
return this._frameManager.frames(); return this._frameManager.frames();
} }
async setRequestInterception(value: boolean) {
return this._frameManager.networkManager().setRequestInterception(value);
}
setOfflineMode(enabled: boolean) { setOfflineMode(enabled: boolean) {
return this._frameManager.networkManager().setOfflineMode(enabled); return this._frameManager.networkManager().setOfflineMode(enabled);
} }

View file

@ -11,6 +11,7 @@ export { ExecutionContext } from './ExecutionContext';
export { Accessibility } from './features/accessibility'; export { Accessibility } from './features/accessibility';
export { Coverage } from './features/coverage'; export { Coverage } from './features/coverage';
export { Geolocation } from './features/geolocation'; export { Geolocation } from './features/geolocation';
export { Interception } from './features/interception';
export { PDF } from './features/pdf'; export { PDF } from './features/pdf';
export { Permissions } from './features/permissions'; export { Permissions } from './features/permissions';
export { Tracing } from './features/tracing'; export { Tracing } from './features/tracing';
@ -22,3 +23,4 @@ export { Request, Response } from './NetworkManager';
export { ConsoleMessage, FileChooser, Page } from './Page'; export { ConsoleMessage, FileChooser, Page } from './Page';
export { Playwright } from './Playwright'; export { Playwright } from './Playwright';
export { Target } from './Target'; export { Target } from './Target';

View file

@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { NetworkManager, Request } from '../NetworkManager';
export class Interception {
private _networkManager: NetworkManager;
constructor(networkManager: NetworkManager) {
this._networkManager = networkManager;
}
enable() {
this._networkManager.setRequestInterception(true);
}
disable() {
this._networkManager.setRequestInterception(false);
}
async continue(request: Request, overrides: { url?: string; method?: string; postData?: string; headers?: {[key: string]: string}; } = {}) {
return request._continue(overrides);
}
async fulfill(request: Request, response: { status: number; headers: {[key: string]: string}; contentType: string; body: (string | Buffer); }) {
return request._fulfill(response);
}
async abort(request: Request, errorCode: string = 'failed') {
return request._abort(errorCode);
}
}

View file

@ -169,7 +169,7 @@ export class Request {
return this._errorText ? {errorText: this._errorText} : null; return this._errorText ? {errorText: this._errorText} : null;
} }
async continue(overrides: any = {}) { async _continue(overrides: any = {}) {
assert(!overrides.url, 'Playwright-Firefox does not support overriding URL'); assert(!overrides.url, 'Playwright-Firefox does not support overriding URL');
assert(!overrides.method, 'Playwright-Firefox does not support overriding method'); assert(!overrides.method, 'Playwright-Firefox does not support overriding method');
assert(!overrides.postData, 'Playwright-Firefox does not support overriding postData'); assert(!overrides.postData, 'Playwright-Firefox does not support overriding postData');
@ -187,7 +187,7 @@ export class Request {
}); });
} }
async abort() { async _abort() {
assert(this._suspended, 'Request Interception is not enabled!'); assert(this._suspended, 'Request Interception is not enabled!');
assert(!this._interceptionHandled, 'Request is already handled!'); assert(!this._interceptionHandled, 'Request is already handled!');
this._interceptionHandled = true; this._interceptionHandled = true;

View file

@ -9,6 +9,7 @@ import { Connection, JugglerSession, JugglerSessionEvents } from './Connection';
import { Dialog } from './Dialog'; import { Dialog } from './Dialog';
import { Events } from './events'; import { Events } from './events';
import { Accessibility } from './features/accessibility'; import { Accessibility } from './features/accessibility';
import { Interception } from './features/interception';
import { FrameManager, FrameManagerEvents, normalizeWaitUntil } from './FrameManager'; import { FrameManager, FrameManagerEvents, normalizeWaitUntil } from './FrameManager';
import { Keyboard, Mouse } from './Input'; import { Keyboard, Mouse } from './Input';
import { createHandle, ElementHandle, JSHandle } from './JSHandle'; import { createHandle, ElementHandle, JSHandle } from './JSHandle';
@ -25,6 +26,7 @@ export class Page extends EventEmitter {
private _keyboard: Keyboard; private _keyboard: Keyboard;
private _mouse: Mouse; private _mouse: Mouse;
readonly accessibility: Accessibility; readonly accessibility: Accessibility;
readonly interception: Interception;
private _closed: boolean; private _closed: boolean;
private _pageBindings: Map<string, Function>; private _pageBindings: Map<string, Function>;
private _networkManager: NetworkManager; private _networkManager: NetworkManager;
@ -59,6 +61,7 @@ export class Page extends EventEmitter {
this._networkManager = new NetworkManager(session); this._networkManager = new NetworkManager(session);
this._frameManager = new FrameManager(session, this, this._networkManager, this._timeoutSettings); this._frameManager = new FrameManager(session, this, this._networkManager, this._timeoutSettings);
this._networkManager.setFrameManager(this._frameManager); this._networkManager.setFrameManager(this._frameManager);
this.interception = new Interception(this._networkManager);
this._eventListeners = [ this._eventListeners = [
helper.addEventListener(this._session, 'Page.uncaughtError', this._onUncaughtError.bind(this)), helper.addEventListener(this._session, 'Page.uncaughtError', this._onUncaughtError.bind(this)),
helper.addEventListener(this._session, 'Runtime.console', this._onConsole.bind(this)), helper.addEventListener(this._session, 'Runtime.console', this._onConsole.bind(this)),
@ -137,10 +140,6 @@ export class Page extends EventEmitter {
} }
} }
async setRequestInterception(enabled) {
await this._networkManager.setRequestInterception(enabled);
}
async setExtraHTTPHeaders(headers) { async setExtraHTTPHeaders(headers) {
await this._networkManager.setExtraHTTPHeaders(headers); await this._networkManager.setExtraHTTPHeaders(headers);
} }

View file

@ -7,6 +7,7 @@ export { BrowserFetcher } from './BrowserFetcher';
export { Dialog } from './Dialog'; export { Dialog } from './Dialog';
export { ExecutionContext } from './ExecutionContext'; export { ExecutionContext } from './ExecutionContext';
export { Accessibility } from './features/accessibility'; export { Accessibility } from './features/accessibility';
export { Interception } from './features/interception';
export { Permissions } from './features/permissions'; export { Permissions } from './features/permissions';
export { Frame } from './FrameManager'; export { Frame } from './FrameManager';
export { Keyboard, Mouse } from './Input'; export { Keyboard, Mouse } from './Input';
@ -14,3 +15,4 @@ export { ElementHandle, JSHandle } from './JSHandle';
export { Request, Response } from './NetworkManager'; export { Request, Response } from './NetworkManager';
export { ConsoleMessage, Page } from './Page'; export { ConsoleMessage, Page } from './Page';
export { Playwright } from './Playwright'; export { Playwright } from './Playwright';

View file

@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { NetworkManager, Request } from '../NetworkManager';
export class Interception {
private _networkManager: NetworkManager;
constructor(networkManager: NetworkManager) {
this._networkManager = networkManager;
}
enable() {
this._networkManager.setRequestInterception(true);
}
disable() {
this._networkManager.setRequestInterception(false);
}
async continue(request: Request, overrides: { url?: string; method?: string; postData?: string; headers?: {[key: string]: string}; } = {}) {
return request._continue(overrides);
}
async fulfill(request: Request, response: { status: number; headers: {[key: string]: string}; contentType: string; body: (string | Buffer); }) {
throw new Error('Not implemented');
}
async abort(request: Request, errorCode: string = 'failed') {
return request._abort();
}
}

View file

@ -132,8 +132,8 @@ module.exports.addPageTests = function({testRunner, expect}) {
res.end('console.log(1);'); res.end('console.log(1);');
}); });
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => request.continue()); page.on('request', request => page.interception.continue(request));
await page.goto(server.PREFIX + '/intervention'); await page.goto(server.PREFIX + '/intervention');
// Check for feature URL substring rather than https://www.chromestatus.com to // Check for feature URL substring rather than https://www.chromestatus.com to
// make it work with Edgium. // make it work with Edgium.

View file

@ -93,7 +93,7 @@ module.exports.addTests = function({testRunner, expect, playwright, defaultBrows
const browser = await playwright.launch(headfulOptions); const browser = await playwright.launch(headfulOptions);
const page = await browser.newPage(); const page = await browser.newPage();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', r => r.respond({body: 'YO, GOOGLE.COM'})); page.on('request', r => r.respond({body: 'YO, GOOGLE.COM'}));
await page.evaluate(() => { await page.evaluate(() => {
const frame = document.createElement('iframe'); const frame = document.createElement('iframe');

View file

@ -43,7 +43,7 @@ module.exports.addTests = function({testRunner, expect, defaultBrowserOptions, p
expect(response.ok()).toBe(true); expect(response.ok()).toBe(true);
}); });
it('should work with request interception', async({page, server, httpsServer}) => { it('should work with request interception', async({page, server, httpsServer}) => {
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => request.continue()); page.on('request', request => request.continue());
const response = await page.goto(httpsServer.EMPTY_PAGE); const response = await page.goto(httpsServer.EMPTY_PAGE);
expect(response.status()).toBe(200); expect(response.status()).toBe(200);

View file

@ -235,7 +235,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
// FIXME: requires request interception. // FIXME: requires request interception.
it.skip(WEBKIT)('Page.Events.RequestFailed', async({page, server}) => { it.skip(WEBKIT)('Page.Events.RequestFailed', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => { page.on('request', request => {
if (request.url().endsWith('css')) if (request.url().endsWith('css'))
request.abort(); request.abort();
@ -318,7 +318,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
requests.set(request.url().split('/').pop(), request); requests.set(request.url().split('/').pop(), request);
request.continue(); request.continue();
}); });
await page.setRequestInterception(true); await page.interception.enable();
server.setRedirect('/rrredirect', '/frames/one-frame.html'); server.setRedirect('/rrredirect', '/frames/one-frame.html');
await page.goto(server.PREFIX + '/rrredirect'); await page.goto(server.PREFIX + '/rrredirect');
expect(requests.get('rrredirect').isNavigationRequest()).toBe(true); expect(requests.get('rrredirect').isNavigationRequest()).toBe(true);

View file

@ -44,7 +44,7 @@ module.exports.addTests = function({testRunner, expect, defaultBrowserOptions, p
expect(page.frames().length).toBe(2); expect(page.frames().length).toBe(2);
}); });
it('should load oopif iframes with subresources and request interception', async function({page, server, context}) { it('should load oopif iframes with subresources and request interception', async function({page, server, context}) {
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => request.continue()); page.on('request', request => request.continue());
await page.goto(server.PREFIX + '/dynamic-oopif.html'); await page.goto(server.PREFIX + '/dynamic-oopif.html');
expect(oopifs(context).length).toBe(1); expect(oopifs(context).length).toBe(1);

View file

@ -864,8 +864,8 @@ module.exports.addTests = function({testRunner, expect, headless, playwright, FF
}); });
it.skip(WEBKIT)('should stay disabled when toggling request interception on/off', async({page, server}) => { it.skip(WEBKIT)('should stay disabled when toggling request interception on/off', async({page, server}) => {
await page.setCacheEnabled(false); await page.setCacheEnabled(false);
await page.setRequestInterception(true); await page.interception.enable();
await page.setRequestInterception(false); await page.interception.disable();
await page.goto(server.PREFIX + '/cached/one-style.html'); await page.goto(server.PREFIX + '/cached/one-style.html');
const [nonCachedRequest] = await Promise.all([ const [nonCachedRequest] = await Promise.all([

View file

@ -23,12 +23,12 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
const {it, fit, xit} = testRunner; const {it, fit, xit} = testRunner;
const {beforeAll, beforeEach, afterAll, afterEach} = testRunner; const {beforeAll, beforeEach, afterAll, afterEach} = testRunner;
describe.skip(WEBKIT)('Page.setRequestInterception', function() { describe.skip(WEBKIT)('Interception.enable', function() {
it('should intercept', async({page, server}) => { it('should intercept', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => { page.on('request', request => {
if (utils.isFavicon(request)) { if (utils.isFavicon(request)) {
request.continue(); page.interception.continue(request);
return; return;
} }
expect(request.url()).toContain('empty.html'); expect(request.url()).toContain('empty.html');
@ -39,7 +39,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
expect(request.resourceType()).toBe('document'); expect(request.resourceType()).toBe('document');
expect(request.frame() === page.mainFrame()).toBe(true); expect(request.frame() === page.mainFrame()).toBe(true);
expect(request.frame().url()).toBe('about:blank'); expect(request.frame().url()).toBe('about:blank');
request.continue(); page.interception.continue(request);
}); });
const response = await page.goto(server.EMPTY_PAGE); const response = await page.goto(server.EMPTY_PAGE);
expect(response.ok()).toBe(true); expect(response.ok()).toBe(true);
@ -48,8 +48,8 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
it('should work when POST is redirected with 302', async({page, server}) => { it('should work when POST is redirected with 302', async({page, server}) => {
server.setRedirect('/rredirect', '/empty.html'); server.setRedirect('/rredirect', '/empty.html');
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => request.continue()); page.on('request', request => page.interception.continue(request));
await page.setContent(` await page.setContent(`
<form action='/rredirect' method='post'> <form action='/rredirect' method='post'>
<input type="hidden" id="foo" name="foo" value="FOOBAR"> <input type="hidden" id="foo" name="foo" value="FOOBAR">
@ -63,24 +63,24 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
// @see https://github.com/GoogleChrome/puppeteer/issues/3973 // @see https://github.com/GoogleChrome/puppeteer/issues/3973
it('should work when header manipulation headers with redirect', async({page, server}) => { it('should work when header manipulation headers with redirect', async({page, server}) => {
server.setRedirect('/rrredirect', '/empty.html'); server.setRedirect('/rrredirect', '/empty.html');
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => { page.on('request', request => {
const headers = Object.assign({}, request.headers(), { const headers = Object.assign({}, request.headers(), {
foo: 'bar' foo: 'bar'
}); });
request.continue({ headers }); page.interception.continue(request, { headers });
}); });
await page.goto(server.PREFIX + '/rrredirect'); await page.goto(server.PREFIX + '/rrredirect');
}); });
// @see https://github.com/GoogleChrome/puppeteer/issues/4743 // @see https://github.com/GoogleChrome/puppeteer/issues/4743
it('should be able to remove headers', async({page, server}) => { it('should be able to remove headers', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => { page.on('request', request => {
const headers = Object.assign({}, request.headers(), { const headers = Object.assign({}, request.headers(), {
foo: 'bar', foo: 'bar',
origin: undefined, // remove "origin" header origin: undefined, // remove "origin" header
}); });
request.continue({ headers }); page.interception.continue(request, { headers });
}); });
const [serverRequest] = await Promise.all([ const [serverRequest] = await Promise.all([
@ -91,12 +91,12 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
expect(serverRequest.headers.origin).toBe(undefined); expect(serverRequest.headers.origin).toBe(undefined);
}); });
it('should contain referer header', async({page, server}) => { it('should contain referer header', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
const requests = []; const requests = [];
page.on('request', request => { page.on('request', request => {
if (!utils.isFavicon(request)) if (!utils.isFavicon(request))
requests.push(request); requests.push(request);
request.continue(); page.interception.continue(request);
}); });
await page.goto(server.PREFIX + '/one-style.html'); await page.goto(server.PREFIX + '/one-style.html');
expect(requests[1].url()).toContain('/one-style.css'); expect(requests[1].url()).toContain('/one-style.css');
@ -108,26 +108,26 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
await page.setCookie({ name: 'foo', value: 'bar'}); await page.setCookie({ name: 'foo', value: 'bar'});
// Setup request interception. // Setup request interception.
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => request.continue()); page.on('request', request => page.interception.continue(request));
const response = await page.reload(); const response = await page.reload();
expect(response.status()).toBe(200); expect(response.status()).toBe(200);
}); });
it('should stop intercepting', async({page, server}) => { it('should stop intercepting', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
page.once('request', request => request.continue()); page.once('request', request => page.interception.continue(request));
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setRequestInterception(false); await page.interception.disable();
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
}); });
it('should show custom HTTP headers', async({page, server}) => { it('should show custom HTTP headers', async({page, server}) => {
await page.setExtraHTTPHeaders({ await page.setExtraHTTPHeaders({
foo: 'bar' foo: 'bar'
}); });
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => { page.on('request', request => {
expect(request.headers()['foo']).toBe('bar'); expect(request.headers()['foo']).toBe('bar');
request.continue(); page.interception.continue(request);
}); });
const response = await page.goto(server.EMPTY_PAGE); const response = await page.goto(server.EMPTY_PAGE);
expect(response.ok()).toBe(true); expect(response.ok()).toBe(true);
@ -136,8 +136,8 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
it('should work with redirect inside sync XHR', async({page, server}) => { it('should work with redirect inside sync XHR', async({page, server}) => {
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
server.setRedirect('/logo.png', '/pptr.png'); server.setRedirect('/logo.png', '/pptr.png');
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => request.continue()); page.on('request', request => page.interception.continue(request));
const status = await page.evaluate(async() => { const status = await page.evaluate(async() => {
const request = new XMLHttpRequest(); const request = new XMLHttpRequest();
request.open('GET', '/logo.png', false); // `false` makes the request synchronous request.open('GET', '/logo.png', false); // `false` makes the request synchronous
@ -148,21 +148,21 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
}); });
it('should work with custom referer headers', async({page, server}) => { it('should work with custom referer headers', async({page, server}) => {
await page.setExtraHTTPHeaders({ 'referer': server.EMPTY_PAGE }); await page.setExtraHTTPHeaders({ 'referer': server.EMPTY_PAGE });
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => { page.on('request', request => {
expect(request.headers()['referer']).toBe(server.EMPTY_PAGE); expect(request.headers()['referer']).toBe(server.EMPTY_PAGE);
request.continue(); page.interception.continue(request);
}); });
const response = await page.goto(server.EMPTY_PAGE); const response = await page.goto(server.EMPTY_PAGE);
expect(response.ok()).toBe(true); expect(response.ok()).toBe(true);
}); });
it('should be abortable', async({page, server}) => { it('should be abortable', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => { page.on('request', request => {
if (request.url().endsWith('.css')) if (request.url().endsWith('.css'))
request.abort(); page.interception.abort(request);
else else
request.continue(); page.interception.continue(request);
}); });
let failedRequests = 0; let failedRequests = 0;
page.on('requestfailed', event => ++failedRequests); page.on('requestfailed', event => ++failedRequests);
@ -172,9 +172,9 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
expect(failedRequests).toBe(1); expect(failedRequests).toBe(1);
}); });
it.skip(FFOX)('should be abortable with custom error codes', async({page, server}) => { it.skip(FFOX)('should be abortable with custom error codes', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => { page.on('request', request => {
request.abort('internetdisconnected'); page.interception.abort(request, 'internetdisconnected');
}); });
let failedRequest = null; let failedRequest = null;
page.on('requestfailed', request => failedRequest = request); page.on('requestfailed', request => failedRequest = request);
@ -186,8 +186,8 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
await page.setExtraHTTPHeaders({ await page.setExtraHTTPHeaders({
referer: 'http://google.com/' referer: 'http://google.com/'
}); });
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => request.continue()); page.on('request', request => page.interception.continue(request));
const [request] = await Promise.all([ const [request] = await Promise.all([
server.waitForRequest('/grid.html'), server.waitForRequest('/grid.html'),
page.goto(server.PREFIX + '/grid.html'), page.goto(server.PREFIX + '/grid.html'),
@ -195,8 +195,8 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
expect(request.headers['referer']).toBe('http://google.com/'); expect(request.headers['referer']).toBe('http://google.com/');
}); });
it('should fail navigation when aborting main resource', async({page, server}) => { it('should fail navigation when aborting main resource', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => request.abort()); page.on('request', request => page.interception.abort(request));
let error = null; let error = null;
await page.goto(server.EMPTY_PAGE).catch(e => error = e); await page.goto(server.EMPTY_PAGE).catch(e => error = e);
expect(error).toBeTruthy(); expect(error).toBeTruthy();
@ -206,10 +206,10 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
expect(error.message).toContain('NS_ERROR_FAILURE'); expect(error.message).toContain('NS_ERROR_FAILURE');
}); });
it('should work with redirects', async({page, server}) => { it('should work with redirects', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
const requests = []; const requests = [];
page.on('request', request => { page.on('request', request => {
request.continue(); page.interception.continue(request);
requests.push(request); requests.push(request);
}); });
server.setRedirect('/non-existing-page.html', '/non-existing-page-2.html'); server.setRedirect('/non-existing-page.html', '/non-existing-page-2.html');
@ -233,10 +233,10 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
} }
}); });
it('should work with redirects for subresources', async({page, server}) => { it('should work with redirects for subresources', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
const requests = []; const requests = [];
page.on('request', request => { page.on('request', request => {
request.continue(); page.interception.continue(request);
if (!utils.isFavicon(request)) if (!utils.isFavicon(request))
requests.push(request); requests.push(request);
}); });
@ -258,14 +258,14 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
expect(redirectChain[2].url()).toContain('/three-style.css'); expect(redirectChain[2].url()).toContain('/three-style.css');
}); });
it('should be able to abort redirects', async({page, server}) => { it('should be able to abort redirects', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
server.setRedirect('/non-existing.json', '/non-existing-2.json'); server.setRedirect('/non-existing.json', '/non-existing-2.json');
server.setRedirect('/non-existing-2.json', '/simple.html'); server.setRedirect('/non-existing-2.json', '/simple.html');
page.on('request', request => { page.on('request', request => {
if (request.url().includes('non-existing-2')) if (request.url().includes('non-existing-2'))
request.abort(); page.interception.abort(request);
else else
request.continue(); page.interception.continue(request);
}); });
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const result = await page.evaluate(async() => { const result = await page.evaluate(async() => {
@ -284,16 +284,16 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
let responseCount = 1; let responseCount = 1;
server.setRoute('/zzz', (req, res) => res.end((responseCount++) * 11 + '')); server.setRoute('/zzz', (req, res) => res.end((responseCount++) * 11 + ''));
await page.setRequestInterception(true); await page.interception.enable();
let spinner = false; let spinner = false;
// Cancel 2nd request. // Cancel 2nd request.
page.on('request', request => { page.on('request', request => {
if (utils.isFavicon(request)) { if (utils.isFavicon(request)) {
request.continue(); page.interception.continue(request);
return; return;
} }
spinner ? request.abort() : request.continue(); spinner ? page.interception.abort(request) : page.interception.continue(request);
spinner = !spinner; spinner = !spinner;
}); });
const results = await page.evaluate(() => Promise.all([ const results = await page.evaluate(() => Promise.all([
@ -304,11 +304,11 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
expect(results).toEqual(['11', 'FAILED', '22']); expect(results).toEqual(['11', 'FAILED', '22']);
}); });
it.skip(FFOX)('should navigate to dataURL and fire dataURL requests', async({page, server}) => { it.skip(FFOX)('should navigate to dataURL and fire dataURL requests', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
const requests = []; const requests = [];
page.on('request', request => { page.on('request', request => {
requests.push(request); requests.push(request);
request.continue(); page.interception.continue(request);
}); });
const dataURL = 'data:text/html,<div>yo</div>'; const dataURL = 'data:text/html,<div>yo</div>';
const response = await page.goto(dataURL); const response = await page.goto(dataURL);
@ -318,11 +318,11 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
}); });
it.skip(FFOX)('should be able to fetch dataURL and fire dataURL requests', async({page, server}) => { it.skip(FFOX)('should be able to fetch dataURL and fire dataURL requests', async({page, server}) => {
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setRequestInterception(true); await page.interception.enable();
const requests = []; const requests = [];
page.on('request', request => { page.on('request', request => {
requests.push(request); requests.push(request);
request.continue(); page.interception.continue(request);
}); });
const dataURL = 'data:text/html,<div>yo</div>'; const dataURL = 'data:text/html,<div>yo</div>';
const text = await page.evaluate(url => fetch(url).then(r => r.text()), dataURL); const text = await page.evaluate(url => fetch(url).then(r => r.text()), dataURL);
@ -331,11 +331,11 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
expect(requests[0].url()).toBe(dataURL); expect(requests[0].url()).toBe(dataURL);
}); });
it.skip(FFOX)('should navigate to URL with hash and and fire requests without hash', async({page, server}) => { it.skip(FFOX)('should navigate to URL with hash and and fire requests without hash', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
const requests = []; const requests = [];
page.on('request', request => { page.on('request', request => {
requests.push(request); requests.push(request);
request.continue(); page.interception.continue(request);
}); });
const response = await page.goto(server.EMPTY_PAGE + '#hash'); const response = await page.goto(server.EMPTY_PAGE + '#hash');
expect(response.status()).toBe(200); expect(response.status()).toBe(200);
@ -346,25 +346,25 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
it('should work with encoded server', async({page, server}) => { it('should work with encoded server', async({page, server}) => {
// The requestWillBeSent will report encoded URL, whereas interception will // The requestWillBeSent will report encoded URL, whereas interception will
// report URL as-is. @see crbug.com/759388 // report URL as-is. @see crbug.com/759388
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => request.continue()); page.on('request', request => page.interception.continue(request));
const response = await page.goto(server.PREFIX + '/some nonexisting page'); const response = await page.goto(server.PREFIX + '/some nonexisting page');
expect(response.status()).toBe(404); expect(response.status()).toBe(404);
}); });
it('should work with badly encoded server', async({page, server}) => { it('should work with badly encoded server', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
server.setRoute('/malformed?rnd=%911', (req, res) => res.end()); server.setRoute('/malformed?rnd=%911', (req, res) => res.end());
page.on('request', request => request.continue()); page.on('request', request => page.interception.continue(request));
const response = await page.goto(server.PREFIX + '/malformed?rnd=%911'); const response = await page.goto(server.PREFIX + '/malformed?rnd=%911');
expect(response.status()).toBe(200); expect(response.status()).toBe(200);
}); });
it.skip(FFOX)('should work with encoded server - 2', async({page, server}) => { it.skip(FFOX)('should work with encoded server - 2', async({page, server}) => {
// The requestWillBeSent will report URL as-is, whereas interception will // The requestWillBeSent will report URL as-is, whereas interception will
// report encoded URL for stylesheet. @see crbug.com/759388 // report encoded URL for stylesheet. @see crbug.com/759388
await page.setRequestInterception(true); await page.interception.enable();
const requests = []; const requests = [];
page.on('request', request => { page.on('request', request => {
request.continue(); page.interception.continue(request);
requests.push(request); requests.push(request);
}); });
const response = await page.goto(`data:text/html,<link rel="stylesheet" href="${server.PREFIX}/fonts?helvetica|arial"/>`); const response = await page.goto(`data:text/html,<link rel="stylesheet" href="${server.PREFIX}/fonts?helvetica|arial"/>`);
@ -374,7 +374,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
}); });
it.skip(FFOX)('should not throw "Invalid Interception Id" if the request was cancelled', async({page, server}) => { it.skip(FFOX)('should not throw "Invalid Interception Id" if the request was cancelled', async({page, server}) => {
await page.setContent('<iframe></iframe>'); await page.setContent('<iframe></iframe>');
await page.setRequestInterception(true); await page.interception.enable();
let request = null; let request = null;
page.on('request', async r => request = r); page.on('request', async r => request = r);
page.$eval('iframe', (frame, url) => frame.src = url, server.EMPTY_PAGE), page.$eval('iframe', (frame, url) => frame.src = url, server.EMPTY_PAGE),
@ -383,14 +383,14 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
// Delete frame to cause request to be canceled. // Delete frame to cause request to be canceled.
await page.$eval('iframe', frame => frame.remove()); await page.$eval('iframe', frame => frame.remove());
let error = null; let error = null;
await request.continue().catch(e => error = e); await page.interception.continue(request).catch(e => error = e);
expect(error).toBe(null); expect(error).toBe(null);
}); });
it('should throw if interception is not enabled', async({page, server}) => { it('should throw if interception is not enabled', async({page, server}) => {
let error = null; let error = null;
page.on('request', async request => { page.on('request', async request => {
try { try {
await request.continue(); await page.interception.continue(request);
} catch (e) { } catch (e) {
error = e; error = e;
} }
@ -399,11 +399,11 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
expect(error.message).toContain('Request Interception is not enabled'); expect(error.message).toContain('Request Interception is not enabled');
}); });
it.skip(FFOX)('should work with file URLs', async({page, server}) => { it.skip(FFOX)('should work with file URLs', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
const urls = new Set(); const urls = new Set();
page.on('request', request => { page.on('request', request => {
urls.add(request.url().split('/').pop()); urls.add(request.url().split('/').pop());
request.continue(); page.interception.continue(request);
}); });
await page.goto(pathToFileURL(path.join(__dirname, 'assets', 'one-style.html'))); await page.goto(pathToFileURL(path.join(__dirname, 'assets', 'one-style.html')));
expect(urls.size).toBe(2); expect(urls.size).toBe(2);
@ -412,18 +412,18 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
}); });
}); });
describe.skip(WEBKIT)('Request.continue', function() { describe.skip(WEBKIT)('Interception.continue', function() {
it('should work', async({page, server}) => { it('should work', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => request.continue()); page.on('request', request => page.interception.continue(request));
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
}); });
it('should amend HTTP headers', async({page, server}) => { it('should amend HTTP headers', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => { page.on('request', request => {
const headers = Object.assign({}, request.headers()); const headers = Object.assign({}, request.headers());
headers['FOO'] = 'bar'; headers['FOO'] = 'bar';
request.continue({ headers }); page.interception.continue(request, { headers });
}); });
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
const [request] = await Promise.all([ const [request] = await Promise.all([
@ -433,10 +433,10 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
expect(request.headers['foo']).toBe('bar'); expect(request.headers['foo']).toBe('bar');
}); });
it.skip(FFOX)('should redirect in a way non-observable to page', async({page, server}) => { it.skip(FFOX)('should redirect in a way non-observable to page', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => { page.on('request', request => {
const redirectURL = request.url().includes('/empty.html') ? server.PREFIX + '/consolelog.html' : undefined; const redirectURL = request.url().includes('/empty.html') ? server.PREFIX + '/consolelog.html' : undefined;
request.continue({ url: redirectURL }); page.interception.continue(request, { url: redirectURL });
}); });
let consoleMessage = null; let consoleMessage = null;
page.on('console', msg => consoleMessage = msg); page.on('console', msg => consoleMessage = msg);
@ -447,9 +447,9 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
it.skip(FFOX)('should amend method', async({page, server}) => { it.skip(FFOX)('should amend method', async({page, server}) => {
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => { page.on('request', request => {
request.continue({ method: 'POST' }); page.interception.continue(request, { method: 'POST' });
}); });
const [request] = await Promise.all([ const [request] = await Promise.all([
server.waitForRequest('/sleep.zzz'), server.waitForRequest('/sleep.zzz'),
@ -460,9 +460,9 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
it.skip(FFOX)('should amend post data', async({page, server}) => { it.skip(FFOX)('should amend post data', async({page, server}) => {
await page.goto(server.EMPTY_PAGE); await page.goto(server.EMPTY_PAGE);
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => { page.on('request', request => {
request.continue({ postData: 'doggo' }); page.interception.continue(request, { postData: 'doggo' });
}); });
const [serverRequest] = await Promise.all([ const [serverRequest] = await Promise.all([
server.waitForRequest('/sleep.zzz'), server.waitForRequest('/sleep.zzz'),
@ -471,9 +471,9 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
expect(await serverRequest.postBody).toBe('doggo'); expect(await serverRequest.postBody).toBe('doggo');
}); });
it.skip(FFOX)('should amend both post data and method on navigation', async({page, server}) => { it.skip(FFOX)('should amend both post data and method on navigation', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => { page.on('request', request => {
request.continue({ method: 'POST', postData: 'doggo' }); page.interception.continue(request, { method: 'POST', postData: 'doggo' });
}); });
const [serverRequest] = await Promise.all([ const [serverRequest] = await Promise.all([
server.waitForRequest('/empty.html'), server.waitForRequest('/empty.html'),
@ -484,11 +484,11 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
}); });
}); });
describe.skip(FFOX || WEBKIT)('Request.respond', function() { describe.skip(FFOX || WEBKIT)('interception.fulfill', function() {
it('should work', async({page, server}) => { it('should work', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => { page.on('request', request => {
request.respond({ page.interception.fulfill(request, {
status: 201, status: 201,
headers: { headers: {
foo: 'bar' foo: 'bar'
@ -502,9 +502,9 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
expect(await page.evaluate(() => document.body.textContent)).toBe('Yo, page!'); expect(await page.evaluate(() => document.body.textContent)).toBe('Yo, page!');
}); });
it('should work with status code 422', async({page, server}) => { it('should work with status code 422', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => { page.on('request', request => {
request.respond({ page.interception.fulfill(request, {
status: 422, status: 422,
body: 'Yo, page!' body: 'Yo, page!'
}); });
@ -515,13 +515,13 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
expect(await page.evaluate(() => document.body.textContent)).toBe('Yo, page!'); expect(await page.evaluate(() => document.body.textContent)).toBe('Yo, page!');
}); });
it('should redirect', async({page, server}) => { it('should redirect', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => { page.on('request', request => {
if (!request.url().includes('rrredirect')) { if (!request.url().includes('rrredirect')) {
request.continue(); page.interception.continue(request);
return; return;
} }
request.respond({ page.interception.fulfill(request, {
status: 302, status: 302,
headers: { headers: {
location: server.EMPTY_PAGE, location: server.EMPTY_PAGE,
@ -534,10 +534,10 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
expect(response.url()).toBe(server.EMPTY_PAGE); expect(response.url()).toBe(server.EMPTY_PAGE);
}); });
it('should allow mocking binary responses', async({page, server}) => { it('should allow mocking binary responses', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => { page.on('request', request => {
const imageBuffer = fs.readFileSync(path.join(__dirname, 'assets', 'pptr.png')); const imageBuffer = fs.readFileSync(path.join(__dirname, 'assets', 'pptr.png'));
request.respond({ page.interception.fulfill(request, {
contentType: 'image/png', contentType: 'image/png',
body: imageBuffer body: imageBuffer
}); });
@ -552,9 +552,9 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
expect(await img.screenshot()).toBeGolden('mock-binary-response.png'); expect(await img.screenshot()).toBeGolden('mock-binary-response.png');
}); });
it('should stringify intercepted request response headers', async({page, server}) => { it('should stringify intercepted request response headers', async({page, server}) => {
await page.setRequestInterception(true); await page.interception.enable();
page.on('request', request => { page.on('request', request => {
request.respond({ page.interception.fulfill(request, {
status: 200, status: 200,
headers: { headers: {
'foo': true 'foo': true

View file

@ -99,7 +99,7 @@ playwright.launch().then(async browser => {
await page.emulateMedia("screen"); await page.emulateMedia("screen");
await page.pdf({ path: "page.pdf" }); await page.pdf({ path: "page.pdf" });
await page.setRequestInterception(true); await page.interception.enable();
page.on("request", interceptedRequest => { page.on("request", interceptedRequest => {
if ( if (
interceptedRequest.url().endsWith(".png") || interceptedRequest.url().endsWith(".png") ||