mirror of
https://github.com/ChromeDevTools/chrome-devtools-mcp.git
synced 2026-11-04 05:02:31 +00:00
fix: resolve service worker IDs for console messages (#2881)
## Summary - Fix `list_console_messages` to accept the `sw-N` service worker IDs returned by `list_pages`. Resolve the service worker in `McpContext.getServiceWorkerConsoleData` and use its extension ID to retrieve console messages. - Reject raw extension IDs, unknown IDs, and IDs for dedicated or shared workers with `Service worker not found.`. - Update the parameter documentation and generated CLI options to describe the supported ID format. Fixes #2846. ## Testing - `npm run test -- tests/McpResponse.test.ts tests/tools/console.test.ts` (with local Chrome): passed. - `npm run check-format`: passed. - `npm run test` (with local Chrome): one large full-page screenshot test failed with `Page.captureScreenshot: Page is too large`; the same test fails on a clean checkout of base `45c1c6c` with the same Chrome. All other tests passed. Note: #2800 is refactoring worker IDs; this patch is based on current `main` and can be rebased if needed. Co-authored-by: guolisha <guolisha@kylinos.cn>
This commit is contained in:
1 parent
3ea31fbab1
commit
3804a9ad52
6 files changed
+97
-5
No files matched your search
@@ -449,7 +449,7 @@ Results are paginated (10 rules per page by default); use pageIdx to page throug
|
||||
- **includeStackTraces** (boolean) _(optional)_: Set to true to include the stack trace for each message when available. Increases the response size.
|
||||
- **pageIdx** (integer) _(optional)_: Page number to return (0-based). When omitted, returns the first page.
|
||||
- **pageSize** (integer) _(optional)_: Maximum number of messages to return. When omitted, returns all messages.
|
||||
- **serviceWorkerId** (string) _(optional)_: Filter messages to only return messages of the specified service worker.
|
||||
- **serviceWorkerId** (string) _(optional)_: Filter messages by the service worker ID shown by [`list_pages`](#list_pages) (sw-N).
|
||||
- **types** (array) _(optional)_: Filter messages to only return messages of the specified resource types. When omitted or empty, returns all messages.
|
||||
|
||||
---
|
||||
|
||||
+6
-1
@@ -638,8 +638,13 @@ export class McpContext implements Context, BrowserlessContext {
|
||||
}
|
||||
|
||||
getServiceWorkerConsoleData(
|
||||
extensionId: string,
|
||||
serviceWorkerId: string,
|
||||
): Array<ConsoleMessage | UncaughtError> {
|
||||
const worker = this.getWorkerById(serviceWorkerId);
|
||||
if (worker?.type !== 'service_worker') {
|
||||
throw new Error('Service worker not found.');
|
||||
}
|
||||
const extensionId = new URL(worker.url).hostname;
|
||||
return this.#serviceWorkerConsoleCollector?.getData(extensionId) ?? [];
|
||||
}
|
||||
|
||||
|
||||
@@ -1308,7 +1308,7 @@ export const commands: Commands = {
|
||||
name: 'serviceWorkerId',
|
||||
type: 'string',
|
||||
description:
|
||||
'Filter messages to only return messages of the specified service worker.',
|
||||
'Filter messages by the service worker ID shown by list_pages (sw-N).',
|
||||
required: false,
|
||||
positional: false,
|
||||
},
|
||||
|
||||
@@ -90,7 +90,7 @@ export const listConsoleMessages = definePageTool(
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
'Filter messages to only return messages of the specified service worker.',
|
||||
'Filter messages by the service worker ID shown by list_pages (sw-N).',
|
||||
),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
|
||||
@@ -14,6 +14,8 @@ import {pathToFileURL} from 'node:url';
|
||||
import {Locator} from 'puppeteer';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import {UncaughtError} from '../src/collectors/PageCollector.js';
|
||||
import {ServiceWorkerConsoleCollector} from '../src/collectors/ServiceWorkerCollector.js';
|
||||
import {NetworkFormatter} from '../src/formatters/NetworkFormatter.js';
|
||||
import {McpContext} from '../src/McpContext.js';
|
||||
import {McpPage} from '../src/McpPage.js';
|
||||
@@ -27,8 +29,10 @@ import {
|
||||
} from '../src/third_party/index.js';
|
||||
import type {TraceResult} from '../src/processors/PerformanceTrace.js';
|
||||
import {resolveCanonicalPath} from '../src/utils/files.js';
|
||||
import {stableIdSymbol} from '../src/utils/id.js';
|
||||
|
||||
import {
|
||||
createMockMcpWorker,
|
||||
createMockPuppeteerBrowser,
|
||||
createMockPuppeteerPage,
|
||||
createMockPuppeteerTarget,
|
||||
@@ -88,6 +92,89 @@ describe('McpContext', () => {
|
||||
);
|
||||
}
|
||||
|
||||
describe('getServiceWorkerConsoleData', () => {
|
||||
it('resolves the service worker ID to the collector extension ID', async () => {
|
||||
const browser = createMockPuppeteerBrowser();
|
||||
browser.targets.returns([]);
|
||||
const context = await createConnectedMcpContext(
|
||||
browser,
|
||||
{
|
||||
experimentalDevToolsDebugging: false,
|
||||
performanceCrux: false,
|
||||
heapSnapshotManager: new HeapSnapshotManager(),
|
||||
},
|
||||
Locator,
|
||||
);
|
||||
const worker = createMockMcpWorker({
|
||||
id: 'sw-3',
|
||||
url: 'chrome-extension://extension-id/background.js',
|
||||
});
|
||||
const getWorkerById = sinon
|
||||
.stub(context, 'getWorkerById')
|
||||
.returns(worker);
|
||||
const messages = [
|
||||
Object.assign(
|
||||
new UncaughtError(
|
||||
{
|
||||
exceptionId: 1,
|
||||
text: 'Service worker error',
|
||||
lineNumber: 0,
|
||||
columnNumber: 0,
|
||||
},
|
||||
'extension-id',
|
||||
),
|
||||
{[stableIdSymbol]: 1},
|
||||
),
|
||||
];
|
||||
const getData = sinon
|
||||
.stub(ServiceWorkerConsoleCollector.prototype, 'getData')
|
||||
.returns(messages);
|
||||
|
||||
const result = context.getServiceWorkerConsoleData('sw-3');
|
||||
|
||||
sinon.assert.calledOnceWithExactly(getWorkerById, 'sw-3');
|
||||
sinon.assert.calledOnceWithExactly(getData, 'extension-id');
|
||||
assert.strictEqual(result, messages);
|
||||
context.dispose();
|
||||
});
|
||||
|
||||
for (const serviceWorkerId of ['sw-404', 'extension-id', 'dw-1', 'shw-2']) {
|
||||
it(`rejects ${serviceWorkerId} without reading console data`, async () => {
|
||||
const browser = createMockPuppeteerBrowser();
|
||||
browser.targets.returns([]);
|
||||
const context = await createConnectedMcpContext(
|
||||
browser,
|
||||
{
|
||||
experimentalDevToolsDebugging: false,
|
||||
performanceCrux: false,
|
||||
heapSnapshotManager: new HeapSnapshotManager(),
|
||||
},
|
||||
Locator,
|
||||
);
|
||||
const getWorkerById = sinon.stub(context, 'getWorkerById');
|
||||
getWorkerById
|
||||
.withArgs('dw-1')
|
||||
.returns(createMockMcpWorker({id: 'dw-1', type: 'dedicated_worker'}));
|
||||
getWorkerById
|
||||
.withArgs('shw-2')
|
||||
.returns(createMockMcpWorker({id: 'shw-2', type: 'shared_worker'}));
|
||||
const getData = sinon.stub(
|
||||
ServiceWorkerConsoleCollector.prototype,
|
||||
'getData',
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
() => context.getServiceWorkerConsoleData(serviceWorkerId),
|
||||
/Service worker not found\./,
|
||||
);
|
||||
|
||||
sinon.assert.calledOnceWithExactly(getWorkerById, serviceWorkerId);
|
||||
sinon.assert.notCalled(getData);
|
||||
context.dispose();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('list pages', async () => {
|
||||
await withMcpContext(async (_response, context) => {
|
||||
const page = context.getSelectedMcpPage();
|
||||
|
||||
@@ -100,7 +100,7 @@ describe('console', () => {
|
||||
|
||||
await listConsoleMessages(args).handler(
|
||||
{
|
||||
params: {serviceWorkerId: extensionId},
|
||||
params: {serviceWorkerId: sw.id},
|
||||
page: context.getSelectedMcpPage(),
|
||||
},
|
||||
response2,
|
||||
|
||||
Reference in new issue
Block a user