Skip to content

test(test-utils): Add MemoryProfiler for heap snapshot testing via CDP#20555

Merged
JPeer264 merged 3 commits intodevelopfrom
jp/e2e-test-memory-profiler
May 4, 2026
Merged

test(test-utils): Add MemoryProfiler for heap snapshot testing via CDP#20555
JPeer264 merged 3 commits intodevelopfrom
jp/e2e-test-memory-profiler

Conversation

@JPeer264
Copy link
Copy Markdown
Member

@JPeer264 JPeer264 commented Apr 28, 2026

Adds CDPClient and MemoryProfiler to test-utils for V8 heap profiling. This PR prevents #20407 entirely by comparing heap snapshots.

Within a Playwright test following can now be used:

const profiler = new MemoryProfiler({ port: INSPECTOR_PORT });

await profiler.connect();

// ... make initial requests to let the runtime settle ...

const baselineSnapshot = await profiler.takeHeapSnapshot();

// ... run some operations that might leak memory ...

const finalSnapshot = await profiler.takeHeapSnapshot();
const result = profiler.compareSnapshots(baselineSnapshot, finalSnapshot);

expect(result.nodeGrowthPercent).toBeLessThan(1);

await profiler.close();

This works by using the Chrome Developer Protocol (CDP). There is also a CDPSession API available from Playwright, but that would only work for sessions which run in the browser. Theoretically, this could also work in integration tests, but the idea is that this could in the future also be extended to use the CDPSession from Playwright for browser tests.

@JPeer264 JPeer264 self-assigned this Apr 28, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 28, 2026

size-limit report 📦

Path Size % Change Change
@sentry/browser 26.31 kB - -
@sentry/browser - with treeshaking flags 24.8 kB - -
@sentry/browser (incl. Tracing) 44.2 kB - -
@sentry/browser (incl. Tracing + Span Streaming) 46.42 kB - -
@sentry/browser (incl. Tracing, Profiling) 49.16 kB - -
@sentry/browser (incl. Tracing, Replay) 83.58 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 73.04 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 88.26 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 100.87 kB - -
@sentry/browser (incl. Feedback) 43.47 kB - -
@sentry/browser (incl. sendFeedback) 31.12 kB - -
@sentry/browser (incl. FeedbackAsync) 36.21 kB - -
@sentry/browser (incl. Metrics) 27.62 kB - -
@sentry/browser (incl. Logs) 27.75 kB - -
@sentry/browser (incl. Metrics & Logs) 28.45 kB - -
@sentry/react 28.05 kB - -
@sentry/react (incl. Tracing) 46.42 kB - -
@sentry/vue 31.18 kB - -
@sentry/vue (incl. Tracing) 46.04 kB - -
@sentry/svelte 26.34 kB - -
CDN Bundle 28.91 kB - -
CDN Bundle (incl. Tracing) 46.95 kB - -
CDN Bundle (incl. Logs, Metrics) 30.34 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 48.06 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 69.41 kB - -
CDN Bundle (incl. Tracing, Replay) 84.11 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 85.16 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 89.91 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 91.01 kB - -
CDN Bundle - uncompressed 84.72 kB - -
CDN Bundle (incl. Tracing) - uncompressed 140.31 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 88.92 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 143.77 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 212.86 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 258.11 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 261.56 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 271.81 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 275.25 kB - -
@sentry/nextjs (client) 48.92 kB - -
@sentry/sveltekit (client) 44.67 kB - -
@sentry/node-core 59.13 kB +0.02% +9 B 🔺
@sentry/node 170.57 kB +0.01% +11 B 🔺
@sentry/node - without tracing 97.17 kB +0.01% +7 B 🔺
@sentry/aws-serverless 113.99 kB +0.03% +31 B 🔺
@sentry/cloudflare (withSentry) - minified 165.2 kB - -
@sentry/cloudflare (withSentry) 417.71 kB - -

View base workflow run

@JPeer264 JPeer264 force-pushed the jp/e2e-test-memory-profiler branch 8 times, most recently from 1a0c0e3 to 55510e9 Compare April 29, 2026 09:45
@JPeer264 JPeer264 marked this pull request as ready for review April 29, 2026 11:19
Comment thread dev-packages/test-utils/src/memory-profiler.ts
Comment thread dev-packages/test-utils/src/cdp-client.ts
Comment thread dev-packages/test-utils/src/memory-profiler.ts
Comment thread dev-packages/test-utils/src/memory-profiler.ts
Comment thread dev-packages/test-utils/src/cdp-client.ts
Comment thread dev-packages/test-utils/src/cdp-client.ts Outdated
Comment thread dev-packages/test-utils/src/cdp-client.ts Outdated
Comment thread dev-packages/test-utils/src/memory-profiler.ts

private async _collectGarbage(): Promise<void> {
// Multiple GC passes to ensure full collection - some V8 inspectors need this
for (let i = 0; i < 3; i++) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why exactly 3?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are different steps in GCing. Usually one is enough, but I wanted to make sure that everything is really garbage collected and therefore only leaks are getting tested:

https://github.com/thlorenz/v8-perf/blob/eab80c8ba242b7b25a0e2a5a4845f79d181d3d4a/gc.md?plain=1#L110-L111


For that purpose, multiple rounds of work and additional tweaks to the garbage collection process may be needed since some steps (e.g. invocation of weak callbacks) are not designed to be run immediately.

(https://joyeecheung.github.io/blog/2023/12/30/fixing-nodejs-vm-apis-3/)

let totalSize = 0;

if (selfSizeIdx !== -1) {
for (let i = 0; i < snapshot.nodes.length; i += nodeFieldCount) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use a for of here as you are iterating over the nodes

Copy link
Copy Markdown
Member Author

@JPeer264 JPeer264 Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think that would work as I don't step directly over snapshot.nodes and don't increment i by one with i++ but with i += nodeFieldCount

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whoops, should have read more closely

@JPeer264 JPeer264 requested a review from s1gr1d April 29, 2026 13:55
Comment thread dev-packages/test-utils/src/memory-profiler.ts
Comment thread dev-packages/test-utils/src/memory-profiler.ts Outdated
@JPeer264 JPeer264 force-pushed the jp/e2e-test-memory-profiler branch from ba673f9 to dc1877f Compare April 30, 2026 09:17
Comment thread dev-packages/test-utils/src/memory-profiler.ts Outdated
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit dc1877f. Configure here.

Comment thread dev-packages/test-utils/src/cdp-client.ts Outdated
Copy link
Copy Markdown
Member

@chargome chargome left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a useful improvement!

Comment on lines +47 to +50
export interface HeapUsage {
usedSize: number;
totalSize: number;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: Seems to be unused?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great catch ✋ 🏈 💨

edgeGrowth,
edgeGrowthPercent: (edgeGrowth / baseline.edgeCount) * 100,
sizeGrowth,
sizeGrowthPercent: (sizeGrowth / baseline.totalSize) * 100,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: Already flagged by the clankers, but we could just do | 1?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would make sense.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed it to result in 0 instead

Comment thread dev-packages/test-utils/src/memory-profiler.ts
@JPeer264 JPeer264 merged commit ffa4a37 into develop May 4, 2026
256 checks passed
@JPeer264 JPeer264 deleted the jp/e2e-test-memory-profiler branch May 4, 2026 16:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants