diff --git a/src/tools/input.ts b/src/tools/input.ts index cd8b2f4d0..b4ed3729c 100644 --- a/src/tools/input.ts +++ b/src/tools/input.ts @@ -52,6 +52,12 @@ export const click = defineTool({ handler: async (request, response, context) => { const uid = request.params.uid; const handle = await context.getElementByUid(uid); + const page = context.getSelectedPage(); + let popupOpened = false; + const popupListener = () => { + popupOpened = true; + }; + page.on('popup', popupListener); try { await context.waitForEventsAfterAction(async () => { await handle.asLocator().click({ @@ -63,12 +69,16 @@ export const click = defineTool({ ? `Successfully double clicked on the element` : `Successfully clicked on the element`, ); + if (popupOpened) { + response.setIncludePages(true); + } if (request.params.includeSnapshot) { response.includeSnapshot(); } } catch (error) { handleActionError(error, uid); } finally { + page.off('popup', popupListener); void handle.dispose(); } }, @@ -90,18 +100,30 @@ export const clickAt = defineTool({ }, handler: async (request, response, context) => { const page = context.getSelectedPage(); - await context.waitForEventsAfterAction(async () => { - await page.mouse.click(request.params.x, request.params.y, { - clickCount: request.params.dblClick ? 2 : 1, + let popupOpened = false; + const popupListener = () => { + popupOpened = true; + }; + page.on('popup', popupListener); + try { + await context.waitForEventsAfterAction(async () => { + await page.mouse.click(request.params.x, request.params.y, { + clickCount: request.params.dblClick ? 2 : 1, + }); }); - }); - response.appendResponseLine( - request.params.dblClick - ? `Successfully double clicked at the coordinates` - : `Successfully clicked at the coordinates`, - ); - if (request.params.includeSnapshot) { - response.includeSnapshot(); + response.appendResponseLine( + request.params.dblClick + ? `Successfully double clicked at the coordinates` + : `Successfully clicked at the coordinates`, + ); + if (popupOpened) { + response.setIncludePages(true); + } + if (request.params.includeSnapshot) { + response.includeSnapshot(); + } + } finally { + page.off('popup', popupListener); } }, }); diff --git a/tests/tools/input.test.ts b/tests/tools/input.test.ts index 06a752148..58995e7c0 100644 --- a/tests/tools/input.test.ts +++ b/tests/tools/input.test.ts @@ -22,7 +22,7 @@ import { } from '../../src/tools/input.js'; import {parseKey} from '../../src/utils/keyboard.js'; import {serverHooks} from '../server.js'; -import {html, withMcpContext} from '../utils.js'; +import {getTextContent, html, withMcpContext} from '../utils.js'; describe('input', () => { const server = serverHooks(); @@ -205,6 +205,31 @@ describe('input', () => { assert.notStrictEqual(response.snapshotParams, undefined); }); }); + + it('includes pages if click opens a new tab', async () => { + await withMcpContext(async (response, context) => { + const page = context.getSelectedPage(); + await page.setContent( + html``, + ); + await context.createTextSnapshot(); + await click.handler( + { + params: { + uid: '1_1', + }, + }, + response, + context, + ); + assert.ok(response.includePages); + const formattedResponse = await response.handle('test', context); + const textContent = getTextContent(formattedResponse.content[0]); + assert.ok(textContent.includes('## Pages')); + }); + }); }); describe('hover', () => { @@ -293,6 +318,33 @@ describe('input', () => { assert.ok(await page.$('text/dblclicked')); }); }); + + it('includes pages if click at coordinates opens a new tab', async () => { + await withMcpContext(async (response, context) => { + const page = context.getSelectedPage(); + await page.setContent( + html`
`, + ); + await context.createTextSnapshot(); + await clickAt.handler( + { + params: { + x: 50, + y: 50, + }, + }, + response, + context, + ); + assert.ok(response.includePages); + const formattedResponse = await response.handle('test', context); + const textContent = getTextContent(formattedResponse.content[0]); + assert.ok(textContent.includes('## Pages')); + }); + }); }); describe('fill', () => {