Skip to content

Commit 3010e87

Browse files
authored
Merge branch 'main' into mcp-dialog-pt3
2 parents f4622fc + f1afe84 commit 3010e87

7 files changed

Lines changed: 346 additions & 2 deletions

File tree

src/telemetry/ClearcutLogger.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,25 @@ export function transformArgType(zodType: ZodType): string {
9090
}
9191
}
9292

93+
const BUCKETS = [
94+
0, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000,
95+
];
96+
97+
function bucketize(value: number): number {
98+
for (const bucket of BUCKETS) {
99+
if (bucket >= value) {
100+
return bucket;
101+
}
102+
}
103+
return BUCKETS[BUCKETS.length - 1];
104+
}
105+
93106
function transformValue(
94107
zodType: ZodType,
95108
value: unknown,
96109
): LoggedToolCallArgValue {
97110
if (zodType === 'ZodString') {
98-
return (value as string).length;
111+
return bucketize((value as string).length);
99112
} else if (zodType === 'ZodArray') {
100113
return (value as unknown[]).length;
101114
} else {

tests/telemetry/ClearcutLogger.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,35 @@ describe('ClearcutLogger', () => {
235235
});
236236
});
237237

238+
it('bucketizes string lengths correctly', () => {
239+
const schema = {
240+
str0: zod.string(),
241+
str1: zod.string(),
242+
str3: zod.string(),
243+
str5: zod.string(),
244+
str10000: zod.string(),
245+
str10001: zod.string(),
246+
};
247+
248+
const params = {
249+
str0: '',
250+
str1: 'a',
251+
str3: 'abc',
252+
str5: 'abcde',
253+
str10000: 'a'.repeat(10000),
254+
str10001: 'a'.repeat(10001),
255+
};
256+
257+
const sanitized = sanitizeParams(params, schema);
258+
259+
assert.strictEqual(sanitized.str0_length, 0);
260+
assert.strictEqual(sanitized.str1_length, 1);
261+
assert.strictEqual(sanitized.str3_length, 5); // snaps to 5
262+
assert.strictEqual(sanitized.str5_length, 5);
263+
assert.strictEqual(sanitized.str10000_length, 10000);
264+
assert.strictEqual(sanitized.str10001_length, 10000); // snaps to 10000
265+
});
266+
238267
it('throws error for unsupported types', () => {
239268
const schema = {
240269
myObj: zod.object({foo: zod.string()}),

tests/tools/console.test.js.snapshot

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,47 @@ Learn more:
118118
reqid=<reqid> data={"corsErrorStatus":{"corsError":"PreflightMissingAllowOriginHeader","failedParameter":""},"isWarning":false,"request":{"url":"http://hostname:port/data.json"},"initiatorOrigin":"","clientSecurityState":{"initiatorIsSecureContext":false,"initiatorIPAddressSpace":"Loopback","localNetworkAccessRequestPolicy":"BlockFromInsecureToMorePrivate"}}
119119
`;
120120

121+
exports[`console > get_console_message > when dialog is open 1`] = `
122+
{
123+
"dialog": {
124+
"type": "alert",
125+
"message": "test dialog",
126+
"defaultValue": ""
127+
},
128+
"consoleMessage": {
129+
"id": 1,
130+
"type": "error",
131+
"text": "This is an error",
132+
"argsCount": 1,
133+
"args": [
134+
"This is an error"
135+
],
136+
"stackTrace": "at (VM7:1:9)\\nat (pptr:;CdpFrame.%3Canonymous%3E%20(<file-path>)\\n--- PendingScript ----------------------\\nat (pptr:;CdpFrame.%3Canonymous%3E%20(<file-path>)\\nNote: line and column numbers use 1-based indexing"
137+
},
138+
"pagination": {
139+
"currentPage": 0,
140+
"totalPages": 1,
141+
"hasNextPage": false,
142+
"hasPreviousPage": false,
143+
"startIndex": 0,
144+
"endIndex": 1,
145+
"invalidPage": false
146+
},
147+
"consoleMessages": [
148+
{
149+
"type": "error",
150+
"text": "This is an error",
151+
"argsCount": 1,
152+
"id": 1
153+
}
154+
]
155+
}
156+
`;
157+
158+
exports[`console > list_console_messages > issues > when dialog is open 1`] = `
159+
{"content":[{"type":"text","text":"# Open dialog\\nalert: test dialog.\\nCall handle_dialog to handle it before continuing.\\n## Console messages\\nShowing 1-1 of 1 (Page 1 of 1).\\nmsgid=1 [log] Pre-dialog message (1 args)"}],"structuredContent":{"dialog":{"type":"alert","message":"test dialog","defaultValue":""},"pagination":{"currentPage":0,"totalPages":1,"hasNextPage":false,"hasPreviousPage":false,"startIndex":0,"endIndex":1,"invalidPage":false},"consoleMessages":[{"type":"log","text":"Pre-dialog message","argsCount":1,"id":1}]}}
160+
`;
161+
121162
exports[`console > list_console_messages > lists error objects 1`] = `
122163
## Console messages
123164
Showing 1-1 of 1 (Page 1 of 1).

tests/tools/console.test.ts

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import assert from 'node:assert';
88
import {before, describe, it} from 'node:test';
99

10+
import type {Dialog} from 'puppeteer-core';
11+
1012
import type {ParsedArguments} from '../../src/bin/chrome-devtools-mcp-cli-options.js';
1113
import {loadIssueDescriptions} from '../../src/issue-descriptions.js';
1214
import {McpResponse} from '../../src/McpResponse.js';
@@ -17,7 +19,11 @@ import {
1719
listConsoleMessages,
1820
} from '../../src/tools/console.js';
1921
import {serverHooks} from '../server.js';
20-
import {getTextContent, withMcpContext} from '../utils.js';
22+
import {
23+
getTextContent,
24+
withMcpContext,
25+
stabilizeStructuredContent,
26+
} from '../utils.js';
2127

2228
describe('console', () => {
2329
before(async () => {
@@ -162,6 +168,37 @@ describe('console', () => {
162168
}
163169
});
164170
});
171+
172+
it('when dialog is open', async t => {
173+
await withMcpContext(async (response, context) => {
174+
const page = context.getSelectedPptrPage();
175+
await page.setContent(
176+
'<script>console.log("Pre-dialog message")</script>',
177+
);
178+
179+
const dialogPromise = new Promise<Dialog>(resolve => {
180+
page.on('dialog', dialog => resolve(dialog));
181+
});
182+
183+
page.evaluate(() => {
184+
alert('test dialog');
185+
});
186+
const dialog = await dialogPromise;
187+
188+
await listConsoleMessages().handler(
189+
{params: {}, page: context.getSelectedMcpPage()},
190+
response,
191+
context,
192+
);
193+
194+
const result = await response.handle(
195+
'list_console_messages',
196+
context,
197+
);
198+
t.assert.snapshot?.(JSON.stringify(result));
199+
await dialog.dismiss();
200+
});
201+
});
165202
});
166203
});
167204

