Files
fn_registry/functions/browser/cdp_select_option.go
T
Egutierrez 9798aed2cf feat(browser): cdp_collect_console + cdp_print_pdf + cdp_select_option + cdp_set_file_input
Cuatro primitivas CDP nuevas para el dominio browser, base de nuevas tools del
browser_mcp:
- cdp_collect_console: snapshot temporal de console + exceptions + log entries
- cdp_print_pdf: Page.printToPDF -> []byte
- cdp_select_option: selecciona <option> en un <select> y dispara input/change
- cdp_set_file_input: sube archivos a un <input type=file> via DOM.setFileInputFiles

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

88 lines
2.8 KiB
Go

package browser
import (
"fmt"
"strings"
)
// CdpSelectOption selecciona la <option> de un <select> (localizado por selector
// CSS) cuyo value coincide con value; si ningun value coincide, busca por texto
// visible de la option. Tras setear select.value despacha los eventos 'input' y
// 'change' con bubbles:true para que frameworks (React/Vue) reaccionen al cambio.
//
// Devuelve error si el select no existe ("select not found") o si ninguna option
// coincide por value ni por texto ("option not found").
func CdpSelectOption(c *CDPConn, selector string, value string) error {
if c == nil {
return fmt.Errorf("cdp select option: conexion nula")
}
// Script JS: localiza el select, busca la option por value y, como fallback,
// por textContent (trim). Si encuentra, setea value, dispara input+change y
// devuelve "__OK__". Si no, devuelve un centinela de error claro. Usamos
// JSON.stringify de los inputs para inyectarlos de forma segura.
js := fmt.Sprintf(`(function() {
var sel = document.querySelector(%s);
if (!sel) return '__NO_SELECT__';
var want = %s;
var opts = Array.prototype.slice.call(sel.options);
var match = null;
for (var i = 0; i < opts.length; i++) {
if (opts[i].value === want) { match = opts[i]; break; }
}
if (!match) {
for (var j = 0; j < opts.length; j++) {
if ((opts[j].textContent || '').trim() === want) { match = opts[j]; break; }
}
}
if (!match) return '__NO_OPTION__';
sel.value = match.value;
sel.dispatchEvent(new Event('input', {bubbles: true}));
sel.dispatchEvent(new Event('change', {bubbles: true}));
return '__OK__';
})()`, jsString(selector), jsString(value))
res, err := CdpEvaluate(c, js)
if err != nil {
return fmt.Errorf("cdp select option: evaluar selector %q: %w", selector, err)
}
res = strings.Trim(res, `"`)
switch res {
case "__OK__":
return nil
case "__NO_SELECT__":
return fmt.Errorf("cdp select option: select not found para selector %q", selector)
case "__NO_OPTION__":
return fmt.Errorf("cdp select option: option not found para value %q en select %q", value, selector)
default:
return fmt.Errorf("cdp select option: resultado inesperado %q para selector %q", res, selector)
}
}
// jsString convierte un string Go en un literal JS seguro (entre comillas dobles,
// con escapes para comillas, backslashes y saltos de linea). Evita la inyeccion
// de codigo al interpolar selectores/valores arbitrarios en el script JS.
func jsString(s string) string {
var b strings.Builder
b.WriteByte('"')
for _, r := range s {
switch r {
case '"':
b.WriteString(`\"`)
case '\\':
b.WriteString(`\\`)
case '\n':
b.WriteString(`\n`)
case '\r':
b.WriteString(`\r`)
case '\t':
b.WriteString(`\t`)
default:
b.WriteRune(r)
}
}
b.WriteByte('"')
return b.String()
}