mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-13 00:14:15 +00:00
fix(browser): handle DevTools close endpoint response
This commit is contained in:
1 parent
23c819cabc
commit
92252189b1
3 files changed
+59
-2
No files matched your search
@@ -1230,11 +1230,16 @@ function getTools() {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchJson(url, options = undefined) {
|
async function fetchOk(url, options = undefined) {
|
||||||
const response = await fetch(url, options);
|
const response = await fetch(url, options);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP ${response.status} for ${url}`);
|
throw new Error(`HTTP ${response.status} for ${url}`);
|
||||||
}
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchJson(url, options = undefined) {
|
||||||
|
const response = await fetchOk(url, options);
|
||||||
return await response.json();
|
return await response.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5193,7 +5198,7 @@ async function handleClosePage(toolArgs) {
|
|||||||
activeRecordingSession = null;
|
activeRecordingSession = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
await fetchJson(`${getHttpUrl()}/json/close/${encodeURIComponent(page.id)}`);
|
await fetchOk(`${getHttpUrl()}/json/close/${encodeURIComponent(page.id)}`, { method: 'PUT' });
|
||||||
const interceptSession = interceptSessionsByPageId.get(page.id);
|
const interceptSession = interceptSessionsByPageId.get(page.id);
|
||||||
if (interceptSession) {
|
if (interceptSession) {
|
||||||
closeSocket(interceptSession.ws);
|
closeSocket(interceptSession.ws);
|
||||||
|
|||||||
@@ -433,6 +433,45 @@ describe('ccs-browser MCP server - session and interception', () => {
|
|||||||
expect(listText).not.toContain('Docs');
|
expect(listText).not.toContain('Docs');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('closes a page when Chrome DevTools requires PUT and returns text', async () => {
|
||||||
|
const responses = await runMcpRequests(
|
||||||
|
[
|
||||||
|
{ id: 'page-1', title: 'Home', currentUrl: 'https://example.com/' },
|
||||||
|
{ id: 'page-2', title: 'Docs', currentUrl: 'https://example.com/docs' },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
id: 8331,
|
||||||
|
method: 'tools/call',
|
||||||
|
params: { name: 'browser_select_page', arguments: { pageIndex: 1 } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
id: 8332,
|
||||||
|
method: 'tools/call',
|
||||||
|
params: { name: 'browser_close_page', arguments: {} },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
id: 8333,
|
||||||
|
method: 'tools/call',
|
||||||
|
params: { name: 'browser_get_session_info', arguments: {} },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{ requirePutForClosePage: true, closePageRespondsWithText: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const closeText = getResponseText(responses.find((message) => message.id === 8332));
|
||||||
|
expect(closeText).toContain('status: closed');
|
||||||
|
expect(closeText).toContain('selectedPageId: page-1');
|
||||||
|
|
||||||
|
const listText = getResponseText(responses.find((message) => message.id === 8333));
|
||||||
|
expect(listText).toContain('0. Home');
|
||||||
|
expect(listText).toContain('selected: true');
|
||||||
|
expect(listText).not.toContain('Docs');
|
||||||
|
});
|
||||||
|
|
||||||
it('keeps the selected page when closing a different page', async () => {
|
it('keeps the selected page when closing a different page', async () => {
|
||||||
const responses = await runMcpRequests(
|
const responses = await runMcpRequests(
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -350,6 +350,8 @@ type RunMcpRequestsOptions = {
|
|||||||
childEnv?: NodeJS.ProcessEnv;
|
childEnv?: NodeJS.ProcessEnv;
|
||||||
responseTimeoutMs?: number;
|
responseTimeoutMs?: number;
|
||||||
requirePutForNewPage?: boolean;
|
requirePutForNewPage?: boolean;
|
||||||
|
requirePutForClosePage?: boolean;
|
||||||
|
closePageRespondsWithText?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
function encodeMessage(message: unknown): string {
|
function encodeMessage(message: unknown): string {
|
||||||
@@ -746,6 +748,12 @@ function createMockBrowser(pagesInput: MockPageState[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (req.url?.startsWith('/json/close/')) {
|
if (req.url?.startsWith('/json/close/')) {
|
||||||
|
if (options.requirePutForClosePage && req.method !== 'PUT') {
|
||||||
|
res.writeHead(405, { 'Content-Type': 'application/json' });
|
||||||
|
res.end(JSON.stringify({ error: 'method not allowed' }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const targetId = decodeURIComponent(req.url.slice('/json/close/'.length));
|
const targetId = decodeURIComponent(req.url.slice('/json/close/'.length));
|
||||||
const entry = Array.from(pageStates.entries()).find(([, page]) => page.id === targetId);
|
const entry = Array.from(pageStates.entries()).find(([, page]) => page.id === targetId);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
@@ -754,6 +762,11 @@ function createMockBrowser(pagesInput: MockPageState[]) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pageStates.delete(entry[0]);
|
pageStates.delete(entry[0]);
|
||||||
|
if (options.closePageRespondsWithText) {
|
||||||
|
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
||||||
|
res.end('Target is closing');
|
||||||
|
return;
|
||||||
|
}
|
||||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||||
res.end(JSON.stringify({ id: targetId }));
|
res.end(JSON.stringify({ id: targetId }));
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in new issue
Block a user