diff --git a/src/tools/screenshot.ts b/src/tools/screenshot.ts index 03e75f9..46001ec 100644 --- a/src/tools/screenshot.ts +++ b/src/tools/screenshot.ts @@ -114,7 +114,7 @@ export const drag: Tool = { const typeSchema = z.object({ text: z.string().describe('Text to type into the element'), - submit: z.boolean().describe('Whether to submit entered text (press Enter after)'), + submit: z.boolean().optional().describe('Whether to submit entered text (press Enter after)'), }); export const type: Tool = { diff --git a/src/tools/snapshot.ts b/src/tools/snapshot.ts index b0b9e12..4646dce 100644 --- a/src/tools/snapshot.ts +++ b/src/tools/snapshot.ts @@ -101,7 +101,8 @@ export const hover: Tool = { const typeSchema = elementSchema.extend({ text: z.string().describe('Text to type into the element'), - submit: z.boolean().describe('Whether to submit entered text (press Enter after)'), + submit: z.boolean().optional().describe('Whether to submit entered text (press Enter after)'), + slowly: z.boolean().optional().describe('Wether to type one character at a time. Useful for triggering key handlers in the page. By default entire text is filled in at once.'), }); export const type: Tool = { @@ -115,7 +116,10 @@ export const type: Tool = { const validatedParams = typeSchema.parse(params); return await context.runAndWaitWithSnapshot(async () => { const locator = context.lastSnapshot().refLocator(validatedParams.ref); - await locator.fill(validatedParams.text); + if (validatedParams.slowly) + await locator.pressSequentially(validatedParams.text); + else + await locator.fill(validatedParams.text); if (validatedParams.submit) await locator.press('Enter'); }, { diff --git a/tests/basic.spec.ts b/tests/basic.spec.ts index 663a583..b138ed1 100644 --- a/tests/basic.spec.ts +++ b/tests/basic.spec.ts @@ -368,3 +368,61 @@ test('executable path', async ({ startClient }) => { }); expect(response).toContainTextContent(`executable doesn't exist`); }); + +test('fill in text', async ({ client }) => { + await client.callTool({ + name: 'browser_navigate', + arguments: { + url: `data:text/html,`, + }, + }); + await client.callTool({ + name: 'browser_type', + arguments: { + element: 'textbox', + ref: 's1e3', + text: 'Hi!', + submit: true, + }, + }); + const resource = await client.readResource({ + uri: 'browser://console', + }); + expect(resource.contents).toEqual([{ + uri: 'browser://console', + mimeType: 'text/plain', + text: '[LOG] Key pressed: Enter , Text: Hi!', + }]); +}); + +test('type slowly', async ({ client }) => { + await client.callTool({ + name: 'browser_navigate', + arguments: { + url: `data:text/html,`, + }, + }); + await client.callTool({ + name: 'browser_type', + arguments: { + element: 'textbox', + ref: 's1e3', + text: 'Hi!', + submit: true, + slowly: true, + }, + }); + const resource = await client.readResource({ + uri: 'browser://console', + }); + expect(resource.contents).toEqual([{ + uri: 'browser://console', + mimeType: 'text/plain', + text: [ + '[LOG] Key pressed: H Text: ', + '[LOG] Key pressed: i Text: H', + '[LOG] Key pressed: ! Text: Hi', + '[LOG] Key pressed: Enter Text: Hi!', + ].join('\n'), + }]); +});