import { describe, it } from 'bun:test' import assert from 'node:assert' import { check, click, fill, hover, press_key, scroll, select_option, uncheck, } from '../../src/tools/input' import { close_page, new_page } from '../../src/tools/navigation' import { evaluate_script, take_snapshot } from '../../src/tools/snapshot' import { withBrowser } from '../__helpers__/with-browser' function textOf(result: { content: { type: string; text?: string }[] }): string { return result.content .filter((c) => c.type === 'text') .map((c) => c.text) .join('\n') } function structuredOf(result: { structuredContent?: unknown }): T { assert.ok(result.structuredContent, 'Expected structuredContent') return result.structuredContent as T } function pageIdOf(result: { content: { type: string; text?: string }[] structuredContent?: unknown }): number { const data = result.structuredContent as { pageId?: number } | undefined if (typeof data?.pageId === 'number') return data.pageId return Number(textOf(result).match(/Page ID:\s*(\d+)/)?.[1]) } function escapeRegex(s: string): string { return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') } function findElementId(snapshotText: string, label: string): number { const regex = new RegExp(`\\[(\\d+)\\].*?${escapeRegex(label)}`) const match = snapshotText.match(regex) if (!match) throw new Error(`Element "${label}" not found in snapshot`) return Number.parseInt(match[1], 10) } const FORM_PAGE = `data:text/html,${encodeURIComponent(`

Test Form

Bottom of page
`)}` describe('input tools', () => { it('fill types text into an input', async () => { await withBrowser(async ({ execute }) => { const newResult = await execute(new_page, { url: FORM_PAGE }) const pageId = pageIdOf(newResult) const snap = await execute(take_snapshot, { page: pageId }) const snapText = textOf(snap) const inputId = findElementId(snapText, 'Enter name') const fillResult = await execute(fill, { page: pageId, element: inputId, text: 'John Doe', }) assert.ok(!fillResult.isError, textOf(fillResult)) const fillData = structuredOf<{ action: string; textLength: number }>( fillResult, ) assert.strictEqual(fillData.action, 'fill') assert.strictEqual(fillData.textLength, 'John Doe'.length) const val = await execute(evaluate_script, { page: pageId, expression: 'document.getElementById("name").value', }) assert.strictEqual(textOf(val), 'John Doe') await execute(close_page, { page: pageId }) }) }, 60_000) it('click triggers a button', async () => { await withBrowser(async ({ execute }) => { const newResult = await execute(new_page, { url: FORM_PAGE }) const pageId = pageIdOf(newResult) // Fill the input first const snap = await execute(take_snapshot, { page: pageId }) const snapText = textOf(snap) const inputId = findElementId(snapText, 'Enter name') await execute(fill, { page: pageId, element: inputId, text: 'Alice' }) // Click submit const btnId = findElementId(snapText, 'Submit') const clickResult = await execute(click, { page: pageId, element: btnId, }) assert.ok(!clickResult.isError, textOf(clickResult)) const clickData = structuredOf<{ action: string; element: number }>( clickResult, ) assert.strictEqual(clickData.action, 'click') assert.strictEqual(clickData.element, btnId) const output = await execute(evaluate_script, { page: pageId, expression: 'document.getElementById("output").textContent', }) assert.strictEqual(textOf(output), 'clicked:Alice') await execute(close_page, { page: pageId }) }) }, 60_000) it('check and uncheck toggle a checkbox', async () => { await withBrowser(async ({ execute }) => { const newResult = await execute(new_page, { url: FORM_PAGE }) const pageId = pageIdOf(newResult) const snap = await execute(take_snapshot, { page: pageId }) const snapText = textOf(snap) const checkboxId = findElementId(snapText, 'I agree') const checkResult = await execute(check, { page: pageId, element: checkboxId, }) assert.ok(!checkResult.isError, textOf(checkResult)) const checked = await execute(evaluate_script, { page: pageId, expression: 'document.getElementById("agree").checked', }) assert.strictEqual(textOf(checked), 'true') const uncheckResult = await execute(uncheck, { page: pageId, element: checkboxId, }) assert.ok(!uncheckResult.isError, textOf(uncheckResult)) const unchecked = await execute(evaluate_script, { page: pageId, expression: 'document.getElementById("agree").checked', }) assert.strictEqual(textOf(unchecked), 'false') await execute(close_page, { page: pageId }) }) }, 60_000) it('select_option selects a dropdown value', async () => { await withBrowser(async ({ execute }) => { const newResult = await execute(new_page, { url: FORM_PAGE }) const pageId = pageIdOf(newResult) // Use evaluate_script to get the select element's backendNodeId directly const nodeId = await execute(evaluate_script, { page: pageId, expression: '(() => { const el = document.getElementById("color"); return el ? el.getAttribute("id") : null })()', }) assert.strictEqual(textOf(nodeId), 'color') // Get the select element ID from the snapshot const snap = await execute(take_snapshot, { page: pageId }) const snapText = textOf(snap) // Find the combobox/listbox element (the