feat(route): migrate from request interception w/ events to page.route (#809)
This commit is contained in:
parent
84edefd087
commit
8028fb052a
73
docs/api.md
73
docs/api.md
|
|
@ -470,6 +470,7 @@ page.removeListener('request', logRequest);
|
||||||
- [page.opener()](#pageopener)
|
- [page.opener()](#pageopener)
|
||||||
- [page.pdf([options])](#pagepdfoptions)
|
- [page.pdf([options])](#pagepdfoptions)
|
||||||
- [page.reload([options])](#pagereloadoptions)
|
- [page.reload([options])](#pagereloadoptions)
|
||||||
|
- [page.route(url, handler)](#pagerouteurl-handler)
|
||||||
- [page.screenshot([options])](#pagescreenshotoptions)
|
- [page.screenshot([options])](#pagescreenshotoptions)
|
||||||
- [page.select(selector, value, options)](#pageselectselector-value-options)
|
- [page.select(selector, value, options)](#pageselectselector-value-options)
|
||||||
- [page.setCacheEnabled([enabled])](#pagesetcacheenabledenabled)
|
- [page.setCacheEnabled([enabled])](#pagesetcacheenabledenabled)
|
||||||
|
|
@ -478,7 +479,6 @@ page.removeListener('request', logRequest);
|
||||||
- [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout)
|
- [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout)
|
||||||
- [page.setExtraHTTPHeaders(headers)](#pagesetextrahttpheadersheaders)
|
- [page.setExtraHTTPHeaders(headers)](#pagesetextrahttpheadersheaders)
|
||||||
- [page.setOfflineMode(enabled)](#pagesetofflinemodeenabled)
|
- [page.setOfflineMode(enabled)](#pagesetofflinemodeenabled)
|
||||||
- [page.setRequestInterception(enabled)](#pagesetrequestinterceptionenabled)
|
|
||||||
- [page.setViewport(viewport)](#pagesetviewportviewport)
|
- [page.setViewport(viewport)](#pagesetviewportviewport)
|
||||||
- [page.title()](#pagetitle)
|
- [page.title()](#pagetitle)
|
||||||
- [page.tripleclick(selector[, options])](#pagetripleclickselector-options)
|
- [page.tripleclick(selector[, options])](#pagetripleclickselector-options)
|
||||||
|
|
@ -585,7 +585,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(true)`.
|
In order to intercept and mutate requests, see `page.route()`.
|
||||||
|
|
||||||
#### event: 'requestfailed'
|
#### event: 'requestfailed'
|
||||||
- <[Request]>
|
- <[Request]>
|
||||||
|
|
@ -1181,6 +1181,36 @@ The `format` options are:
|
||||||
- `'networkidle2'` - consider navigation to be finished when there are no more than 2 network connections for at least `500` ms.
|
- `'networkidle2'` - consider navigation to be finished when there are no more than 2 network connections for at least `500` ms.
|
||||||
- returns: <[Promise]<[Response]>> Promise which resolves to the main resource response. In case of multiple redirects, the navigation will resolve with the response of the last redirect.
|
- returns: <[Promise]<[Response]>> Promise which resolves to the main resource response. In case of multiple redirects, the navigation will resolve with the response of the last redirect.
|
||||||
|
|
||||||
|
#### page.route(url, handler)
|
||||||
|
- `url` <[string]|[RegExp]|[Function]> A glob pattern, regex pattern or predicate receiving [URL] to match while routing.
|
||||||
|
- `handler` <[Function]> handler function to router the request.
|
||||||
|
- returns: <[Promise]<[void]>>.
|
||||||
|
|
||||||
|
Routing activates the request interception and enables `request.abort`, `request.continue` and
|
||||||
|
`request.respond` methods on the request. This provides the capability to modify network requests that are made by a page.
|
||||||
|
|
||||||
|
Once request interception is enabled, every request matching the url pattern will stall unless it's continued, responded or aborted.
|
||||||
|
An example of a naïve request interceptor that aborts all image requests:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const page = await browser.newPage();
|
||||||
|
await page.route('**/*.{png,jpg,jpeg}', request => request.abort());
|
||||||
|
// await page.route(/\.(png|jpeg|jpg)$/, request => request.abort()); // <-- same thing
|
||||||
|
await page.goto('https://example.com');
|
||||||
|
await browser.close();
|
||||||
|
```
|
||||||
|
|
||||||
|
or the same snippet using a regex pattern instead:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const page = await browser.newPage();
|
||||||
|
await page.route(/(\.png$)|(\.jpg$)/, request => request.abort());
|
||||||
|
await page.goto('https://example.com');
|
||||||
|
await browser.close();
|
||||||
|
```
|
||||||
|
|
||||||
|
> **NOTE** Enabling request interception disables page caching.
|
||||||
|
|
||||||
#### page.screenshot([options])
|
#### page.screenshot([options])
|
||||||
- `options` <[Object]> Options object which might have the following properties:
|
- `options` <[Object]> Options object which might have the following properties:
|
||||||
- `path` <[string]> The file path to save the image to. The screenshot type will be inferred from file extension. If `path` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd). If no path is provided, the image won't be saved to the disk.
|
- `path` <[string]> The file path to save the image to. The screenshot type will be inferred from file extension. If `path` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd). If no path is provided, the image won't be saved to the disk.
|
||||||
|
|
@ -1288,31 +1318,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(enabled)
|
|
||||||
- `enabled` <[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 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.setViewport(viewport)
|
#### page.setViewport(viewport)
|
||||||
- `viewport` <[Object]>
|
- `viewport` <[Object]>
|
||||||
- `width` <[number]> page width in pixels. **required**
|
- `width` <[number]> page width in pixels. **required**
|
||||||
|
|
@ -1501,7 +1506,7 @@ Shortcut for [page.mainFrame().waitForLoadState([options])](#framewaitforloadsta
|
||||||
#### page.waitForNavigation([options])
|
#### page.waitForNavigation([options])
|
||||||
- `options` <[Object]> Navigation parameters which might have the following properties:
|
- `options` <[Object]> Navigation parameters which might have the following properties:
|
||||||
- `timeout` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods.
|
- `timeout` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout. The default value can be changed by using the [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout) or [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout) methods.
|
||||||
- `url` <[string]|[RegExp]|[Function]> URL string, URL regex pattern or predicate receiving [URL] to match while waiting for the navigation.
|
- `url` <[string]|[RegExp]|[Function]> A glob pattern, regex pattern or predicate receiving [URL] to match while waiting for the navigation.
|
||||||
- `waitUntil` <"load"|"domcontentloaded"|"networkidle0"|"networkidle2"|[Array]<"load"|"domcontentloaded"|"networkidle0"|"networkidle2">> When to consider navigation succeeded, defaults to `load`. Given an array of event strings, navigation is considered to be successful after all events have been fired. Events can be either:
|
- `waitUntil` <"load"|"domcontentloaded"|"networkidle0"|"networkidle2"|[Array]<"load"|"domcontentloaded"|"networkidle0"|"networkidle2">> When to consider navigation succeeded, defaults to `load`. Given an array of event strings, navigation is considered to be successful after all events have been fired. Events can be either:
|
||||||
- `'load'` - consider navigation to be finished when the `load` event is fired.
|
- `'load'` - consider navigation to be finished when the `load` event is fired.
|
||||||
- `'domcontentloaded'` - consider navigation to be finished when the `DOMContentLoaded` event is fired.
|
- `'domcontentloaded'` - consider navigation to be finished when the `DOMContentLoaded` event is fired.
|
||||||
|
|
@ -2849,7 +2854,7 @@ If request gets a 'redirect' response, the request is successfully finished with
|
||||||
- `failed` - A generic failure occurred.
|
- `failed` - A generic failure occurred.
|
||||||
- returns: <[Promise]>
|
- returns: <[Promise]>
|
||||||
|
|
||||||
Aborts request. To use this, request interception should be enabled with `page.setRequestInterception`.
|
Aborts request. To use this, request interception should be enabled with `page.route`.
|
||||||
Exception is immediately thrown if the request interception is not enabled.
|
Exception is immediately thrown if the request interception is not enabled.
|
||||||
|
|
||||||
#### request.continue([overrides])
|
#### request.continue([overrides])
|
||||||
|
|
@ -2859,12 +2864,11 @@ Exception is immediately thrown if the request interception is not enabled.
|
||||||
- `headers` <[Object]> If set changes the request HTTP headers. Header values will be converted to a string.
|
- `headers` <[Object]> If set changes the request HTTP headers. Header values will be converted to a string.
|
||||||
- returns: <[Promise]>
|
- returns: <[Promise]>
|
||||||
|
|
||||||
Continues request with optional request overrides. To use this, request interception should be enabled with `page.setRequestInterception`.
|
Continues request with optional request overrides. To use this, request interception should be enabled with `page.route`.
|
||||||
Exception is immediately thrown if the request interception is not enabled.
|
Exception is immediately thrown if the request interception is not enabled.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
await page.setRequestInterception(true);
|
await page.route('**/*', request => {
|
||||||
page.on('request', request => {
|
|
||||||
// Override headers
|
// Override headers
|
||||||
const headers = Object.assign({}, request.headers(), {
|
const headers = Object.assign({}, request.headers(), {
|
||||||
foo: 'bar', // set "foo" header
|
foo: 'bar', // set "foo" header
|
||||||
|
|
@ -2901,14 +2905,13 @@ page.on('requestfailed', request => {
|
||||||
- returns: <[Promise]>
|
- returns: <[Promise]>
|
||||||
|
|
||||||
Fulfills request with given response. To use this, request interception should
|
Fulfills request with given response. To use this, request interception should
|
||||||
be enabled with `page.setRequestInterception`. Exception is thrown if
|
be enabled with `page.route`. Exception is thrown if
|
||||||
request interception is not enabled.
|
request interception is not enabled.
|
||||||
|
|
||||||
An example of fulfilling all requests with 404 responses:
|
An example of fulfilling all requests with 404 responses:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
await page.setRequestInterception(true);
|
await page.route('**/*', request => {
|
||||||
page.on('request', request => {
|
|
||||||
request.respond({
|
request.respond({
|
||||||
status: 404,
|
status: 404,
|
||||||
contentType: 'text/plain',
|
contentType: 'text/plain',
|
||||||
|
|
|
||||||
|
|
@ -199,7 +199,7 @@ export class FrameManager {
|
||||||
watcher._onNavigationRequest(frame, request);
|
watcher._onNavigationRequest(frame, request);
|
||||||
}
|
}
|
||||||
if (!request._isFavicon)
|
if (!request._isFavicon)
|
||||||
this._page.emit(Events.Page.Request, request);
|
this._page._requestStarted(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
requestReceivedResponse(response: network.Response) {
|
requestReceivedResponse(response: network.Response) {
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,62 @@ class Helper {
|
||||||
clearTimeout(timeoutTimer);
|
clearTimeout(timeoutTimer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static globToRegex(glob: string): RegExp {
|
||||||
|
const tokens = ['^'];
|
||||||
|
let inGroup;
|
||||||
|
for (let i = 0; i < glob.length; ++i) {
|
||||||
|
const c = glob[i];
|
||||||
|
if (escapeGlobChars.has(c)) {
|
||||||
|
tokens.push('\\' + c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c === '*') {
|
||||||
|
const beforeDeep = glob[i - 1];
|
||||||
|
let starCount = 1;
|
||||||
|
while (glob[i + 1] === '*') {
|
||||||
|
starCount++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
const afterDeep = glob[i + 1];
|
||||||
|
const isDeep = starCount > 1 &&
|
||||||
|
(beforeDeep === '/' || beforeDeep === undefined) &&
|
||||||
|
(afterDeep === '/' || afterDeep === undefined);
|
||||||
|
if (isDeep) {
|
||||||
|
tokens.push('((?:[^/]*(?:\/|$))*)');
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
tokens.push('([^/]*)');
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case '?':
|
||||||
|
tokens.push('.');
|
||||||
|
break;
|
||||||
|
case '{':
|
||||||
|
inGroup = true;
|
||||||
|
tokens.push('(');
|
||||||
|
break;
|
||||||
|
case '}':
|
||||||
|
inGroup = false;
|
||||||
|
tokens.push(')');
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
if (inGroup) {
|
||||||
|
tokens.push('|');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tokens.push('\\' + c);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
tokens.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tokens.push('$');
|
||||||
|
return new RegExp(tokens.join(''));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function assert(value: any, message?: string) {
|
export function assert(value: any, message?: string) {
|
||||||
|
|
@ -162,4 +218,6 @@ export function assert(value: any, message?: string) {
|
||||||
throw new Error(message);
|
throw new Error(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const escapeGlobChars = new Set(['/', '$', '^', '+', '.', '(', ')', '=', '!', '|']);
|
||||||
|
|
||||||
export const helper = Helper;
|
export const helper = Helper;
|
||||||
|
|
|
||||||
|
|
@ -216,6 +216,10 @@ export class Request {
|
||||||
assert(!this._interceptionHandled, 'Request is already handled!');
|
assert(!this._interceptionHandled, 'Request is already handled!');
|
||||||
await this._delegate!.continue(overrides);
|
await this._delegate!.continue(overrides);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_isIntercepted(): boolean {
|
||||||
|
return !!this._delegate;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetResponseBodyCallback = () => Promise<platform.BufferType>;
|
type GetResponseBodyCallback = () => Promise<platform.BufferType>;
|
||||||
|
|
|
||||||
23
src/page.ts
23
src/page.ts
|
|
@ -111,6 +111,7 @@ export class Page extends platform.EventEmitter {
|
||||||
private _workers = new Map<string, Worker>();
|
private _workers = new Map<string, Worker>();
|
||||||
readonly pdf: ((options?: types.PDFOptions) => Promise<platform.BufferType>) | undefined;
|
readonly pdf: ((options?: types.PDFOptions) => Promise<platform.BufferType>) | undefined;
|
||||||
readonly coverage: Coverage | undefined;
|
readonly coverage: Coverage | undefined;
|
||||||
|
readonly _requestHandlers: { url: types.URLMatch, handler: (request: network.Request) => void }[] = [];
|
||||||
|
|
||||||
constructor(delegate: PageDelegate, browserContext: BrowserContext) {
|
constructor(delegate: PageDelegate, browserContext: BrowserContext) {
|
||||||
super();
|
super();
|
||||||
|
|
@ -416,11 +417,25 @@ export class Page extends platform.EventEmitter {
|
||||||
await this._delegate.setCacheEnabled(enabled);
|
await this._delegate.setCacheEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
async setRequestInterception(enabled: boolean) {
|
async route(url: types.URLMatch, handler: (request: network.Request) => void) {
|
||||||
if (this._state.interceptNetwork === enabled)
|
if (!this._state.interceptNetwork) {
|
||||||
|
this._state.interceptNetwork = true;
|
||||||
|
await this._delegate.setRequestInterception(true);
|
||||||
|
}
|
||||||
|
this._requestHandlers.push({ url, handler });
|
||||||
|
}
|
||||||
|
|
||||||
|
_requestStarted(request: network.Request) {
|
||||||
|
this.emit(Events.Page.Request, request);
|
||||||
|
if (!request._isIntercepted())
|
||||||
return;
|
return;
|
||||||
this._state.interceptNetwork = enabled;
|
for (const { url, handler } of this._requestHandlers) {
|
||||||
await this._delegate.setRequestInterception(enabled);
|
if (platform.urlMatches(request.url(), url)) {
|
||||||
|
handler(request);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request.continue();
|
||||||
}
|
}
|
||||||
|
|
||||||
async setOfflineMode(enabled: boolean) {
|
async setOfflineMode(enabled: boolean) {
|
||||||
|
|
|
||||||
|
|
@ -219,19 +219,20 @@ export function getMimeType(file: string): string | null {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function urlMatches(urlString: string, match: types.URLMatch | undefined): boolean {
|
export function urlMatches(urlString: string, match: types.URLMatch | undefined): boolean {
|
||||||
if (match === undefined)
|
if (match === undefined || match === '')
|
||||||
return true;
|
return true;
|
||||||
if (typeof match === 'string')
|
if (helper.isString(match))
|
||||||
return match === urlString;
|
match = helper.globToRegex(match);
|
||||||
if (match instanceof RegExp)
|
if (match instanceof RegExp)
|
||||||
return match.test(urlString);
|
return match.test(urlString);
|
||||||
assert(typeof match === 'function', 'url parameter should be string, RegExp or function');
|
if (typeof match === 'string' && match === urlString)
|
||||||
|
return true;
|
||||||
|
const url = new URL(urlString);
|
||||||
|
if (typeof match === 'string')
|
||||||
|
return url.pathname === match;
|
||||||
|
|
||||||
try {
|
assert(typeof match === 'function', 'url parameter should be string, RegExp or function');
|
||||||
return match(new URL(urlString));
|
return match(url);
|
||||||
} catch (e) {
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pngToJpeg(buffer: Buffer): Buffer {
|
export function pngToJpeg(buffer: Buffer): Buffer {
|
||||||
|
|
|
||||||
|
|
@ -224,7 +224,7 @@ module.exports.describe = function({testRunner, expect, playwright, FFOX, CHROMI
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Chromium-Specific Page Tests', function() {
|
describe('Chromium-Specific Page Tests', function() {
|
||||||
it('Page.setRequestInterception should work with intervention headers', async({server, page}) => {
|
it('Page.route should work with intervention headers', async({server, page}) => {
|
||||||
server.setRoute('/intervention', (req, res) => res.end(`
|
server.setRoute('/intervention', (req, res) => res.end(`
|
||||||
<script>
|
<script>
|
||||||
document.write('<script src="${server.CROSS_PROCESS_PREFIX}/intervention.js">' + '</scr' + 'ipt>');
|
document.write('<script src="${server.CROSS_PROCESS_PREFIX}/intervention.js">' + '</scr' + 'ipt>');
|
||||||
|
|
@ -237,8 +237,7 @@ module.exports.describe = function({testRunner, expect, playwright, FFOX, CHROMI
|
||||||
res.end('console.log(1);');
|
res.end('console.log(1);');
|
||||||
});
|
});
|
||||||
|
|
||||||
await page.setRequestInterception(true);
|
await page.route('*', request => request.continue());
|
||||||
page.on('request', request => request.continue());
|
|
||||||
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.
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,7 @@ module.exports.describe = 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({browser, page, server, context}) {
|
it('should load oopif iframes with subresources and request interception', async function({browser, page, server, context}) {
|
||||||
await page.setRequestInterception(true);
|
await page.route('*', 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(browser).length).toBe(1);
|
expect(oopifs(browser).length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const { helper } = require('../lib/helper');
|
||||||
const utils = require('./utils');
|
const utils = require('./utils');
|
||||||
|
|
||||||
module.exports.describe = function({testRunner, expect, defaultBrowserOptions, playwright, FFOX, CHROMIUM, WEBKIT}) {
|
module.exports.describe = function({testRunner, expect, defaultBrowserOptions, playwright, FFOX, CHROMIUM, WEBKIT}) {
|
||||||
|
|
@ -24,10 +25,9 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
const {it, fit, xit, dit} = testRunner;
|
const {it, fit, xit, dit} = testRunner;
|
||||||
const {beforeAll, beforeEach, afterAll, afterEach} = testRunner;
|
const {beforeAll, beforeEach, afterAll, afterEach} = testRunner;
|
||||||
|
|
||||||
describe('Page.setRequestInterception', function() {
|
describe('Page.route', function() {
|
||||||
it('should intercept', async({page, server}) => {
|
it('should intercept', async({page, server}) => {
|
||||||
await page.setRequestInterception(true);
|
await page.route('/empty.html', request => {
|
||||||
page.on('request', request => {
|
|
||||||
expect(request.url()).toContain('empty.html');
|
expect(request.url()).toContain('empty.html');
|
||||||
expect(request.headers()['user-agent']).toBeTruthy();
|
expect(request.headers()['user-agent']).toBeTruthy();
|
||||||
expect(request.method()).toBe('GET');
|
expect(request.method()).toBe('GET');
|
||||||
|
|
@ -44,8 +44,7 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
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.route('**/*', request => request.continue());
|
||||||
page.on('request', request => request.continue());
|
|
||||||
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">
|
||||||
|
|
@ -59,8 +58,7 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
// @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.route('**/*', request => {
|
||||||
page.on('request', request => {
|
|
||||||
const headers = Object.assign({}, request.headers(), {
|
const headers = Object.assign({}, request.headers(), {
|
||||||
foo: 'bar'
|
foo: 'bar'
|
||||||
});
|
});
|
||||||
|
|
@ -70,8 +68,7 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
});
|
});
|
||||||
// @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.route('**/*', 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
|
||||||
|
|
@ -87,9 +84,8 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
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);
|
|
||||||
const requests = [];
|
const requests = [];
|
||||||
page.on('request', request => {
|
await page.route('**/*', request => {
|
||||||
requests.push(request);
|
requests.push(request);
|
||||||
request.continue();
|
request.continue();
|
||||||
});
|
});
|
||||||
|
|
@ -103,24 +99,15 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
await context.setCookies([{ url: server.EMPTY_PAGE, name: 'foo', value: 'bar'}]);
|
await context.setCookies([{ url: server.EMPTY_PAGE, name: 'foo', value: 'bar'}]);
|
||||||
|
|
||||||
// Setup request interception.
|
// Setup request interception.
|
||||||
await page.setRequestInterception(true);
|
await page.route('**/*', request => request.continue());
|
||||||
page.on('request', request => request.continue());
|
|
||||||
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}) => {
|
|
||||||
await page.setRequestInterception(true);
|
|
||||||
page.once('request', request => request.continue());
|
|
||||||
await page.goto(server.EMPTY_PAGE);
|
|
||||||
await page.setRequestInterception(false);
|
|
||||||
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.route('**/*', request => {
|
||||||
page.on('request', request => {
|
|
||||||
expect(request.headers()['foo']).toBe('bar');
|
expect(request.headers()['foo']).toBe('bar');
|
||||||
request.continue();
|
request.continue();
|
||||||
});
|
});
|
||||||
|
|
@ -131,8 +118,7 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
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.route('**/*', request => request.continue());
|
||||||
page.on('request', request => request.continue());
|
|
||||||
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
|
||||||
|
|
@ -143,8 +129,7 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
});
|
});
|
||||||
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.route('**/*', request => {
|
||||||
page.on('request', request => {
|
|
||||||
expect(request.headers()['referer']).toBe(server.EMPTY_PAGE);
|
expect(request.headers()['referer']).toBe(server.EMPTY_PAGE);
|
||||||
request.continue();
|
request.continue();
|
||||||
});
|
});
|
||||||
|
|
@ -152,13 +137,7 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
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.route(/\.css$/, request => request.abort());
|
||||||
page.on('request', request => {
|
|
||||||
if (request.url().endsWith('.css'))
|
|
||||||
request.abort();
|
|
||||||
else
|
|
||||||
request.continue();
|
|
||||||
});
|
|
||||||
let failedRequests = 0;
|
let failedRequests = 0;
|
||||||
page.on('requestfailed', event => ++failedRequests);
|
page.on('requestfailed', event => ++failedRequests);
|
||||||
const response = await page.goto(server.PREFIX + '/one-style.html');
|
const response = await page.goto(server.PREFIX + '/one-style.html');
|
||||||
|
|
@ -167,10 +146,7 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
expect(failedRequests).toBe(1);
|
expect(failedRequests).toBe(1);
|
||||||
});
|
});
|
||||||
it('should be abortable with custom error codes', async({page, server}) => {
|
it('should be abortable with custom error codes', async({page, server}) => {
|
||||||
await page.setRequestInterception(true);
|
await page.route('**/*', request => request.abort('internetdisconnected'));
|
||||||
page.on('request', request => {
|
|
||||||
request.abort('internetdisconnected');
|
|
||||||
});
|
|
||||||
let failedRequest = null;
|
let failedRequest = null;
|
||||||
page.on('requestfailed', request => failedRequest = request);
|
page.on('requestfailed', request => failedRequest = request);
|
||||||
await page.goto(server.EMPTY_PAGE).catch(e => {});
|
await page.goto(server.EMPTY_PAGE).catch(e => {});
|
||||||
|
|
@ -186,8 +162,7 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
await page.setExtraHTTPHeaders({
|
await page.setExtraHTTPHeaders({
|
||||||
referer: 'http://google.com/'
|
referer: 'http://google.com/'
|
||||||
});
|
});
|
||||||
await page.setRequestInterception(true);
|
await page.route('**/*', request => request.continue());
|
||||||
page.on('request', request => request.continue());
|
|
||||||
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 +170,7 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
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.route('**/*', request => request.abort());
|
||||||
page.on('request', request => request.abort());
|
|
||||||
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();
|
||||||
|
|
@ -208,9 +182,8 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
expect(error.message).toContain('net::ERR_FAILED');
|
expect(error.message).toContain('net::ERR_FAILED');
|
||||||
});
|
});
|
||||||
it('should work with redirects', async({page, server}) => {
|
it('should work with redirects', async({page, server}) => {
|
||||||
await page.setRequestInterception(true);
|
|
||||||
const requests = [];
|
const requests = [];
|
||||||
page.on('request', request => {
|
await page.route('**/*', request => {
|
||||||
request.continue();
|
request.continue();
|
||||||
requests.push(request);
|
requests.push(request);
|
||||||
});
|
});
|
||||||
|
|
@ -235,9 +208,8 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
it('should work with redirects for subresources', async({page, server}) => {
|
it('should work with redirects for subresources', async({page, server}) => {
|
||||||
await page.setRequestInterception(true);
|
|
||||||
const requests = [];
|
const requests = [];
|
||||||
page.on('request', request => {
|
await page.route('**/*', request => {
|
||||||
request.continue();
|
request.continue();
|
||||||
requests.push(request);
|
requests.push(request);
|
||||||
});
|
});
|
||||||
|
|
@ -262,11 +234,10 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
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);
|
|
||||||
|
|
||||||
let spinner = false;
|
let spinner = false;
|
||||||
// Cancel 2nd request.
|
// Cancel 2nd request.
|
||||||
page.on('request', request => {
|
await page.route('**/*', request => {
|
||||||
spinner ? request.abort() : request.continue();
|
spinner ? request.abort() : request.continue();
|
||||||
spinner = !spinner;
|
spinner = !spinner;
|
||||||
});
|
});
|
||||||
|
|
@ -278,9 +249,8 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
expect(results).toEqual(['11', 'FAILED', '22']);
|
expect(results).toEqual(['11', 'FAILED', '22']);
|
||||||
});
|
});
|
||||||
it('should navigate to dataURL and not fire dataURL requests', async({page, server}) => {
|
it('should navigate to dataURL and not fire dataURL requests', async({page, server}) => {
|
||||||
await page.setRequestInterception(true);
|
|
||||||
const requests = [];
|
const requests = [];
|
||||||
page.on('request', request => {
|
await page.route('**/*', request => {
|
||||||
requests.push(request);
|
requests.push(request);
|
||||||
request.continue();
|
request.continue();
|
||||||
});
|
});
|
||||||
|
|
@ -291,9 +261,8 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
});
|
});
|
||||||
it('should be able to fetch dataURL and not fire dataURL requests', async({page, server}) => {
|
it('should be able to fetch dataURL and not fire dataURL requests', async({page, server}) => {
|
||||||
await page.goto(server.EMPTY_PAGE);
|
await page.goto(server.EMPTY_PAGE);
|
||||||
await page.setRequestInterception(true);
|
|
||||||
const requests = [];
|
const requests = [];
|
||||||
page.on('request', request => {
|
await page.route('**/*', request => {
|
||||||
requests.push(request);
|
requests.push(request);
|
||||||
request.continue();
|
request.continue();
|
||||||
});
|
});
|
||||||
|
|
@ -303,9 +272,8 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
expect(requests.length).toBe(0);
|
expect(requests.length).toBe(0);
|
||||||
});
|
});
|
||||||
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);
|
|
||||||
const requests = [];
|
const requests = [];
|
||||||
page.on('request', request => {
|
await page.route('**/*', request => {
|
||||||
requests.push(request);
|
requests.push(request);
|
||||||
request.continue();
|
request.continue();
|
||||||
});
|
});
|
||||||
|
|
@ -318,24 +286,21 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
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.route('**/*', request => request.continue());
|
||||||
page.on('request', request => request.continue());
|
|
||||||
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);
|
|
||||||
server.setRoute('/malformed?rnd=%911', (req, res) => res.end());
|
server.setRoute('/malformed?rnd=%911', (req, res) => res.end());
|
||||||
page.on('request', request => request.continue());
|
await page.route('**/*', request => request.continue());
|
||||||
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('should work with encoded server - 2', async({page, server}) => {
|
it('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);
|
|
||||||
const requests = [];
|
const requests = [];
|
||||||
page.on('request', request => {
|
await page.route('**/*', request => {
|
||||||
request.continue();
|
request.continue();
|
||||||
requests.push(request);
|
requests.push(request);
|
||||||
});
|
});
|
||||||
|
|
@ -346,9 +311,8 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
});
|
});
|
||||||
it('should not throw "Invalid Interception Id" if the request was cancelled', async({page, server}) => {
|
it('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);
|
|
||||||
let request = null;
|
let request = null;
|
||||||
page.on('request', async r => request = r);
|
await page.route('**/*', 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),
|
||||||
// Wait for request interception.
|
// Wait for request interception.
|
||||||
await utils.waitEvent(page, 'request');
|
await utils.waitEvent(page, 'request');
|
||||||
|
|
@ -373,11 +337,9 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
});
|
});
|
||||||
it('should intercept main resource during cross-process navigation', async({page, server}) => {
|
it('should intercept main resource during cross-process navigation', async({page, server}) => {
|
||||||
await page.goto(server.EMPTY_PAGE);
|
await page.goto(server.EMPTY_PAGE);
|
||||||
await page.setRequestInterception(true);
|
|
||||||
let intercepted = false;
|
let intercepted = false;
|
||||||
page.on('request', request => {
|
await page.route(server.CROSS_PROCESS_PREFIX + '/empty.html', request => {
|
||||||
if (request.url().includes(server.CROSS_PROCESS_PREFIX + '/empty.html'))
|
intercepted = true;
|
||||||
intercepted = true;
|
|
||||||
request.continue();
|
request.continue();
|
||||||
});
|
});
|
||||||
const response = await page.goto(server.CROSS_PROCESS_PREFIX + '/empty.html');
|
const response = await page.goto(server.CROSS_PROCESS_PREFIX + '/empty.html');
|
||||||
|
|
@ -385,11 +347,7 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
expect(intercepted).toBe(true);
|
expect(intercepted).toBe(true);
|
||||||
});
|
});
|
||||||
it('should not throw when continued after navigation', async({page, server}) => {
|
it('should not throw when continued after navigation', async({page, server}) => {
|
||||||
await page.setRequestInterception(true);
|
await page.route(server.PREFIX + '/one-style.css', () => {});
|
||||||
page.on('request', request => {
|
|
||||||
if (request.url() !== server.PREFIX + '/one-style.css')
|
|
||||||
request.continue();
|
|
||||||
});
|
|
||||||
// For some reason, Firefox issues load event with one outstanding request.
|
// For some reason, Firefox issues load event with one outstanding request.
|
||||||
const failed = page.goto(server.PREFIX + '/one-style.html', { waitUntil: FFOX ? 'networkidle0' : 'load' }).catch(e => e);
|
const failed = page.goto(server.PREFIX + '/one-style.html', { waitUntil: FFOX ? 'networkidle0' : 'load' }).catch(e => e);
|
||||||
const request = await page.waitForRequest(server.PREFIX + '/one-style.css');
|
const request = await page.waitForRequest(server.PREFIX + '/one-style.css');
|
||||||
|
|
@ -400,11 +358,7 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
expect(notAnError).toBe(null);
|
expect(notAnError).toBe(null);
|
||||||
});
|
});
|
||||||
it('should not throw when continued after cross-process navigation', async({page, server}) => {
|
it('should not throw when continued after cross-process navigation', async({page, server}) => {
|
||||||
await page.setRequestInterception(true);
|
await page.route(server.PREFIX + '/one-style.css', () => {});
|
||||||
page.on('request', request => {
|
|
||||||
if (request.url() !== server.PREFIX + '/one-style.css')
|
|
||||||
request.continue();
|
|
||||||
});
|
|
||||||
// For some reason, Firefox issues load event with one outstanding request.
|
// For some reason, Firefox issues load event with one outstanding request.
|
||||||
const failed = page.goto(server.PREFIX + '/one-style.html', { waitUntil: FFOX ? 'networkidle0' : 'load' }).catch(e => e);
|
const failed = page.goto(server.PREFIX + '/one-style.html', { waitUntil: FFOX ? 'networkidle0' : 'load' }).catch(e => e);
|
||||||
const request = await page.waitForRequest(server.PREFIX + '/one-style.css');
|
const request = await page.waitForRequest(server.PREFIX + '/one-style.css');
|
||||||
|
|
@ -418,13 +372,11 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
|
|
||||||
describe('Request.continue', function() {
|
describe('Request.continue', function() {
|
||||||
it('should work', async({page, server}) => {
|
it('should work', async({page, server}) => {
|
||||||
await page.setRequestInterception(true);
|
await page.route('**/*', request => request.continue());
|
||||||
page.on('request', request => request.continue());
|
|
||||||
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.route('**/*', 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 });
|
request.continue({ headers });
|
||||||
|
|
@ -439,10 +391,7 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
it('should amend method', async({page, server}) => {
|
it('should amend method', async({page, server}) => {
|
||||||
const sRequest = server.waitForRequest('/sleep.zzz');
|
const sRequest = server.waitForRequest('/sleep.zzz');
|
||||||
await page.goto(server.EMPTY_PAGE);
|
await page.goto(server.EMPTY_PAGE);
|
||||||
await page.setRequestInterception(true);
|
await page.route('**/*', request => request.continue({ method: 'POST' }));
|
||||||
page.on('request', request => {
|
|
||||||
request.continue({ method: 'POST' });
|
|
||||||
});
|
|
||||||
const [request] = await Promise.all([
|
const [request] = await Promise.all([
|
||||||
server.waitForRequest('/sleep.zzz'),
|
server.waitForRequest('/sleep.zzz'),
|
||||||
page.evaluate(() => fetch('/sleep.zzz'))
|
page.evaluate(() => fetch('/sleep.zzz'))
|
||||||
|
|
@ -452,17 +401,13 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
});
|
});
|
||||||
it('should amend method on main request', async({page, server}) => {
|
it('should amend method on main request', async({page, server}) => {
|
||||||
const request = server.waitForRequest('/empty.html');
|
const request = server.waitForRequest('/empty.html');
|
||||||
await page.setRequestInterception(true);
|
await page.route('**/*', request => request.continue({ method: 'POST' }));
|
||||||
page.on('request', request => {
|
|
||||||
request.continue({ method: 'POST' });
|
|
||||||
});
|
|
||||||
await page.goto(server.EMPTY_PAGE);
|
await page.goto(server.EMPTY_PAGE);
|
||||||
expect((await request).method).toBe('POST');
|
expect((await request).method).toBe('POST');
|
||||||
});
|
});
|
||||||
it('should amend post data', async({page, server}) => {
|
it('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.route('**/*', request => {
|
||||||
page.on('request', request => {
|
|
||||||
request.continue({ postData: 'doggo' });
|
request.continue({ postData: 'doggo' });
|
||||||
});
|
});
|
||||||
const [serverRequest] = await Promise.all([
|
const [serverRequest] = await Promise.all([
|
||||||
|
|
@ -475,8 +420,7 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
|
|
||||||
describe('Request.fulfill', function() {
|
describe('Request.fulfill', function() {
|
||||||
it('should work', async({page, server}) => {
|
it('should work', async({page, server}) => {
|
||||||
await page.setRequestInterception(true);
|
await page.route('**/*', request => {
|
||||||
page.on('request', request => {
|
|
||||||
request.fulfill({
|
request.fulfill({
|
||||||
status: 201,
|
status: 201,
|
||||||
headers: {
|
headers: {
|
||||||
|
|
@ -492,8 +436,7 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
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.route('**/*', request => {
|
||||||
page.on('request', request => {
|
|
||||||
request.fulfill({
|
request.fulfill({
|
||||||
status: 422,
|
status: 422,
|
||||||
body: 'Yo, page!'
|
body: 'Yo, page!'
|
||||||
|
|
@ -505,8 +448,7 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
expect(await page.evaluate(() => document.body.textContent)).toBe('Yo, page!');
|
expect(await page.evaluate(() => document.body.textContent)).toBe('Yo, 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.route('**/*', 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.fulfill({
|
request.fulfill({
|
||||||
contentType: 'image/png',
|
contentType: 'image/png',
|
||||||
|
|
@ -523,8 +465,7 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
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.route('**/*', request => {
|
||||||
page.on('request', request => {
|
|
||||||
request.fulfill({
|
request.fulfill({
|
||||||
status: 200,
|
status: 200,
|
||||||
headers: {
|
headers: {
|
||||||
|
|
@ -601,11 +542,10 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
describe('Interception vs isNavigationRequest', () => {
|
describe('Interception vs isNavigationRequest', () => {
|
||||||
it('should work with request interception', async({page, server}) => {
|
it('should work with request interception', async({page, server}) => {
|
||||||
const requests = new Map();
|
const requests = new Map();
|
||||||
page.on('request', request => {
|
await page.route('**/*', request => {
|
||||||
requests.set(request.url().split('/').pop(), request);
|
requests.set(request.url().split('/').pop(), request);
|
||||||
request.continue();
|
request.continue();
|
||||||
});
|
});
|
||||||
await page.setRequestInterception(true);
|
|
||||||
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);
|
||||||
|
|
@ -616,31 +556,34 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Page.setCacheEnabled', function() {
|
|
||||||
it('should stay disabled when toggling request interception on/off', async({page, server}) => {
|
|
||||||
await page.setCacheEnabled(false);
|
|
||||||
await page.setRequestInterception(true);
|
|
||||||
await page.setRequestInterception(false);
|
|
||||||
|
|
||||||
await page.goto(server.PREFIX + '/cached/one-style.html');
|
|
||||||
const [nonCachedRequest] = await Promise.all([
|
|
||||||
server.waitForRequest('/cached/one-style.html'),
|
|
||||||
page.reload(),
|
|
||||||
]);
|
|
||||||
expect(nonCachedRequest.headers['if-modified-since']).toBe(undefined);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('ignoreHTTPSErrors', function() {
|
describe('ignoreHTTPSErrors', function() {
|
||||||
it('should work with request interception', async({newPage, httpsServer}) => {
|
it('should work with request interception', async({newPage, httpsServer}) => {
|
||||||
const page = await newPage({ ignoreHTTPSErrors: true, interceptNetwork: true });
|
const page = await newPage({ ignoreHTTPSErrors: true, interceptNetwork: true });
|
||||||
|
|
||||||
await page.setRequestInterception(true);
|
await page.route('**/*', 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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('glob', function() {
|
||||||
|
it('should work with glob', async({newPage, httpsServer}) => {
|
||||||
|
expect(helper.globToRegex('**/*.js').test('https://localhost:8080/foo.js')).toBeTruthy();
|
||||||
|
expect(helper.globToRegex('**/*.css').test('https://localhost:8080/foo.js')).toBeFalsy();
|
||||||
|
expect(helper.globToRegex('*.js').test('https://localhost:8080/foo.js')).toBeFalsy();
|
||||||
|
expect(helper.globToRegex('https://**/*.js').test('https://localhost:8080/foo.js')).toBeTruthy();
|
||||||
|
expect(helper.globToRegex('http://localhost:8080/simple/path.js').test('http://localhost:8080/simple/path.js')).toBeTruthy();
|
||||||
|
expect(helper.globToRegex('http://localhost:8080/?imple/path.js').test('http://localhost:8080/Simple/path.js')).toBeTruthy();
|
||||||
|
expect(helper.globToRegex('**/{a,b}.js').test('https://localhost:8080/a.js')).toBeTruthy();
|
||||||
|
expect(helper.globToRegex('**/{a,b}.js').test('https://localhost:8080/b.js')).toBeTruthy();
|
||||||
|
expect(helper.globToRegex('**/{a,b}.js').test('https://localhost:8080/c.js')).toBeFalsy();
|
||||||
|
|
||||||
|
expect(helper.globToRegex('**/*.{png,jpg,jpeg}').test('https://localhost:8080/c.jpg')).toBeTruthy();
|
||||||
|
expect(helper.globToRegex('**/*.{png,jpg,jpeg}').test('https://localhost:8080/c.jpeg')).toBeTruthy();
|
||||||
|
expect(helper.globToRegex('**/*.{png,jpg,jpeg}').test('https://localhost:8080/c.png')).toBeTruthy();
|
||||||
|
expect(helper.globToRegex('**/*.{png,jpg,jpeg}').test('https://localhost:8080/c.css')).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -35,27 +35,5 @@ module.exports.describe = function ({ testRunner, expect }) {
|
||||||
expect(htmlReq.headers['foo']).toBe(undefined);
|
expect(htmlReq.headers['foo']).toBe(undefined);
|
||||||
expect(cssReq.headers['foo']).toBe('bar');
|
expect(cssReq.headers['foo']).toBe('bar');
|
||||||
});
|
});
|
||||||
it('should continue load when interception gets disabled during provisional load', async({page, server}) => {
|
|
||||||
await page.goto(server.EMPTY_PAGE);
|
|
||||||
await page.setRequestInterception(true);
|
|
||||||
expect(await page.evaluate(() => navigator.onLine)).toBe(true);
|
|
||||||
let intercepted = null;
|
|
||||||
const order = [];
|
|
||||||
page.on('request', request => {
|
|
||||||
intercepted = page.setRequestInterception(false).then(() => order.push('setRequestInterception'));
|
|
||||||
});
|
|
||||||
const response = await page.goto(server.CROSS_PROCESS_PREFIX + '/empty.html').then(response => {
|
|
||||||
order.push('goto');
|
|
||||||
return response;
|
|
||||||
});
|
|
||||||
// Should intercept a request.
|
|
||||||
expect(intercepted).not.toBe(null);
|
|
||||||
await intercepted;
|
|
||||||
// Should continue on disabling and load successfully.
|
|
||||||
expect(response.status()).toBe(200);
|
|
||||||
// Should resolve setRequestInterception before goto.
|
|
||||||
expect(order[0]).toBe('setRequestInterception');
|
|
||||||
expect(order[1]).toBe('goto');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue