Qué widgets de reserva se cubren
El test Hospitality Booking es un escaneo especializado para los widgets interactivos que gobiernan los flujos de reserva hotelera: búsqueda, fechas, huéspedes y selección de habitación.
La mayoría de escáneres de accesibilidad solo ven la página tal como carga por primera vez. Las partes interesantes de un formulario de reserva están ocultas hasta que interactúas con ellas: la lista de destinos, el calendario, el panel de huéspedes. Este test abre cada una como lo haría un visitante y ejecuta las comprobaciones de accesibilidad dentro del panel una vez abierto.
Cómo es una ejecución
Cuando se apunta el test a una URL de un flujo de reserva, recorre este ciclo de forma automática, sin interacción manual:
| Paso | Qué ocurre |
|---|---|
| 1. Carga de la página | Un navegador abre la URL con el viewport, las cookies y el nivel de zoom configurados, y acota la auditoría al formulario de reserva en vez de a toda la página. |
| 2. Despejar el camino | Se cierran los avisos de cookies y cualquier diálogo modal ya presente, para que no contaminen la auditoría. |
| 3. Descubrimiento de widgets | Se escanea la página buscando los campos y botones que abren paneles de reserva, mediante nueve pasadas de detección en capas (ver más abajo). |
| 4. Ciclo por widget | Para cada uno: abrirlo (clic o pulsando Enter / Espacio / flechas), recorrer el panel con Tab y las flechas registrando cada elemento que recibe el foco, comprobar cada uno de esos elementos y cerrar el panel antes de seguir. |
| 5. Comprobaciones por elemento | Los mismos checkpoints que el Detector ejecuta en otros sitios, aplicados dentro del panel abierto: alcanzabilidad por teclado, operabilidad por teclado, visibilidad del foco, contraste de texto (estados normal, hover y foco), contraste no textual, y nombre y rol accesibles. |
| 6. Agregación | Los hallazgos se deduplican —el mismo fallo en varios widgets se colapsa en uno—, se ordenan según el orden de la página y se enriquecen con una solución sugerida. |
Cada hallazgo lleva un título, una descripción, la ubicación en la página, el HTML implicado y el criterio WCAG al que corresponde.
Variantes del test
El mismo motor ofrece varios puntos de entrada, para poder aislar una preocupación cada vez:
| Test | Alcance |
|---|---|
hospitality_booking | Auditoría completa. |
hospitality_booking_navigation_only | Solo alcanzabilidad por teclado, sin contraste. |
hospitality_booking_contrast_only | Contraste de texto y no textual dentro de los widgets, sin hallazgos de navegación. |
hospitality_booking_states_only | Solo contraste de los estados hover y foco. |
hospitality_booking_form | Combina la comprobación de contraste de texto de toda la página con la auditoría de reserva completa. |
Qué cuenta como widget
Un elemento se trata como disparador de widget cuando cumple al menos una de las señales de abajo. La detección va por orden de prioridad —primero las señales ARIA específicas, al final los recursos de reserva— y un elemento detectado en una pasada anterior se omite en las posteriores, de modo que el marcado semántico correcto siempre tiene preferencia sobre las suposiciones por palabra clave.
Señales primarias (ARIA primero)
| Señal | Qué se busca |
|---|---|
aria-haspopup | El elemento declara que abre un popup (menu, listbox, tree, grid, dialog). |
aria-expanded | El elemento controla una región que se puede expandir y plegar. |
role="combobox" | Un campo que abre una lista de opciones, apoyado opcionalmente por aria-controls, aria-owns, aria-activedescendant o aria-autocomplete. |
Recursos de reserva, para componentes personalizados y widgets anteriores a ARIA
| Señal | Patrón |
|---|---|
| Select nativo | Un elemento <select> (de selección única, sin multiple ni size). |
| Campo pulsable | [data-role="field"][tabindex], usado por algunos motores de reserva basados en Polymer. |
| Campo con placeholder | Un <input> con un placeholder significativo de tres caracteres o más, habitual en Angular y otros formularios de página única. |
| Campo de autocompletado | Campos de autocompletado de jQuery-UI o personalizados, reconocidos por el nombre de clase o el atributo data-source. |
| Campo-botón | Un envoltorio <div role="button"> o <span tabindex="0"> con una clase o etiqueta propia de un destino. |
| Campo por palabra clave | Un cajón de sastre: cualquier campo restante cuya etiqueta, placeholder, id, nombre o texto mencione una palabra clave de reserva — destination, hotel, check-in, dates, guests, rooms, personas, huéspedes, quartos. |
Una vez encontrado un disparador, los manejadores especializados de destino, selector de fechas y huéspedes-y-habitaciones tienen cada uno la oportunidad de reclamarlo. Si ninguno lo hace, toma el relevo una rutina genérica de abrir / recorrer / cerrar.
Fuera del ámbito hotelero, la misma filosofía sustenta navegadores de propósito general para comboboxes, acordeones, widgets de divulgación y listas de pestañas.
Tipos de widget y cobertura de cada uno
| Widget | Soporte | Cómo se detecta |
|---|---|---|
| Selector de fechas (calendario de entrada / salida) | ✅ Manejador dedicado | aria-haspopup o aria-expanded en el campo de fecha o su envoltorio; recurso por clase (.datepicker, .daterangepicker, jQuery-UI); recurso por palabra clave. Las celdas pasadas y deshabilitadas se excluyen de la auditoría. |
| Desplegables (destino, tipo de habitación, tarifa) | ✅ Varias vías | <select> nativo; un envoltorio <div role="button" aria-haspopup>; un combobox ARIA; selects mejorados con Select2, donde el elemento nativo oculto se reconoce para no auditarlo dos veces. |
| Contador de huéspedes / habitaciones | ✅ Manejador dedicado | Coincidencia por palabra clave con guest, room, persona, huésped, quarto. Abre el panel y recorre con Tab los controles de incremento, decremento y cantidad. |
| Tarjetas de habitación / carrusel | ⚠️ Parcial | Las tarjetas con aria-expanded o aria-haspopup se tratan como disparadores y se recorren con Tab. Todavía no hay un manejador específico de carrusel —sin comprobaciones de velocidad de rotación ni de enlaces de salto—, pero la alcanzabilidad por teclado y el contraste sí se ejecutan sobre cada hijo enfocable. |
| Indicador de pasos / barra de progreso | ⚠️ Cobertura genérica | Los pasos construidos como botones con aria-expanded se recorren; si no, los cubre el navegador de pestañas genérico. Sin semántica específica de indicador de pasos. |
| Diálogos modales (detalles de habitación, políticas de cancelación, desglose de tarifas) | ✅ Cubierto | Se detectan mediante role="dialog". Los modales ya abiertos al iniciar la ejecución se cierran primero para que no tapen el formulario; los que se abren durante la auditoría los recorre el navegador genérico. |
| Campos de formulario (datos personales, pago, peticiones especiales) | ✅ Cobertura base | Las comprobaciones estándar de nombre y rol, operabilidad por teclado, visibilidad del foco y contraste de texto. La asociación de errores del formulario tiene su propia comprobación. |
| Autocompletado / búsqueda con sugerencias (búsqueda de destino) | ✅ Manejador dedicado | aria-autocomplete="list" o "both" más un rol de popup; recursos por clase y por data-source. El manejador escribe una consulta inicial, recorre la lista de sugerencias y registra contraste y foco en cada opción. |
| Paneles de acordeón (detalles de tarifa, qué incluye, políticas) | ✅ Navegador de propósito general | aria-expanded (obligatorio) más un elemento de cabecera válido (button, <h1>–<h6> o role="button") más un panel con role="region" o aria-labelledby. Se exigen al menos dos de estos indicadores para suprimir falsos positivos. |
| Paneles de pestañas (vistas de habitación, servicios, reseñas) | ✅ Navegador de propósito general | El patrón ARIA nativo: role="tablist" conteniendo elementos role="tab" con aria-selected. Tab se mueve entre grupos y las flechas ciclan dentro de uno. |
Por qué un escáner de propósito general se pierde esto
Este test no introduce ninguna comprobación WCAG nueva. Aplica las existentes —contraste, nombre y rol, operabilidad por teclado, visibilidad del foco, contraste no textual— dentro de contextos emergentes vivos.
Ese es precisamente el punto. Los escáneres automáticos tradicionales auditan el DOM inicial estático, así que todo lo que hay detrás de un calendario cerrado o de un panel de huéspedes plegado les resulta invisible. En un formulario de reserva, eso es la mayor parte de la interfaz que una persona tiene que manejar.
Acotación
La auditoría se acota siempre al widget de reserva y no a la página entera. Se rechaza un selector raíz que abarque todo el documento, para que la ejecución se mantenga centrada en el formulario de reserva y no se desvíe hacia el armazón del sitio —cabeceras, pies y navegación—, que ya cubren las comprobaciones de página completa.
