---
name: cdp_find_by_role
kind: function
lang: go
domain: browser
version: "1.0.0"
purity: impure
signature: "func CdpFindByRole(c *CDPConn, role string, opts CdpFindByRoleOpts) (ref int, count int, err error)"
description: "Localiza el primer elemento por su ROLE ARIA + accessible name (estilo getByRole de Playwright) reusando el AX tree (Accessibility.getFullAXTree). Devuelve el backendDOMNodeId (#ref) del primer match y el total de matches para detectar ambiguedad."
tags: [browser]
params:
  - name: c
    desc: "Conexion CDP viva (*CDPConn) del pool. nil => error."
  - name: role
    desc: "Rol ARIA exacto a matchear (ej 'button', 'link', 'textbox', 'checkbox')."
  - name: opts
    desc: "CdpFindByRoleOpts: Name (accessible name, vacio = no filtra), Exact (igualdad en vez de substring), Regex (Name como expresion regular RE2), CaseSensitive (default false)."
output: "(ref int, count int, err error): ref = backendDOMNodeId del primer match (#ref para CdpClickRef/CdpHoverRef); count = total de matches (>1 = ambiguo); err si conexion nula, role vacio, regex invalida, fallo CDP o 0 matches."
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: []
tested: false
tests: []
test_file_path: ""
file_path: "functions/browser/cdp_find_by_role.go"
---

## Ejemplo

```go
c, _ := browser.CdpConnect(9333) // conexion CDP del pool
ref, count, err := browser.CdpFindByRole(c, "button", browser.CdpFindByRoleOpts{
    Name: "Aceptar", // substring del accessible name, case-insensitive
})
if err != nil {
    log.Fatal(err) // ej: no element with role "button" and name "Aceptar"
}
if count > 1 {
    log.Printf("aviso: %d botones matchean 'Aceptar', usando el primero", count)
}
// ref es el mismo #ref que produce page_perceive: alimentarlo a CdpClickRef.
_ = browser.CdpClickRef(c, ref, browser.MouseHumanOpts{})

// Match exacto + case-sensitive:
ref, _, _ = browser.CdpFindByRole(c, "link", browser.CdpFindByRoleOpts{
    Name: "Iniciar sesion", Exact: true, CaseSensitive: true,
})

// Match por regex (ej "Eliminar 3 elementos" / "Eliminar 12 elementos"):
ref, _, _ = browser.CdpFindByRole(c, "button", browser.CdpFindByRoleOpts{
    Name: `^Eliminar \d+ elementos$`, Regex: true,
})
```

## Cuando usarla

Cuando necesites localizar un control de forma robusta a cambios de DOM/CSS: el rol
ARIA + accessible name sobreviven a refactors de markup y clases CSS que romperian un
selector `nth-of-type`. Es el patron primario que recomienda Playwright (getByRole)
para encontrar elementos accionables (botones, links, inputs). Combina el `ref`
devuelto directamente con `cdp_click_ref` / `cdp_hover_ref` para actuar sin pasar por
un selector fragil. Revisa `count` antes de actuar: si es >1 la busqueda es ambigua
y conviene refinar (Name mas especifico, Exact, o Regex anclada).

## Gotchas

- El `name` que se matchea es el **accessible name computado** por el motor de
  accesibilidad de Chrome (deriva de aria-label, label asociado, contenido, alt,
  title segun la spec ARIA), **no** el `innerText` del elemento. Si buscas por el
  texto visible literal, usa `cdp_find_ref_by_text` en su lugar.
- `count > 1` => ambiguedad: se devuelve el primer match en orden del AX tree, que no
  siempre es el visualmente primero ni el que quieres. Refina la busqueda.
- El `role` se compara por **igualdad exacta** del rol ARIA: "button" no matchea
  "menuitem" aunque ambos sean clicables. Mira el outline de `page_perceive` /
  `cdp_get_ax_outline` para ver el rol real que Chrome asigna a cada nodo.
- Nodos `ignored` del AX tree se descartan. Si el elemento esta oculto (aria-hidden,
  display:none) puede no aparecer y dar 0 matches.
- El `ref` es un `backendDOMNodeId`: estable mientras el nodo viva, pero si el DOM
  muta entre el find y el click el ref puede quedar obsoleto.
