Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 33 additions & 11 deletions src/tools/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's embed it into waitForEventsAfterAction since not only clicks can trigger a popup?

await handle.asLocator().click({
Expand All @@ -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();
}
},
Expand All @@ -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);
}
},
});
Expand Down
54 changes: 53 additions & 1 deletion tests/tools/input.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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`<button onclick="window.open('about:blank', '_blank')"
>open</button
>`,
);
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', () => {
Expand Down Expand Up @@ -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`<div
style="width: 100px; height: 100px; background: red;"
onclick="window.open('about:blank', '_blank')"
></div>`,
);
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', () => {
Expand Down
Loading