feat: add page.emulateNetworkConditions (#6759)
This commit is contained in:
parent
ebd087a316
commit
5ea76e9333
45
docs/api.md
45
docs/api.md
@ -42,6 +42,7 @@
|
|||||||
* [puppeteer.errors](#puppeteererrors)
|
* [puppeteer.errors](#puppeteererrors)
|
||||||
* [puppeteer.executablePath()](#puppeteerexecutablepath)
|
* [puppeteer.executablePath()](#puppeteerexecutablepath)
|
||||||
* [puppeteer.launch([options])](#puppeteerlaunchoptions)
|
* [puppeteer.launch([options])](#puppeteerlaunchoptions)
|
||||||
|
* [puppeteer.networkConditions](#puppeteernetworkconditions)
|
||||||
* [puppeteer.product](#puppeteerproduct)
|
* [puppeteer.product](#puppeteerproduct)
|
||||||
* [puppeteer.registerCustomQueryHandler(name, queryHandler)](#puppeteerregistercustomqueryhandlername-queryhandler)
|
* [puppeteer.registerCustomQueryHandler(name, queryHandler)](#puppeteerregistercustomqueryhandlername-queryhandler)
|
||||||
* [puppeteer.unregisterCustomQueryHandler(name)](#puppeteerunregistercustomqueryhandlername)
|
* [puppeteer.unregisterCustomQueryHandler(name)](#puppeteerunregistercustomqueryhandlername)
|
||||||
@ -128,6 +129,7 @@
|
|||||||
* [page.emulateIdleState(overrides)](#pageemulateidlestateoverrides)
|
* [page.emulateIdleState(overrides)](#pageemulateidlestateoverrides)
|
||||||
* [page.emulateMediaFeatures(features)](#pageemulatemediafeaturesfeatures)
|
* [page.emulateMediaFeatures(features)](#pageemulatemediafeaturesfeatures)
|
||||||
* [page.emulateMediaType(type)](#pageemulatemediatypetype)
|
* [page.emulateMediaType(type)](#pageemulatemediatypetype)
|
||||||
|
* [page.emulateNetworkConditions(networkConditions)](#pageemulatenetworkconditionsnetworkconditions)
|
||||||
* [page.emulateTimezone(timezoneId)](#pageemulatetimezonetimezoneid)
|
* [page.emulateTimezone(timezoneId)](#pageemulatetimezonetimezoneid)
|
||||||
* [page.emulateVisionDeficiency(type)](#pageemulatevisiondeficiencytype)
|
* [page.emulateVisionDeficiency(type)](#pageemulatevisiondeficiencytype)
|
||||||
* [page.evaluate(pageFunction[, ...args])](#pageevaluatepagefunction-args)
|
* [page.evaluate(pageFunction[, ...args])](#pageevaluatepagefunction-args)
|
||||||
@ -610,6 +612,26 @@ const browser = await puppeteer.launch({
|
|||||||
>
|
>
|
||||||
> See [`this article`](https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/) for a description of the differences between Chromium and Chrome. [`This article`](https://chromium.googlesource.com/chromium/src/+/lkgr/docs/chromium_browser_vs_google_chrome.md) describes some differences for Linux users.
|
> See [`this article`](https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/) for a description of the differences between Chromium and Chrome. [`This article`](https://chromium.googlesource.com/chromium/src/+/lkgr/docs/chromium_browser_vs_google_chrome.md) describes some differences for Linux users.
|
||||||
|
|
||||||
|
#### puppeteer.networkConditions
|
||||||
|
- returns: <[Object]>
|
||||||
|
|
||||||
|
Returns a list of network conditions to be used with [`page.emulateNetworkConditions(networkConditions)`](#pageemulatenetworkconditionsnetworkconditions). Actual list of
|
||||||
|
conditions can be found in [`src/common/NetworkConditions.ts`](https://github.com/puppeteer/puppeteer/blob/main/src/common/NetworkConditions.ts).
|
||||||
|
|
||||||
|
```js
|
||||||
|
const puppeteer = require('puppeteer');
|
||||||
|
const slow3G = puppeteer.networkConditions['Slow 3G'];
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const browser = await puppeteer.launch();
|
||||||
|
const page = await browser.newPage();
|
||||||
|
await page.emulateNetworkConditions(slow3G);
|
||||||
|
await page.goto('https://www.google.com');
|
||||||
|
// other actions...
|
||||||
|
await browser.close();
|
||||||
|
})();
|
||||||
|
```
|
||||||
|
|
||||||
#### puppeteer.product
|
#### puppeteer.product
|
||||||
- returns: <[string]> returns the name of the browser that is under automation (`"chrome"` or `"firefox"`)
|
- returns: <[string]> returns the name of the browser that is under automation (`"chrome"` or `"firefox"`)
|
||||||
|
|
||||||
@ -1441,6 +1463,29 @@ await page.evaluate(() => matchMedia('print').matches);
|
|||||||
// → false
|
// → false
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### page.emulateNetworkConditions(networkConditions)
|
||||||
|
- `networkConditions` <?[Object]> Passing `null` disables network condition emulation.
|
||||||
|
- `download` <[number]> Download speed (bytes/s), `-1` to disable
|
||||||
|
- `upload` <[number]> Upload speed (bytes/s), `-1` to disable
|
||||||
|
- `latency` <[number]> Latency (ms), `0` to disable
|
||||||
|
- returns: <[Promise]>
|
||||||
|
|
||||||
|
> **NOTE** This does not affect WebSockets and WebRTC PeerConnections (see https://crbug.com/563644)
|
||||||
|
|
||||||
|
```js
|
||||||
|
const puppeteer = require('puppeteer');
|
||||||
|
const slow3G = puppeteer.networkConditions['Slow 3G'];
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const browser = await puppeteer.launch();
|
||||||
|
const page = await browser.newPage();
|
||||||
|
await page.emulateNetworkConditions(slow3G);
|
||||||
|
await page.goto('https://www.google.com');
|
||||||
|
// other actions...
|
||||||
|
await browser.close();
|
||||||
|
})();
|
||||||
|
```
|
||||||
|
|
||||||
#### page.emulateTimezone(timezoneId)
|
#### page.emulateTimezone(timezoneId)
|
||||||
- `timezoneId` <?[string]> Changes the timezone of the page. See [ICU’s `metaZones.txt`](https://cs.chromium.org/chromium/src/third_party/icu/source/data/misc/metaZones.txt?rcl=faee8bc70570192d82d2978a71e2a615788597d1) for a list of supported timezone IDs. Passing `null` disables timezone emulation.
|
- `timezoneId` <?[string]> Changes the timezone of the page. See [ICU’s `metaZones.txt`](https://cs.chromium.org/chromium/src/third_party/icu/source/data/misc/metaZones.txt?rcl=faee8bc70570192d82d2978a71e2a615788597d1) for a list of supported timezone IDs. Passing `null` disables timezone emulation.
|
||||||
- returns: <[Promise]>
|
- returns: <[Promise]>
|
||||||
|
32
src/common/NetworkConditions.ts
Normal file
32
src/common/NetworkConditions.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2021 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { NetworkConditions } from './NetworkManager.js';
|
||||||
|
|
||||||
|
export type PredefinedNetworkConditions = { [name: string]: NetworkConditions };
|
||||||
|
|
||||||
|
export const networkConditions: PredefinedNetworkConditions = {
|
||||||
|
'Slow 3G': {
|
||||||
|
download: ((500 * 1000) / 8) * 0.8,
|
||||||
|
upload: ((500 * 1000) / 8) * 0.8,
|
||||||
|
latency: 400 * 5,
|
||||||
|
},
|
||||||
|
'Fast 3G': {
|
||||||
|
download: ((1.6 * 1000 * 1000) / 8) * 0.9,
|
||||||
|
upload: ((750 * 1000) / 8) * 0.9,
|
||||||
|
latency: 150 * 3.75,
|
||||||
|
},
|
||||||
|
};
|
@ -30,6 +30,22 @@ export interface Credentials {
|
|||||||
password: string;
|
password: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export interface NetworkConditions {
|
||||||
|
// Download speed (bytes/s)
|
||||||
|
download: number;
|
||||||
|
// Upload speed (bytes/s)
|
||||||
|
upload: number;
|
||||||
|
// Latency (ms)
|
||||||
|
latency: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface InternalNetworkConditions extends NetworkConditions {
|
||||||
|
offline: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We use symbols to prevent any external parties listening to these events.
|
* We use symbols to prevent any external parties listening to these events.
|
||||||
* They are internal to Puppeteer.
|
* They are internal to Puppeteer.
|
||||||
@ -56,13 +72,18 @@ export class NetworkManager extends EventEmitter {
|
|||||||
Protocol.Network.RequestWillBeSentEvent
|
Protocol.Network.RequestWillBeSentEvent
|
||||||
>();
|
>();
|
||||||
_extraHTTPHeaders: Record<string, string> = {};
|
_extraHTTPHeaders: Record<string, string> = {};
|
||||||
_offline = false;
|
|
||||||
_credentials?: Credentials = null;
|
_credentials?: Credentials = null;
|
||||||
_attemptedAuthentications = new Set<string>();
|
_attemptedAuthentications = new Set<string>();
|
||||||
_userRequestInterceptionEnabled = false;
|
_userRequestInterceptionEnabled = false;
|
||||||
_protocolRequestInterceptionEnabled = false;
|
_protocolRequestInterceptionEnabled = false;
|
||||||
_userCacheDisabled = false;
|
_userCacheDisabled = false;
|
||||||
_requestIdToInterceptionId = new Map<string, string>();
|
_requestIdToInterceptionId = new Map<string, string>();
|
||||||
|
_emulatedNetworkConditions: InternalNetworkConditions = {
|
||||||
|
offline: false,
|
||||||
|
upload: -1,
|
||||||
|
download: -1,
|
||||||
|
latency: 0,
|
||||||
|
};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
client: CDPSession,
|
client: CDPSession,
|
||||||
@ -130,14 +151,32 @@ export class NetworkManager extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async setOfflineMode(value: boolean): Promise<void> {
|
async setOfflineMode(value: boolean): Promise<void> {
|
||||||
if (this._offline === value) return;
|
this._emulatedNetworkConditions.offline = value;
|
||||||
this._offline = value;
|
await this._updateNetworkConditions();
|
||||||
|
}
|
||||||
|
|
||||||
|
async emulateNetworkConditions(
|
||||||
|
networkConditions: NetworkConditions | null
|
||||||
|
): Promise<void> {
|
||||||
|
this._emulatedNetworkConditions.upload = networkConditions
|
||||||
|
? networkConditions.upload
|
||||||
|
: -1;
|
||||||
|
this._emulatedNetworkConditions.download = networkConditions
|
||||||
|
? networkConditions.download
|
||||||
|
: -1;
|
||||||
|
this._emulatedNetworkConditions.latency = networkConditions
|
||||||
|
? networkConditions.latency
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
await this._updateNetworkConditions();
|
||||||
|
}
|
||||||
|
|
||||||
|
async _updateNetworkConditions(): Promise<void> {
|
||||||
await this._client.send('Network.emulateNetworkConditions', {
|
await this._client.send('Network.emulateNetworkConditions', {
|
||||||
offline: this._offline,
|
offline: this._emulatedNetworkConditions.offline,
|
||||||
// values of 0 remove any active throttling. crbug.com/456324#c9
|
latency: this._emulatedNetworkConditions.latency,
|
||||||
latency: 0,
|
uploadThroughput: this._emulatedNetworkConditions.upload,
|
||||||
downloadThroughput: -1,
|
downloadThroughput: this._emulatedNetworkConditions.download,
|
||||||
uploadThroughput: -1,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,11 @@ import { Browser, BrowserContext } from './Browser.js';
|
|||||||
import { Target } from './Target.js';
|
import { Target } from './Target.js';
|
||||||
import { createJSHandle, JSHandle, ElementHandle } from './JSHandle.js';
|
import { createJSHandle, JSHandle, ElementHandle } from './JSHandle.js';
|
||||||
import { Viewport } from './PuppeteerViewport.js';
|
import { Viewport } from './PuppeteerViewport.js';
|
||||||
import { Credentials, NetworkManagerEmittedEvents } from './NetworkManager.js';
|
import {
|
||||||
|
Credentials,
|
||||||
|
NetworkConditions,
|
||||||
|
NetworkManagerEmittedEvents,
|
||||||
|
} from './NetworkManager.js';
|
||||||
import { HTTPRequest } from './HTTPRequest.js';
|
import { HTTPRequest } from './HTTPRequest.js';
|
||||||
import { HTTPResponse } from './HTTPResponse.js';
|
import { HTTPResponse } from './HTTPResponse.js';
|
||||||
import { Accessibility } from './Accessibility.js';
|
import { Accessibility } from './Accessibility.js';
|
||||||
@ -693,6 +697,14 @@ export class Page extends EventEmitter {
|
|||||||
return this._frameManager.networkManager().setOfflineMode(enabled);
|
return this._frameManager.networkManager().setOfflineMode(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emulateNetworkConditions(
|
||||||
|
networkConditions: NetworkConditions | null
|
||||||
|
): Promise<void> {
|
||||||
|
return this._frameManager
|
||||||
|
.networkManager()
|
||||||
|
.emulateNetworkConditions(networkConditions);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param timeout - Maximum navigation time in milliseconds.
|
* @param timeout - Maximum navigation time in milliseconds.
|
||||||
*/
|
*/
|
||||||
|
@ -26,6 +26,10 @@ import {
|
|||||||
} from './QueryHandler.js';
|
} from './QueryHandler.js';
|
||||||
import { Product } from './Product.js';
|
import { Product } from './Product.js';
|
||||||
import { connectToBrowser, BrowserOptions } from './BrowserConnector.js';
|
import { connectToBrowser, BrowserOptions } from './BrowserConnector.js';
|
||||||
|
import {
|
||||||
|
PredefinedNetworkConditions,
|
||||||
|
networkConditions,
|
||||||
|
} from './NetworkConditions.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Settings that are common to the Puppeteer class, regardless of enviroment.
|
* Settings that are common to the Puppeteer class, regardless of enviroment.
|
||||||
@ -125,6 +129,31 @@ export class Puppeteer {
|
|||||||
return puppeteerErrors;
|
return puppeteerErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @remarks
|
||||||
|
* Returns a list of network conditions to be used with `page.emulateNetworkConditions(networkConditions)`. Actual list of predefined conditions can be found in {@link https://github.com/puppeteer/puppeteer/blob/main/src/common/NetworkConditions.ts | src/common/NetworkConditions.ts}.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* const puppeteer = require('puppeteer');
|
||||||
|
* const slow3G = puppeteer.networkConditions['Slow 3G'];
|
||||||
|
*
|
||||||
|
* (async () => {
|
||||||
|
* const browser = await puppeteer.launch();
|
||||||
|
* const page = await browser.newPage();
|
||||||
|
* await page.emulateNetworkConditions(slow3G);
|
||||||
|
* await page.goto('https://www.google.com');
|
||||||
|
* // other actions...
|
||||||
|
* await browser.close();
|
||||||
|
* })();
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
get networkConditions(): PredefinedNetworkConditions {
|
||||||
|
return networkConditions;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a {@link CustomQueryHandler | custom query handler}. After
|
* Registers a {@link CustomQueryHandler | custom query handler}. After
|
||||||
* registration, the handler can be used everywhere where a selector is
|
* registration, the handler can be used everywhere where a selector is
|
||||||
|
@ -388,6 +388,28 @@ describe('Page', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describeFailsFirefox('Page.emulateNetworkConditions', function () {
|
||||||
|
it('should change navigator.connection.effectiveType', async () => {
|
||||||
|
const { page, puppeteer } = getTestState();
|
||||||
|
|
||||||
|
const slow3G = puppeteer.networkConditions['Slow 3G'];
|
||||||
|
const fast3G = puppeteer.networkConditions['Fast 3G'];
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await page.evaluate('window.navigator.connection.effectiveType')
|
||||||
|
).toBe('4g');
|
||||||
|
await page.emulateNetworkConditions(fast3G);
|
||||||
|
expect(
|
||||||
|
await page.evaluate('window.navigator.connection.effectiveType')
|
||||||
|
).toBe('3g');
|
||||||
|
await page.emulateNetworkConditions(slow3G);
|
||||||
|
expect(
|
||||||
|
await page.evaluate('window.navigator.connection.effectiveType')
|
||||||
|
).toBe('2g');
|
||||||
|
await page.emulateNetworkConditions(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('ExecutionContext.queryObjects', function () {
|
describe('ExecutionContext.queryObjects', function () {
|
||||||
itFailsFirefox('should work', async () => {
|
itFailsFirefox('should work', async () => {
|
||||||
const { page } = getTestState();
|
const { page } = getTestState();
|
||||||
|
@ -576,6 +576,13 @@ function compareDocumentations(actual, expected) {
|
|||||||
expectedName: 'Viewport',
|
expectedName: 'Viewport',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'Method Page.emulateNetworkConditions() networkConditions',
|
||||||
|
{
|
||||||
|
actualName: 'Object',
|
||||||
|
expectedName: 'NetworkConditions',
|
||||||
|
},
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'Method Page.setViewport() options.viewport',
|
'Method Page.setViewport() options.viewport',
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user