Skip to content
This repository has been archived by the owner on Jun 6, 2019. It is now read-only.

Commit

Permalink
Merge d262ebf into d0dbead
Browse files Browse the repository at this point in the history
  • Loading branch information
csabapalfi committed Jun 22, 2018
2 parents d0dbead + d262ebf commit 2824451
Show file tree
Hide file tree
Showing 6 changed files with 3,434 additions and 187 deletions.
112 changes: 38 additions & 74 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,102 +5,66 @@
[![Build Status](https://travis-ci.org/csabapalfi/puppeteer-network-stats.svg?branch=master)](https://travis-ci.org/csabapalfi/puppeteer-network-stats/)
[![Coverage Status](https://coveralls.io/repos/github/csabapalfi/puppeteer-network-stats/badge.svg)](https://coveralls.io/github/csabapalfi/puppeteer-network-stats)

Attach to a puppeteer page and collect network stats.
Attach to a puppeteer page and collect network request stats.

## Install

```sh
npm install puppeteer-network-stats
```

## Usage - cli
## Usage

Requires puppeteer to be installed globally, then:
Example below:

```sh
puppeteer-network-stats <url> <device>
```

e.g.
* captures data for all requests

```sh
npm install --global puppeteer puppeteer-network-stats
```
* request URLs based on the `Network.requestWillBeSent` event

```sh
puppeteer-network-stats https://www.google.com | jq .
{
"url": "https://www.google.com"
"requests": [
{
"type": "Document",
"url": "https://www.google.com/",
"status": 200,
"size": 72313
},
...
]
}
```
* response status based on the `Network.responseReceived` event

You can also specify a device to emulate. See the list of [all available devices here](https://github.com/GoogleChrome/puppeteer/blob/master/DeviceDescriptors.js).
* all event data is merged based on request ids

```sh
puppeteer-network-stats https://www.google.com "iPhone X" | jq .
{
"url": "https://www.google.com"
"device": {
"name": "iPhone X",
...
},
"requests": [
{
"type": "Document",
"url": "https://www.google.com/",
"status": 200,
"size": 72313
},
...
]
}
```
```js
const PuppeteerNetworkStats = require('puppeteer-network-stats');

## Usage - module
const config = {
requestWillBeSent: ({request: {url}}) => ({url}),
responseReceived: ({response: {status}}) => ({status})
};

You can just require the run function (that's also used for the cli).
const networkStats = new PuppeteerNetworkStats(config);

```js
const run = require('puppeteer-network-stats/run');
console.log(await run('https://www.google.com', 'iPhone X'));
```
// const browser = await puppeteer.launch();
// const page = browser.newPage();

If you want to interact with your page and customize even more:
await networkStats.attach(page); // creates CDP session, registers listeners

```js
const PuppeteerNetworkStats = require('puppeteer-network-stats');
const networkStats = new PuppeteerNetworkStats();
await networkStats.attach(page);
// ... goto a page, etc
networkStats.getStats() // gives you an array of all requests
```
// await page.goto(url);

It's also easy to capture data from any [Network.*](https://chromedevtools.github.io/devtools-protocol/tot/Network#event-dataReceived) event.
networkStats.getRequests(); // gives you an map of all request data by id

e.g. to capture mimeType, too
networkStats.clearRequests(); // clears all captured requests

```js
const networkStats = new PuppeteerNetworkStats({
responseReceived:
({response: {status, mimeType}}) =>
({status, mimeType}),
});
await networkStats.detach(page); // detaches CDP session
```

## Caveats
A similar configuration allows capturing data from any [Network.*](https://chromedevtools.github.io/devtools-protocol/tot/Network#event-dataReceived) events.

* The default config doesn't handle `requestServedFromCache` and `loadingFailed` events.
* Overriding data capture for an event type completely overrides fields captured by default.
As an example for debugging we can just log all event data easily:

## Why not just build HAR files or use `puppeteer-har`?

See [sitespeedio/chrome-har#15](https://github.com/sitespeedio/chrome-har/issues/15). It's not trivial to build HAR from just network events hence this minimalist module that's not concerned with the specific HAR format.
```js
const config = [
'requestWillBeSent',
'requestServedFromCache',
'loadingFinished',
'loadingFailed',
'responseReceived'
].map(
(event) => ({
[event]: (params) => ({[event]: params})
})
).reduce(
(result, item) => ({...result, ...item}), {}
)
```
30 changes: 13 additions & 17 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,29 @@
const {entries} = Object;

const defaults = {
requestWillBeSent: ({type, request: {url}}) => ({type, url}),
responseReceived: ({response: {status}}) => ({status}),
loadingFinished: ({encodedDataLength: size}) => ({size}),
};

class PuppeteerNetworkStats {

constructor(config = {}) {
this.config = {...defaults, ...config};
this.stats = {};
constructor(config) {
this.config = config;
this.requests = {};
}

onEvent(capture, {requestId, ...params}) {
this.stats[requestId] = {
...this.stats[requestId],
onEvent(capture, {requestId: id, ...params}) {
this.requests[id] = {
...this.requests[id],
...capture(params)
};
}

getStats() {
return entries(this.stats).map(([,value]) => value);
getRequests() {
return this.requests;
}

clearRequests() {
this.requests = {};
}

async attach(page) {
this.client = await page.target().createCDPSession();
await this.client.send('Network.enable');
for (let [event, capture] of entries(this.config)) {
for (let [event, capture] of Object.entries(this.config)) {
const callback = this.onEvent.bind(this, capture);
await this.client.on(`Network.${event}`, callback);
}
Expand Down
Loading

0 comments on commit 2824451

Please sign in to comment.