mirror of
https://github.com/hanzoai/puppeteer.git
synced 2026-09-24 17:02:14 +00:00
feat(page): expose heap snapshot getter (#14610)
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: OrKoN <[email protected]>
This commit is contained in:
committed by
GitHub
co-authored by
google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
OrKoN
parent
9aa2690c51
commit
057608f94f
@@ -1017,6 +1017,15 @@ Device in a request prompt.
|
||||
</td></tr>
|
||||
<tr><td>
|
||||
|
||||
<span id="heapsnapshotoptions">[HeapSnapshotOptions](./puppeteer.heapsnapshotoptions.md)</span>
|
||||
|
||||
</td><td>
|
||||
|
||||
Options for [Page.captureHeapSnapshot()](./puppeteer.page.captureheapsnapshot.md).
|
||||
|
||||
</td></tr>
|
||||
<tr><td>
|
||||
|
||||
<span id="interceptresolutionstate">[InterceptResolutionState](./puppeteer.interceptresolutionstate.md)</span>
|
||||
|
||||
</td><td>
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
sidebar_label: HeapSnapshotOptions
|
||||
---
|
||||
|
||||
# HeapSnapshotOptions interface
|
||||
|
||||
Options for [Page.captureHeapSnapshot()](./puppeteer.page.captureheapsnapshot.md).
|
||||
|
||||
### Signature
|
||||
|
||||
```typescript
|
||||
export interface HeapSnapshotOptions
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
<table><thead><tr><th>
|
||||
|
||||
Property
|
||||
|
||||
</th><th>
|
||||
|
||||
Modifiers
|
||||
|
||||
</th><th>
|
||||
|
||||
Type
|
||||
|
||||
</th><th>
|
||||
|
||||
Description
|
||||
|
||||
</th><th>
|
||||
|
||||
Default
|
||||
|
||||
</th></tr></thead>
|
||||
<tbody><tr><td>
|
||||
|
||||
<span id="path">path</span>
|
||||
|
||||
</td><td>
|
||||
|
||||
</td><td>
|
||||
|
||||
string
|
||||
|
||||
</td><td>
|
||||
|
||||
The file path to save the heap snapshot to.
|
||||
|
||||
</td><td>
|
||||
|
||||
</td></tr>
|
||||
</tbody></table>
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
sidebar_label: Page.captureHeapSnapshot
|
||||
---
|
||||
|
||||
# Page.captureHeapSnapshot() method
|
||||
|
||||
Captures a snapshot of the JavaScript heap and writes it to a file.
|
||||
|
||||
### Signature
|
||||
|
||||
```typescript
|
||||
class Page {
|
||||
abstract captureHeapSnapshot(options: HeapSnapshotOptions): Promise<void>;
|
||||
}
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
<table><thead><tr><th>
|
||||
|
||||
Parameter
|
||||
|
||||
</th><th>
|
||||
|
||||
Type
|
||||
|
||||
</th><th>
|
||||
|
||||
Description
|
||||
|
||||
</th></tr></thead>
|
||||
<tbody><tr><td>
|
||||
|
||||
options
|
||||
|
||||
</td><td>
|
||||
|
||||
[HeapSnapshotOptions](./puppeteer.heapsnapshotoptions.md)
|
||||
|
||||
</td><td>
|
||||
|
||||
</td></tr>
|
||||
</tbody></table>
|
||||
|
||||
**Returns:**
|
||||
|
||||
Promise<void>
|
||||
@@ -409,6 +409,17 @@ Get the browser context that the page belongs to.
|
||||
</td></tr>
|
||||
<tr><td>
|
||||
|
||||
<span id="captureheapsnapshot">[captureHeapSnapshot(options)](./puppeteer.page.captureheapsnapshot.md)</span>
|
||||
|
||||
</td><td>
|
||||
|
||||
</td><td>
|
||||
|
||||
Captures a snapshot of the JavaScript heap and writes it to a file.
|
||||
|
||||
</td></tr>
|
||||
<tr><td>
|
||||
|
||||
<span id="click">[click(selector, options)](./puppeteer.page.click.md)</span>
|
||||
|
||||
</td><td>
|
||||
|
||||
@@ -647,6 +647,18 @@ export interface ReloadOptions extends WaitForOptions {
|
||||
ignoreCache?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for {@link Page.captureHeapSnapshot}.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface HeapSnapshotOptions {
|
||||
/**
|
||||
* The file path to save the heap snapshot to.
|
||||
*/
|
||||
path: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Page provides methods to interact with a single tab or
|
||||
* {@link https://developer.chrome.com/extensions/background_pages | extension background page}
|
||||
@@ -1721,6 +1733,11 @@ export abstract class Page extends EventEmitter<PageEvents> {
|
||||
*/
|
||||
abstract metrics(): Promise<Metrics>;
|
||||
|
||||
/**
|
||||
* Captures a snapshot of the JavaScript heap and writes it to a file.
|
||||
*/
|
||||
abstract captureHeapSnapshot(options: HeapSnapshotOptions): Promise<void>;
|
||||
|
||||
/**
|
||||
* The page's URL.
|
||||
*
|
||||
|
||||
@@ -18,6 +18,7 @@ import type {HTTPResponse} from '../api/HTTPResponse.js';
|
||||
import type {
|
||||
Credentials,
|
||||
GeolocationOptions,
|
||||
HeapSnapshotOptions,
|
||||
MediaFeature,
|
||||
PageEvents,
|
||||
ReloadOptions,
|
||||
@@ -952,6 +953,12 @@ export class BidiPage extends Page {
|
||||
throw new UnsupportedOperation();
|
||||
}
|
||||
|
||||
override async captureHeapSnapshot(
|
||||
_options: HeapSnapshotOptions,
|
||||
): Promise<void> {
|
||||
throw new UnsupportedOperation();
|
||||
}
|
||||
|
||||
override async goBack(
|
||||
options: WaitForOptions = {},
|
||||
): Promise<HTTPResponse | null> {
|
||||
|
||||
@@ -16,7 +16,11 @@ import type {ElementHandle} from '../api/ElementHandle.js';
|
||||
import type {Frame, WaitForOptions} from '../api/Frame.js';
|
||||
import type {HTTPResponse} from '../api/HTTPResponse.js';
|
||||
import type {JSHandle} from '../api/JSHandle.js';
|
||||
import type {Credentials, ReloadOptions} from '../api/Page.js';
|
||||
import type {
|
||||
Credentials,
|
||||
HeapSnapshotOptions,
|
||||
ReloadOptions,
|
||||
} from '../api/Page.js';
|
||||
import {
|
||||
Page,
|
||||
PageEvent,
|
||||
@@ -54,6 +58,7 @@ import {
|
||||
validateDialogType,
|
||||
} from '../common/util.js';
|
||||
import type {Viewport} from '../common/Viewport.js';
|
||||
import {environment} from '../environment.js';
|
||||
import {assert} from '../util/assert.js';
|
||||
import {Deferred} from '../util/Deferred.js';
|
||||
import {AsyncDisposableStack} from '../util/disposable.js';
|
||||
@@ -812,6 +817,40 @@ export class CdpPage extends Page {
|
||||
return this.#buildMetricsObject(response.metrics);
|
||||
}
|
||||
|
||||
override async captureHeapSnapshot(
|
||||
options: HeapSnapshotOptions,
|
||||
): Promise<void> {
|
||||
const {createWriteStream} = environment.value.fs;
|
||||
const stream = createWriteStream(options.path);
|
||||
const streamPromise = new Promise<void>((resolve, reject) => {
|
||||
stream.on('error', reject);
|
||||
stream.on('finish', resolve);
|
||||
});
|
||||
|
||||
const client = this.#primaryTargetClient;
|
||||
await client.send('HeapProfiler.enable');
|
||||
await client.send('HeapProfiler.collectGarbage');
|
||||
|
||||
const handler = (
|
||||
event: Protocol.HeapProfiler.AddHeapSnapshotChunkEvent,
|
||||
) => {
|
||||
stream.write(event.chunk);
|
||||
};
|
||||
client.on('HeapProfiler.addHeapSnapshotChunk', handler);
|
||||
|
||||
try {
|
||||
await client.send('HeapProfiler.takeHeapSnapshot', {
|
||||
reportProgress: false,
|
||||
});
|
||||
} finally {
|
||||
client.off('HeapProfiler.addHeapSnapshotChunk', handler);
|
||||
await client.send('HeapProfiler.disable');
|
||||
}
|
||||
|
||||
stream.end();
|
||||
await streamPromise;
|
||||
}
|
||||
|
||||
#emitMetrics(event: Protocol.Performance.MetricsEvent): void {
|
||||
this.emit(PageEvent.Metrics, {
|
||||
title: event.title,
|
||||
|
||||
@@ -97,6 +97,13 @@
|
||||
"expectations": ["SKIP"],
|
||||
"comment": "Spawns headful browser, needs display or `xvfb` like which is not required for other headless tests"
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[heapSnapshot.spec] *",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
"parameters": ["webDriverBiDi"],
|
||||
"expectations": ["FAIL"],
|
||||
"comment": "Not supported in WebDriver BiDi"
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[interventionHeaders.spec] *",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import fs from 'node:fs';
|
||||
import {mkdtemp, rm} from 'node:fs/promises';
|
||||
import {tmpdir} from 'node:os';
|
||||
import path from 'node:path';
|
||||
|
||||
import expect from 'expect';
|
||||
|
||||
import {getTestState, setupTestBrowserHooks} from '../mocha-utils.js';
|
||||
|
||||
describe('Heap Snapshot', function () {
|
||||
setupTestBrowserHooks();
|
||||
|
||||
let tempDir: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
tempDir = await mkdtemp(path.join(tmpdir(), 'heap-snapshot-'));
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await rm(tempDir, {recursive: true, force: true});
|
||||
});
|
||||
|
||||
it('should capture heap snapshot', async () => {
|
||||
const {page} = await getTestState();
|
||||
const filePath = path.join(tempDir, 'heap.heapsnapshot');
|
||||
|
||||
await page.captureHeapSnapshot({path: filePath});
|
||||
|
||||
expect(fs.existsSync(filePath)).toBe(true);
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
const snapshot = JSON.parse(content);
|
||||
expect(snapshot.snapshot).toBeDefined();
|
||||
expect(snapshot.nodes).toBeDefined();
|
||||
expect(snapshot.edges).toBeDefined();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user