Files
fn_registry/functions/browser/cdp_fill.md
T
Egutierrez 4187f9b6b1 feat(browser): actionability + dropdowns + fill + role locator (estilo Playwright)
Tras estudiar el código de Playwright (sources/playwright), 4 primitivas nuevas y
1 endurecida para que la interacción web sea fiable:

- cdp_wait_actionable: visible + stable (2 rAF) + enabled + hit-test (elementFromPoint
  cruzando shadow DOM) + retry backoff + scroll cycling. Devuelve el punto validado.
  Réplica de _retryAction/_checkElementIsStable/expectHitTarget de Playwright.
- cdp_select_dropdown: desplegables custom (combobox/MUI/select2/headlessui): click real
  en trigger -> espera apertura (aria-expanded/[role=option] visible) -> click real en
  la opción. Resuelve el fallo nº1: clicar antes de que monte el listbox.
- cdp_select_option (endurecida v1.1.0): valida <select> real, match value/label
  normalizado/índice, option.selected para multiple, eventos input{composed}+change.
- cdp_fill: escribir fiable en inputs React/Vue: focus -> select-all -> Input.insertText
  (sin native value setter, como Playwright); native setter solo para inputs especiales.
- cdp_find_by_role: localizar por rol ARIA + accessible name (estilo getByRole),
  reutilizando el AX tree de cdp_get_ax_outline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 20:49:37 +02:00

5.1 KiB

name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, tested, tests, test_file_path, params, output, file_path
name kind lang domain version purity signature description tags uses_functions uses_types returns returns_optional error_type imports tested tests test_file_path params output file_path
cdp_fill function go browser 1.0.0 impure func CdpFill(c *CDPConn, backendNodeID int, value string) error Rellena un campo de texto de forma robusta estilo Playwright, fiable con inputs controlados por frameworks (React/Vue). Valida visible+enabled+editable, enfoca el nodo, y según el tipo: para text/textarea/email/search/url/tel/password/number/contenteditable selecciona el valor previo y lo reemplaza con Input.insertText (eventos input/beforeinput confiables del motor — React/Vue reconcilian solos); para inputs especiales (color/date/time/range/week/month/datetime-local) fija el.value y dispara input{bubbles,composed}+change{bubbles}. Verifica que el.value===value al final. backendNodeID es el #ref del AX outline. Variante por selector: CdpFillSelector. Reemplaza el patrón frágil focus+type que concatena al valor existente.
cdp
browser
action
ref
fill
form
react
vue
navegator
false error_go_core
false
name desc
c Conexión CDP activa al tab objetivo (*CDPConn).
name desc
backendNodeID El #ref del AX outline = backendDOMNodeId estable del nodo DOM. Se obtiene de page_perceive / render_ax_outline.
name desc
value Valor a poner en el campo. Reemplaza el contenido entero (no concatena). value=='' borra el campo. Para input[type=number] debe ser numérico; para color se normaliza a minúsculas.
nil si el campo quedó con el valor pedido; error si la conexión es nil, el nodo no es editable (readonly/disabled/oculto), el tipo de input no se puede rellenar, o la verificación final (el.value===value) falla. functions/browser/cdp_fill.go

Ejemplo

// Tras un page_perceive que devuelve un <input> React con #ref=4521:
conn, _ := CdpConnect(9222)

// Por #ref del AX outline (camino habitual del bucle percibir→actuar):
if err := CdpFill(conn, 4521, "ada@example.com"); err != nil {
    log.Fatal(err)
}

// Por selector CSS estable (resuelve a backendNodeID y delega en CdpFill):
if err := CdpFillSelector(conn, "input[name='email']", "ada@example.com"); err != nil {
    log.Fatal(err)
}

// Vaciar un campo:
_ = CdpFillSelector(conn, "#search", "")

// Input especial (date): ruta setvalue + eventos input/change:
_ = CdpFillSelector(conn, "input[type='date']", "2026-06-16")

Cuando usarla

Cuando necesites rellenar inputs de formularios controlados por React/Vue/otros frameworks de forma fiable. Es el reemplazo del patrón DOM.focus + CdpTypeText/CdpInsertText que concatena al valor existente y a menudo deja el estado del framework desincronizado (el value del DOM cambia pero el estado de React no, o al revés). CdpFill selecciona y reemplaza el contenido entero y, al usar Input.insertText (no el native value setter), emite los eventos input/beforeinput confiables que hacen que el framework reconcilie su estado. Úsala para login, registro, búsquedas y cualquier campo donde el patrón focus+type falle o duplique texto. Para teclear carácter a carácter simulando un humano (sitios con detección por pulsación o autocompletes estrictos) sigue prefiriendo CdpTypeRef (camino human).

Gotchas

  • El #ref es un backendDOMNodeId, no el nodeId efímero del AX tree. Si la página recargó o navegó tras el snapshot, el ref puede estar muerto — re-percibir (page_perceive) antes de actuar.
  • contenteditable: la ruta needsinput inserta el valor seleccionando todo el contenido, pero la verificación final no es fiable para contenteditable (el motor normaliza el HTML). Por eso para contenteditable CdpFill no falla por verificación; confía en que Input.insertText cuajó. Si necesitas garantía dura del contenido, léelo aparte con CdpEvaluate.
  • Inputs especiales (color/date/time/datetime-local/month/range/week) van por la ruta setvalue: fijan el.value y disparan input{bubbles,composed}+change{bubbles}. Algunos frameworks que escuchan eventos de teclado en estos inputs pueden no reaccionar — es el mismo trade-off que hace Playwright.
  • input[type=number]: el valor debe ser numérico (isNaN lo rechaza con error claro). Espacios se recortan.
  • Frameworks y el evento nativo: la clave de la robustez es NO usar el "native value setter" (Object.getOwnPropertyDescriptor(...).set). React parchea el setter de value y se confunde si lo invocas a mano; Input.insertText del motor emite los eventos que React intercepta correctamente. Si una versión muy vieja de un framework custom no reacciona, cae a CdpTypeRef (char por char).
  • No hace scroll humanizado: DOM.focus hace scroll-into-view del nodo, pero si el input está dentro de un contenedor con scroll propio y oculto, valida visible y puede fallar con "elemento no visible". En ese caso haz CdpClickRef (que hace scrollIntoViewIfNeeded) antes.
  • value=="" borra el campo enviando Delete sobre la selección previa (no Input.insertText con cadena vacía, que sería no-op). Esto dispara los eventos de borrado que el framework espera.