@@ -474,5 +511,44 @@ describe('console', () => {
474511
t.assert.snapshot?.(rawText);
475512
});
476513
});
514+
515+
it('when dialog is open', async t => {
516+
await withMcpContext(async (response, context) => {
517+
const page = context.getSelectedPptrPage();
518+
await page.setContent(
519+
'<script>console.error("This is an error")</script>',
520+
);
521+
522+
await listConsoleMessages().handler(
523+
{params: {}, page: context.getSelectedMcpPage()},
524+
response,
525+
context,
526+
);
527+
528+
const dialogPromise = new Promise<Dialog>(resolve => {
529+
page.on('dialog', dialog => resolve(dialog));
530+
});
531+
page.evaluate(() => {
532+
alert('test dialog');
533+
});
534+
const dialog = await dialogPromise;
535+
536+
await getConsoleMessage.handler(
537+
{params: {msgid: 1}, page: context.getSelectedMcpPage()},
538+
response,
539+
context,
540+
);
541+
542+
const result = await response.handle('get_console_message', context);
543+
t.assert.snapshot?.(
544+
JSON.stringify(
545+
stabilizeStructuredContent(result.structuredContent),
546+
null,
547+
2,
548+
),
549+
);
550+
await dialog.dismiss();
551+
});
552+
});
477553
});
478554
});

