package browser import ( "encoding/json" "fmt" ) // CdpEvaluate ejecuta una expresion JavaScript en la pagina actual via Runtime.evaluate. // Retorna el resultado como string. Soporta expresiones simples y complejas. // Para valores no-string, Chrome los serializa a JSON. func CdpEvaluate(c *CDPConn, expression string) (string, error) { if c == nil { return "", fmt.Errorf("cdp evaluate: conexion nula") } params := map[string]any{ "expression": expression, "returnByValue": true, "awaitPromise": true, "userGesture": true, } result, err := c.sendCDP("Runtime.evaluate", params) if err != nil { return "", fmt.Errorf("cdp evaluate: %w", err) } // Verificar excepcion JS if exc, ok := result["exceptionDetails"]; ok && exc != nil { excMap, _ := exc.(map[string]any) text, _ := excMap["text"].(string) return "", fmt.Errorf("cdp evaluate: excepcion JS: %s", text) } // Extraer valor del resultado resVal, ok := result["result"].(map[string]any) if !ok { return "", fmt.Errorf("cdp evaluate: resultado inesperado: %v", result) } value, ok := resVal["value"] if !ok { // Puede ser undefined o un tipo no serializable typ, _ := resVal["type"].(string) return typ, nil } // Strings se devuelven tal cual (sin comillas). Objetos y arrays JS, que Chrome // deserializa a map/slice cuando returnByValue=true, se serializan a JSON real // en vez de la repr de Go de fmt.Sprintf("%v") (que produciria "map[a:1]" en lugar // de {"a":1}). Asi el caller puede parsear datos estructurados. if s, ok := value.(string); ok { return s, nil } b, err := json.Marshal(value) if err != nil { return fmt.Sprintf("%v", value), nil } return string(b), nil }