mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
feat(Page): Support Page.getMetrics and metrics event. (#939)
Provides access to the current page performance metrics. Allows to push page metrics from the page JavaScript with console.timeStamp() Fixes #309
This commit is contained in:
parent
77d3c2972f
commit
b82d3197ed
32
docs/api.md
32
docs/api.md
@ -25,6 +25,7 @@
|
|||||||
+ [event: 'framedetached'](#event-framedetached)
|
+ [event: 'framedetached'](#event-framedetached)
|
||||||
+ [event: 'framenavigated'](#event-framenavigated)
|
+ [event: 'framenavigated'](#event-framenavigated)
|
||||||
+ [event: 'load'](#event-load)
|
+ [event: 'load'](#event-load)
|
||||||
|
+ [event: 'metrics'](#event-metrics)
|
||||||
+ [event: 'pageerror'](#event-pageerror)
|
+ [event: 'pageerror'](#event-pageerror)
|
||||||
+ [event: 'request'](#event-request)
|
+ [event: 'request'](#event-request)
|
||||||
+ [event: 'requestfailed'](#event-requestfailed)
|
+ [event: 'requestfailed'](#event-requestfailed)
|
||||||
@ -49,6 +50,7 @@
|
|||||||
+ [page.exposeFunction(name, puppeteerFunction)](#pageexposefunctionname-puppeteerfunction)
|
+ [page.exposeFunction(name, puppeteerFunction)](#pageexposefunctionname-puppeteerfunction)
|
||||||
+ [page.focus(selector)](#pagefocusselector)
|
+ [page.focus(selector)](#pagefocusselector)
|
||||||
+ [page.frames()](#pageframes)
|
+ [page.frames()](#pageframes)
|
||||||
|
+ [page.getMetrics()](#pagegetmetrics)
|
||||||
+ [page.goBack(options)](#pagegobackoptions)
|
+ [page.goBack(options)](#pagegobackoptions)
|
||||||
+ [page.goForward(options)](#pagegoforwardoptions)
|
+ [page.goForward(options)](#pagegoforwardoptions)
|
||||||
+ [page.goto(url, options)](#pagegotourl-options)
|
+ [page.goto(url, options)](#pagegotourl-options)
|
||||||
@ -326,6 +328,15 @@ Emitted when a frame is navigated to a new url.
|
|||||||
|
|
||||||
Emitted when the JavaScript [`load`](https://developer.mozilla.org/en-US/docs/Web/Events/load) event is dispatched.
|
Emitted when the JavaScript [`load`](https://developer.mozilla.org/en-US/docs/Web/Events/load) event is dispatched.
|
||||||
|
|
||||||
|
#### event: 'metrics'
|
||||||
|
- <[Object]>
|
||||||
|
- `title` <[string]> The title passed to `console.timeStamp`.
|
||||||
|
- `metrics` <[Object]> Object containing metrics as key/value pairs. The values
|
||||||
|
of metrics are of <[number]> type.
|
||||||
|
|
||||||
|
Emitted when the JavaScript code makes a call to `console.timeStamp`. For the list
|
||||||
|
of metrics see `page.getMetrics`.
|
||||||
|
|
||||||
#### event: 'pageerror'
|
#### event: 'pageerror'
|
||||||
- <[string]> The exception message
|
- <[string]> The exception message
|
||||||
|
|
||||||
@ -637,6 +648,27 @@ If there's no element matching `selector`, the method throws an error.
|
|||||||
#### page.frames()
|
#### page.frames()
|
||||||
- returns: <[Array]<[Frame]>> An array of all frames attached to the page.
|
- returns: <[Array]<[Frame]>> An array of all frames attached to the page.
|
||||||
|
|
||||||
|
#### page.getMetrics()
|
||||||
|
- returns: <[Object]> Object containing metrics as key/value pairs.
|
||||||
|
- `Timestamp` <[number]> The timestamp when the metrics sample was taken.
|
||||||
|
- `DocumentCount` <[number]> Number of documents in the page.
|
||||||
|
- `FrameCount` <[number]> Number of frames in the page.
|
||||||
|
- `JSEventListenerCount` <[number]> Number of events in the page.
|
||||||
|
- `NodeCount` <[number]> Number of DOM nodes in the page.
|
||||||
|
- `LayoutCount` <[number]> Total number of full or partial page layout.
|
||||||
|
- `RecalcStyleCount` <[number]> Total number of page style recalculations.
|
||||||
|
- `LayoutDuration` <[number]> Combined durations of all page layouts.
|
||||||
|
- `RecalcStyleDuration` <[number]> Combined duration of all page style recalculations.
|
||||||
|
- `ScriptDuration` <[number]> Combined duration of JavaScript execution.
|
||||||
|
- `TaskDuration` <[number]> Combined duration of all tasks performed by the browser.
|
||||||
|
- `JSHeapUsedSize` <[number]> Used JavaScript heap size.
|
||||||
|
- `JSHeapTotalSize` <[number]> Total JavaScript heap size.
|
||||||
|
- `FirstMeaningfulPaint` <[number]> Timestamp of the first meaningful paint event.
|
||||||
|
- `DomContentLoaded` <[number]> Timestamp of the DOM content loaded event.
|
||||||
|
- `NavigationStart` <[number]> Timestamp of the navigation start event.
|
||||||
|
|
||||||
|
> **NOTE** All timestamps are in monotonic time: monotonically increasing time in seconds since an arbitrary point in the past.
|
||||||
|
|
||||||
#### page.goBack(options)
|
#### page.goBack(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.
|
- `timeout` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout.
|
||||||
|
54
lib/Page.js
54
lib/Page.js
@ -40,6 +40,7 @@ class Page extends EventEmitter {
|
|||||||
client.send('Page.enable', {}),
|
client.send('Page.enable', {}),
|
||||||
client.send('Runtime.enable', {}),
|
client.send('Runtime.enable', {}),
|
||||||
client.send('Security.enable', {}),
|
client.send('Security.enable', {}),
|
||||||
|
client.send('Performance.enable', {})
|
||||||
]);
|
]);
|
||||||
if (ignoreHTTPSErrors)
|
if (ignoreHTTPSErrors)
|
||||||
await client.send('Security.setOverrideCertificateErrors', {override: true});
|
await client.send('Security.setOverrideCertificateErrors', {override: true});
|
||||||
@ -87,6 +88,7 @@ class Page extends EventEmitter {
|
|||||||
client.on('Runtime.exceptionThrown', exception => this._handleException(exception.exceptionDetails));
|
client.on('Runtime.exceptionThrown', exception => this._handleException(exception.exceptionDetails));
|
||||||
client.on('Security.certificateError', event => this._onCertificateError(event));
|
client.on('Security.certificateError', event => this._onCertificateError(event));
|
||||||
client.on('Inspector.targetCrashed', event => this._onTargetCrashed());
|
client.on('Inspector.targetCrashed', event => this._onTargetCrashed());
|
||||||
|
client.on('Performance.metrics', event => this._emitMetrics(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
_onTargetCrashed() {
|
_onTargetCrashed() {
|
||||||
@ -304,6 +306,37 @@ class Page extends EventEmitter {
|
|||||||
return this._networkManager.setUserAgent(userAgent);
|
return this._networkManager.setUserAgent(userAgent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {!Promise<!Object>}
|
||||||
|
*/
|
||||||
|
async getMetrics() {
|
||||||
|
const response = await this._client.send('Performance.getMetrics');
|
||||||
|
return this._buildMetricsObject(response.metrics);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {*} event
|
||||||
|
*/
|
||||||
|
_emitMetrics(event) {
|
||||||
|
this.emit(Page.Events.Metrics, {
|
||||||
|
title: event.title,
|
||||||
|
metrics: this._buildMetricsObject(event.metrics)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?Array<!{name: string, value: number}>} metrics
|
||||||
|
* @return {!Object}
|
||||||
|
*/
|
||||||
|
_buildMetricsObject(metrics) {
|
||||||
|
const result = {};
|
||||||
|
for (const metric of metrics || []) {
|
||||||
|
if (supportedMetrics.has(metric.name))
|
||||||
|
result[metric.name] = metric.value;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {!Object} exceptionDetails
|
* @param {!Object} exceptionDetails
|
||||||
*/
|
*/
|
||||||
@ -776,6 +809,26 @@ class Page extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @type {!Set<string>} */
|
||||||
|
const supportedMetrics = new Set([
|
||||||
|
'Timestamp',
|
||||||
|
'DocumentCount',
|
||||||
|
'FrameCount',
|
||||||
|
'JSEventListenerCount',
|
||||||
|
'NodeCount',
|
||||||
|
'LayoutCount',
|
||||||
|
'RecalcStyleCount',
|
||||||
|
'LayoutDuration',
|
||||||
|
'RecalcStyleDuration',
|
||||||
|
'ScriptDuration',
|
||||||
|
'TaskDuration',
|
||||||
|
'JSHeapUsedSize',
|
||||||
|
'JSHeapTotalSize',
|
||||||
|
'FirstMeaningfulPaint',
|
||||||
|
'DomContentLoaded',
|
||||||
|
'NavigationStart',
|
||||||
|
]);
|
||||||
|
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
Page.PaperFormats = {
|
Page.PaperFormats = {
|
||||||
letter: {width: 8.5, height: 11},
|
letter: {width: 8.5, height: 11},
|
||||||
@ -844,6 +897,7 @@ Page.Events = {
|
|||||||
FrameDetached: 'framedetached',
|
FrameDetached: 'framedetached',
|
||||||
FrameNavigated: 'framenavigated',
|
FrameNavigated: 'framenavigated',
|
||||||
Load: 'load',
|
Load: 'load',
|
||||||
|
Metrics: 'metrics',
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
41
test/test.js
41
test/test.js
@ -749,6 +749,47 @@ describe('Page', function() {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Page.getMetrics', function() {
|
||||||
|
it('should get metrics from a page', SX(async function() {
|
||||||
|
await page.goto('about:blank');
|
||||||
|
const metrics = await page.getMetrics();
|
||||||
|
checkMetrics(metrics);
|
||||||
|
}));
|
||||||
|
it('metrics event fired on console.timeStamp', SX(async function() {
|
||||||
|
const metricsPromise = new Promise(fulfill => page.once('metrics', fulfill));
|
||||||
|
await page.evaluate(() => console.timeStamp('test42'));
|
||||||
|
const metrics = await metricsPromise;
|
||||||
|
expect(metrics.title).toBe('test42');
|
||||||
|
checkMetrics(metrics.metrics);
|
||||||
|
}));
|
||||||
|
function checkMetrics(metrics) {
|
||||||
|
const metricsToCheck = new Set([
|
||||||
|
'Timestamp',
|
||||||
|
'DocumentCount',
|
||||||
|
'FrameCount',
|
||||||
|
'JSEventListenerCount',
|
||||||
|
'NodeCount',
|
||||||
|
'LayoutCount',
|
||||||
|
'RecalcStyleCount',
|
||||||
|
'LayoutDuration',
|
||||||
|
'RecalcStyleDuration',
|
||||||
|
'ScriptDuration',
|
||||||
|
'TaskDuration',
|
||||||
|
'JSHeapUsedSize',
|
||||||
|
'JSHeapTotalSize',
|
||||||
|
'FirstMeaningfulPaint',
|
||||||
|
'DomContentLoaded',
|
||||||
|
'NavigationStart',
|
||||||
|
]);
|
||||||
|
for (const name in metrics) {
|
||||||
|
expect(metricsToCheck.has(name)).toBeTruthy();
|
||||||
|
expect(metrics[name]).toBeGreaterThanOrEqual(0);
|
||||||
|
metricsToCheck.delete(name);
|
||||||
|
}
|
||||||
|
expect(metricsToCheck.size).toBe(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
describe('Page.goto', function() {
|
describe('Page.goto', function() {
|
||||||
it('should navigate to about:blank', SX(async function() {
|
it('should navigate to about:blank', SX(async function() {
|
||||||
const response = await page.goto('about:blank');
|
const response = await page.goto('about:blank');
|
||||||
|
Loading…
Reference in New Issue
Block a user