tests/tools/pages.test.js.snapshot

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
exports[`pages > close_page > when dialog is open 1`] = `
2+
{"content":[{"type":"text","text":"## Pages\\n1: about:blank [selected]"}],"structuredContent":{"pages":[{"id":1,"url":"about:blank","selected":true}]}}
3+
`;
4+
15
exports[`pages > list_pages > list pages for extension pages with --category-extensions 1`] = `
26
## Pages
37
1: about:blank [selected]
@@ -25,3 +29,23 @@ exports[`pages > list_pages > list pages for side panels with --category-extensi
2529
## Extension Service Workers
2630
sw-1: chrome-extension://<extension-id>/sw.js
2731
`;
32+
33+
exports[`pages > list_pages > when dialog is open 1`] = `
34+
{"content":[{"type":"text","text":"# Open dialog\\nalert: test dialog.\\nCall handle_dialog to handle it before continuing.\\n## Pages\\n1: about:blank [selected]"}],"structuredContent":{"dialog":{"type":"alert","message":"test dialog","defaultValue":""},"pages":[{"id":1,"url":"about:blank","selected":true}]}}
35+
`;
36+
37+
exports[`pages > navigate_page > when dialog is open 1`] = `
38+
{"content":[{"type":"text","text":"Successfully navigated to data:text/html,<div>Navigated</div>.\\n# Open dialog\\nalert: test dialog.\\nCall handle_dialog to handle it before continuing.\\n## Pages\\n1: data:text/html,<div>Navigated</div> [selected]"}],"structuredContent":{"message":"Successfully navigated to data:text/html,<div>Navigated</div>.","dialog":{"type":"alert","message":"test dialog","defaultValue":""},"pages":[{"id":1,"url":"data:text/html,<div>Navigated</div>","selected":true}]}}
39+
`;
40+
41+
exports[`pages > new_page with isolatedContext > when dialog is open 1`] = `
42+
{"content":[{"type":"text","text":"# Open dialog\\nalert: test dialog.\\nCall handle_dialog to handle it before continuing.\\n## Pages\\n1: about:blank\\n2: about:blank [selected]"}],"structuredContent":{"dialog":{"type":"alert","message":"test dialog","defaultValue":""},"pages":[{"id":1,"url":"about:blank","selected":false},{"id":2,"url":"about:blank","selected":true}]}}
43+
`;
44+
45+
exports[`pages > resize > when dialog is open 1`] = `
46+
{"content":[{"type":"text","text":"# Open dialog\\nalert: test dialog.\\nCall handle_dialog to handle it before continuing.\\n## Pages\\n1: about:blank [selected]"}],"structuredContent":{"dialog":{"type":"alert","message":"test dialog","defaultValue":""},"pages":[{"id":1,"url":"about:blank","selected":true}]}}
47+
`;
48+
49+
exports[`pages > select_page > when dialog is open 1`] = `
50+
{"content":[{"type":"text","text":"# Open dialog\\nalert: test dialog.\\nCall handle_dialog to handle it before continuing.\\n## Pages\\n1: about:blank [selected]"}],"structuredContent":{"dialog":{"type":"alert","message":"test dialog","defaultValue":""},"pages":[{"id":1,"url":"about:blank","selected":true}]}}
51+
`;

0 commit comments

Comments
 (0)