mirror of
https://github.com/ChromeDevTools/chrome-devtools-mcp.git
synced 2026-09-28 11:22:57 +08:00
fix: bound ConsoleCollector retention per navigation (#2773)
## Summary `ConsoleCollector` calls `super(page, listeners)` without passing a `maxResourcesPerNavigation` value, so the per-navigation trim that `PageCollector` already implements never runs for console messages. A long-lived page (or an SPA that does not navigate) can therefore accumulate unbounded console entries in a single navigation bucket. `NetworkCollector` already passes `MAX_REQUESTS_PER_NAVIGATION = 1_000` and `ServiceWorkerConsoleCollector` caps its own buffer at 1 000 entries. This change applies the same bound to `ConsoleCollector`. ## Changes **`src/collectors/PageCollector.ts`** - Add `static readonly MAX_MESSAGES_PER_NAVIGATION = 1_000` to `ConsoleCollector`. - Accept an optional `maxMessagesPerNavigation` constructor parameter (defaults to the constant) and forward it to `PageCollector`. **`tests/collectors/PageCollector.test.ts`** - Add a test that emits more messages than a custom cap and asserts only the newest are retained. - Add a test that emits more messages than the default cap and asserts the retained count equals `MAX_MESSAGES_PER_NAVIGATION`. ## Verification ``` npm run typecheck # no errors npm run build # clean npm run test:no-build -- tests/collectors/PageCollector.test.ts # 22 tests pass (20 existing + 2 new) ``` Fixes #2768 --------- Co-authored-by: Alex Rudenko <OrKoN@users.noreply.github.com> Co-authored-by: Nicholas Roscino <nroscino@google.com>
This commit is contained in:
co-authored by
Alex Rudenko
Nicholas Roscino
parent
b10be8ebeb
commit
e98a3ca404
@@ -196,6 +196,8 @@ export class PageCollector<T> {
|
||||
export class ConsoleCollector extends PageCollector<
|
||||
ConsoleMessage | Error | DevTools.AggregatedIssue | UncaughtError
|
||||
> {
|
||||
static readonly MAX_MESSAGES_PER_NAVIGATION = 10_000;
|
||||
|
||||
#subscriber?: PageEventSubscriber;
|
||||
|
||||
constructor(
|
||||
@@ -205,8 +207,9 @@ export class ConsoleCollector extends PageCollector<
|
||||
item: ConsoleMessage | Error | DevTools.AggregatedIssue | UncaughtError,
|
||||
) => void,
|
||||
) => ListenerMap<PageEvents>,
|
||||
maxMessagesPerNavigation = ConsoleCollector.MAX_MESSAGES_PER_NAVIGATION,
|
||||
) {
|
||||
super(page, listeners);
|
||||
super(page, listeners, maxMessagesPerNavigation);
|
||||
this.#subscriber = new PageEventSubscriber(this.pptrPage);
|
||||
this.#subscriber.subscribe();
|
||||
}
|
||||
|
||||
@@ -7,7 +7,12 @@
|
||||
import assert from 'node:assert';
|
||||
import {afterEach, beforeEach, describe, it} from 'node:test';
|
||||
|
||||
import type {Frame, HTTPRequest, Protocol} from 'puppeteer-core';
|
||||
import type {
|
||||
ConsoleMessage,
|
||||
Frame,
|
||||
HTTPRequest,
|
||||
Protocol,
|
||||
} from 'puppeteer-core';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import type {ListenerMap} from '../../src/collectors/PageCollector.js';
|
||||
@@ -20,6 +25,14 @@ import {DevTools, FrameEvent} from '../../src/third_party/index.js';
|
||||
|
||||
import {getMockRequest, getMockBrowser} from '../utils.js';
|
||||
|
||||
function createMockConsoleMessage(text: string): ConsoleMessage {
|
||||
return {
|
||||
type: () => 'log',
|
||||
text: () => text,
|
||||
args: () => [],
|
||||
} as unknown as ConsoleMessage;
|
||||
}
|
||||
|
||||
describe('PageCollector', () => {
|
||||
it('works', async () => {
|
||||
const browser = getMockBrowser();
|
||||
@@ -531,4 +544,59 @@ describe('ConsoleCollector', () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('retains only the newest messages per navigation', async () => {
|
||||
const browser = getMockBrowser();
|
||||
const page = (await browser.pages())[0];
|
||||
const cap = 5;
|
||||
const collector = new ConsoleCollector(
|
||||
page,
|
||||
collect => {
|
||||
return {
|
||||
console: (msg: ConsoleMessage) => {
|
||||
collect(msg);
|
||||
},
|
||||
} as ListenerMap;
|
||||
},
|
||||
cap,
|
||||
);
|
||||
|
||||
const messages = Array.from({length: cap + 3}, (_, i) =>
|
||||
createMockConsoleMessage(`msg-${i}`),
|
||||
);
|
||||
|
||||
for (const msg of messages) {
|
||||
page.emit('console', msg);
|
||||
}
|
||||
|
||||
const retained = collector.getData();
|
||||
assert.equal(retained.length, cap);
|
||||
assert.deepEqual(retained, messages.slice(messages.length - cap));
|
||||
});
|
||||
|
||||
it('uses MAX_MESSAGES_PER_NAVIGATION as the default cap', async () => {
|
||||
const browser = getMockBrowser();
|
||||
const page = (await browser.pages())[0];
|
||||
const collector = new ConsoleCollector(page, collect => {
|
||||
return {
|
||||
console: (msg: ConsoleMessage) => {
|
||||
collect(msg);
|
||||
},
|
||||
} as ListenerMap;
|
||||
});
|
||||
|
||||
const messages = Array.from(
|
||||
{length: ConsoleCollector.MAX_MESSAGES_PER_NAVIGATION + 1},
|
||||
(_, i) => createMockConsoleMessage(`msg-${i}`),
|
||||
);
|
||||
|
||||
for (const msg of messages) {
|
||||
page.emit('console', msg);
|
||||
}
|
||||
|
||||
assert.equal(
|
||||
collector.getData().length,
|
||||
ConsoleCollector.MAX_MESSAGES_PER_NAVIGATION,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user