feat: add page.emulateNetworkConditions (#6759)

This commit is contained in:
Jan Scheffler 2021-01-21 10:00:57 +01:00 committed by GitHub
parent ebd087a316
commit 5ea76e9333
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 195 additions and 9 deletions

View File

@ -42,6 +42,7 @@
* [puppeteer.errors](#puppeteererrors)
* [puppeteer.executablePath()](#puppeteerexecutablepath)
* [puppeteer.launch([options])](#puppeteerlaunchoptions)
* [puppeteer.networkConditions](#puppeteernetworkconditions)
* [puppeteer.product](#puppeteerproduct)
* [puppeteer.registerCustomQueryHandler(name, queryHandler)](#puppeteerregistercustomqueryhandlername-queryhandler)
* [puppeteer.unregisterCustomQueryHandler(name)](#puppeteerunregistercustomqueryhandlername)
@ -128,6 +129,7 @@
* [page.emulateIdleState(overrides)](#pageemulateidlestateoverrides)
* [page.emulateMediaFeatures(features)](#pageemulatemediafeaturesfeatures)
* [page.emulateMediaType(type)](#pageemulatemediatypetype)
* [page.emulateNetworkConditions(networkConditions)](#pageemulatenetworkconditionsnetworkconditions)
* [page.emulateTimezone(timezoneId)](#pageemulatetimezonetimezoneid)
* [page.emulateVisionDeficiency(type)](#pageemulatevisiondeficiencytype)
* [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.
#### 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
- 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
```
#### 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)
- `timezoneId` <?[string]> Changes the timezone of the page. See [ICUs `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]>

View 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,
},
};

View File

@ -30,6 +30,22 @@ export interface Credentials {
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.
* They are internal to Puppeteer.
@ -56,13 +72,18 @@ export class NetworkManager extends EventEmitter {
Protocol.Network.RequestWillBeSentEvent
>();
_extraHTTPHeaders: Record<string, string> = {};
_offline = false;
_credentials?: Credentials = null;
_attemptedAuthentications = new Set<string>();
_userRequestInterceptionEnabled = false;
_protocolRequestInterceptionEnabled = false;
_userCacheDisabled = false;
_requestIdToInterceptionId = new Map<string, string>();
_emulatedNetworkConditions: InternalNetworkConditions = {
offline: false,
upload: -1,
download: -1,
latency: 0,
};
constructor(
client: CDPSession,
@ -130,14 +151,32 @@ export class NetworkManager extends EventEmitter {
}
async setOfflineMode(value: boolean): Promise<void> {
if (this._offline === value) return;
this._offline = value;
this._emulatedNetworkConditions.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', {
offline: this._offline,
// values of 0 remove any active throttling. crbug.com/456324#c9
latency: 0,
downloadThroughput: -1,
uploadThroughput: -1,
offline: this._emulatedNetworkConditions.offline,
latency: this._emulatedNetworkConditions.latency,
uploadThroughput: this._emulatedNetworkConditions.upload,
downloadThroughput: this._emulatedNetworkConditions.download,
});
}

View File

@ -37,7 +37,11 @@ import { Browser, BrowserContext } from './Browser.js';
import { Target } from './Target.js';
import { createJSHandle, JSHandle, ElementHandle } from './JSHandle.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 { HTTPResponse } from './HTTPResponse.js';
import { Accessibility } from './Accessibility.js';
@ -693,6 +697,14 @@ export class Page extends EventEmitter {
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.
*/

View File

@ -26,6 +26,10 @@ import {
} from './QueryHandler.js';
import { Product } from './Product.js';
import { connectToBrowser, BrowserOptions } from './BrowserConnector.js';
import {
PredefinedNetworkConditions,
networkConditions,
} from './NetworkConditions.js';
/**
* Settings that are common to the Puppeteer class, regardless of enviroment.
@ -125,6 +129,31 @@ export class Puppeteer {
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
* registration, the handler can be used everywhere where a selector is

View File

@ -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 () {
itFailsFirefox('should work', async () => {
const { page } = getTestState();

View File

@ -576,6 +576,13 @@ function compareDocumentations(actual, expected) {
expectedName: 'Viewport',
},
],
[
'Method Page.emulateNetworkConditions() networkConditions',
{
actualName: 'Object',
expectedName: 'NetworkConditions',
},
],
[
'Method Page.setViewport() options.viewport',
{