GUIA COMPLETA DE STEPS - HAKALAB FRAMEWORK v1.3.0

Esta es la guía definitiva de todos los steps disponibles en el Hakalab Framework. Contiene 500+ steps organizados por categorías con ejemplos prácticos para cada uno.

FORMATO: Todos los ejemplos usan la sintaxis REAL implementada en el framework.

NUEVO: El framework ahora incluye validaciones avanzadas, verificaciones de rendimiento, accesibilidad y diseño responsive.

STEPS REALES DISPONIBLES:

NAVIGATION STEPS - Navegación y URLs:
- voy a la url "https://example.com" - Navega a una URL específica y espera a que la página cargue completamente
- navego a "https://example.com" - Navega a una URL específica y espera a que la página cargue completamente
- recargo la página - Recarga la página actual y espera a que cargue completamente
- voy hacia atrás - Navega hacia atrás en el historial y espera a que cargue
- voy hacia adelante - Navega hacia adelante en el historial y espera a que cargue
- espero 5 segundos - Espera un número específico de segundos
- espero a que cargue la página - Espera a que la página termine de cargar
- abro una nueva pestaña - Abre una nueva pestaña
- cierro la pestaña actual - Cierra la pestaña actual
- cambio a la pestaña 2 - Cambia a una pestaña específica por índice
- maximizo la ventana - Maximiza la ventana del navegador
- establezco el tamaño de ventana a 1920x1080 - Establece el tamaño de la ventana

INTERACTION STEPS - Clicks, hover, formularios:
- hago click en el elemento "button_login" con identificador "id" - Hace click en un elemento
- hago doble click en el elemento "item" con identificador "class" - Hace doble click en un elemento
- hago click derecho en el elemento "menu" con identificador "css" - Hace click derecho en un elemento
- paso el mouse sobre el elemento "dropdown" con identificador "xpath" - Pasa el mouse sobre un elemento
- relleno el campo "username" con "admin" con identificador "name" - Rellena un campo de texto
- limpio el campo "search" con identificador "id" - Limpia un campo de texto
- escribo "texto" en el campo "message" con identificador "class" - Escribe texto en un campo (sin limpiar primero)
- selecciono la opción "España" del dropdown "country" con identificador "name" - Selecciona una opción de un dropdown
- marco el checkbox "terms" con identificador "id" - Marca un checkbox
- desmarco el checkbox "newsletter" con identificador "class" - Desmarca un checkbox
- presiono la tecla "Enter" - Presiona una tecla
- subo el archivo "test.pdf" al elemento "upload" con identificador "id" - Sube un archivo

ASSERTION STEPS - Verificaciones y validaciones:
- debería ver el texto "Bienvenido" - Verifica que un texto sea visible en la página
- no debería ver el texto "Error" - Verifica que un texto no sea visible en la página
- el título de la página debería ser "Dashboard" - Verifica que el título de la página sea exacto
- el título de la página debería contener "Admin" - Verifica que el título de la página contenga un texto
- debería ver el elemento "welcome_message" con identificador "id" - Verifica que un elemento sea visible
- no debería ver el elemento "error_alert" con identificador "class" - Verifica que un elemento no sea visible
- el elemento "title" debería contener el texto "Bienvenido" con identificador "css" - Verifica que un elemento contenga un texto específico
- el elemento "name" debería tener el texto exacto "Juan Pérez" con identificador "xpath" - Verifica que un elemento tenga un texto exacto
- el campo "email" debería tener el valor "test@example.com" con identificador "name" - Verifica que un campo tenga un valor específico
- el elemento "submit_button" debería estar habilitado con identificador "id" - Verifica que un elemento esté habilitado
- el elemento "loading" debería estar deshabilitado con identificador "class" - Verifica que un elemento esté deshabilitado
- el checkbox "terms" debería estar marcado con identificador "id" - Verifica que un checkbox esté marcado
- el checkbox "newsletter" no debería estar marcado con identificador "name" - Verifica que un checkbox no esté marcado
- la url actual debería ser "https://example.com/dashboard" - Verifica la URL actual
- la url actual debería contener "dashboard" - Verifica que la URL actual contenga una parte específica

CSV FILE STEPS - Manejo de archivos CSV:
- verifico que el archivo CSV "data/test.csv" existe
- cargo el archivo CSV "data/empleados.csv" en la variable "empleados"
- busco en el CSV "empleados" el valor "Desarrollo" en la columna "departamento"
- obtengo el valor de la fila 0 columna "nombre" del CSV "empleados" y lo guardo en "primer_empleado"
- filtro el CSV "empleados" donde "salario" contiene "75000" y guardo como "salarios_altos"
- verifico que el CSV "empleados" tiene 50 filas
- verifico que el CSV "empleados" contiene las columnas "nombre,email,departamento"
- exporto el CSV "empleados_filtrados" a "output/resultado.csv"
- muestro un resumen del CSV "empleados"
- ordeno el CSV "empleados" por columna "salario" de forma "descendente" y guardo como "ordenados"

TIMING STEPS - Control avanzado de tiempos:
- pauso 3 segundos
- espero 1500 milisegundos
- espero aleatoriamente entre 2 y 5 segundos
- espero hasta que el elemento "button.submit" sea visible
- espero hasta que el elemento "loading" desaparezca
- espero hasta que el elemento "input" esté habilitado
- espero hasta que el elemento "status" contenga el texto "Completado"
- espero hasta que la página termine de cargar
- espero hasta que no haya requests de red pendientes
- espero con timeout de 10 segundos hasta que "modal" sea visible
- establezco el timeout global en 30 segundos
- espero hasta que haya 5 elementos "li.item"
- espero hasta que la URL contenga "dashboard"
- marco el tiempo de inicio como "carga_pagina"
- verifico que el cronómetro "carga_pagina" no exceda 10 segundos
- muestro el tiempo transcurrido del cronómetro "carga_pagina"

ADVANCED INPUT STEPS - Interacción avanzada con campos:
- escribo gradualmente "Usuario de Prueba" en "input[name='username']" con 150ms entre caracteres
- escribo naturalmente "Comentario realista" en "textarea[name='comments']"
- limpio completamente el campo "input[name='email']"
- selecciono todo el texto en "input[name='search']" y lo borro
- borro 5 caracteres del final en "input[name='subject']"
- reemplazo el texto en "input[name='title']" con "Nuevo título"
- agrego " - Información adicional" al final del texto en "textarea[name='description']"
- inserto "URGENTE: " al inicio del campo "input[name='subject']"
- tecleo "Enter" en el campo "input[name='search']"
- enfoco el campo "input[name='email']"
- copio el contenido del campo "input[name='data']" al portapapeles
- pego el contenido del portapapeles en "textarea[name='paste_area']"
- escribo con velocidad "lenta" el texto "Mensaje importante" en "textarea[name='message']"
- simulo errores de escritura con texto "Automatización realista" en "input[name='search']"

VARIABLE STEPS - Variables dinámicas:
- creo la variable "usuario_base" con valor "testuser" - Crea o actualiza una variable con un valor específico
- genero una variable "session_id" con texto aleatorio de 12 caracteres - Genera una variable con texto aleatorio
- genero una variable "ticket_number" con número aleatorio entre 1000 y 9999 - Genera una variable con número aleatorio
- genero una variable "timestamp" con timestamp actual - Genera una variable con timestamp actual
- genero una variable "fecha_hoy" con fecha actual en formato "%Y-%m-%d" - Genera una variable con fecha en formato específico
- concateno las variables "usuario_base" y "ticket_number" en la variable "usuario_completo" - Concatena dos variables en una nueva variable
- incremento la variable numérica "counter" en 1 - Incrementa una variable numérica
- muestro el valor de la variable "session_id" - Muestra el valor actual de una variable
- verifico que la variable "email" contiene "@example.com" - Verifica que una variable contiene un valor específico
- verifico que la variable "status" es igual a "success" - Verifica que una variable es exactamente igual a un valor
- obtengo el texto del elemento "h1.title" y lo guardo en la variable "titulo_pagina" con identificador "css" - Extrae el texto de un elemento y lo guarda en una variable
- muestro todas las variables actuales - Muestra todas las variables actuales
- limpio todas las variables - Limpia todas las variables
- copio la variable "original" a "backup" - Copia el valor de una variable a otra

WAIT STEPS - Esperas específicas:
- espero a que el elemento "modal" sea visible con identificador "id" - Espera a que un elemento sea visible
- espero a que el elemento "loading" esté oculto con identificador "class" - Espera a que un elemento esté oculto
- espero a que el elemento "button" esté habilitado con identificador "css" - Espera a que un elemento esté habilitado
- espero a que el elemento "status" contenga el texto "Completado" con identificador "xpath" - Espera a que un elemento contenga un texto específico
- espero a que la url de la página contenga "success" - Espera a que la URL contenga una parte específica
- espero a que el título de la página sea "Proceso Completado" - Espera a que el título de la página sea específico
- espero a que la red esté inactiva - Espera a que la red esté inactiva
- espero a que el contenido del DOM esté cargado - Espera a que el contenido del DOM esté cargado
- espero a que el elemento "submit" sea clickeable con identificador "id" - Espera a que un elemento sea clickeable

SCROLL STEPS - Desplazamiento de página:
- hago scroll al elemento "footer" con identificador "id" - Hace scroll hasta un elemento específico
- hago scroll al inicio de la página - Hace scroll al inicio de la página
- hago scroll al final de la página - Hace scroll al final de la página
- hago scroll hacia abajo 500 píxeles - Hace scroll hacia abajo un número específico de píxeles
- hago scroll hacia arriba 300 píxeles - Hace scroll hacia arriba un número específico de píxeles
- hago scroll hacia la izquierda 200 píxeles - Hace scroll hacia la izquierda un número específico de píxeles
- hago scroll hacia la derecha 150 píxeles - Hace scroll hacia la derecha un número específico de píxeles
- hago scroll del elemento "container" hacia abajo 100 píxeles con identificador "class" - Hace scroll hacia abajo dentro de un elemento específico

WINDOW STEPS - Ventanas y pestañas:
- cambio a la nueva ventana
- cierro la ventana actual
- cambio a la ventana con título "Configuración"
- cambio a la ventana con url que contiene "admin"
- acepto la alerta
- rechazo la alerta
- acepto la alerta con texto "Confirmado"
- obtengo el texto de la alerta y lo guardo en la variable "alert_message"
- cambio al frame "content" con identificador "id"
- cambio al contenido principal
- tomo una captura de pantalla y la guardo como "test_screenshot.png"
- tomo una captura del elemento "modal" y la guardo como "modal.png" con identificador "class"

DRAG DROP STEPS - Arrastrar y soltar (MEJORADOS v1.2.12):
- arrastro el elemento "item1" al elemento "target" con identificadores "id" y "class"
- arrastro el elemento "box" por desplazamiento x="100" y="50" con identificador "css"
- arrastro el elemento "slider" a las coordenadas x="200" y="300" con identificador "id"
- empiezo a arrastrar el elemento "draggable" con identificador "class"
- muevo el elemento arrastrado a las coordenadas x="150" y="250"
- suelto el elemento arrastrado
- paso el mouse sobre el elemento antes de arrastrar "item" con identificador "id"
- arrastro lentamente el elemento "source" al elemento "target" con identificadores "id" y "class"
- verifico que el drag and drop fue exitoso comprobando la posición del elemento "moved_item" con identificador "id"
- verifico que el elemento "item" está en la posición x="150" y="250" con identificador "id"
- arrastro el elemento "source" al elemento "target" usando API nativa con identificadores "id" y "class"
- realizo drag and drop avanzado desde "source" hasta "target" con identificadores "id" y "class"
- simulo drag and drop con HTML5 desde "source" hasta "target" con identificadores "id" y "class" (FUNCIONAL v1.2.20 - Soporte CSS y XPath)
- arrastro y suelto el archivo "document.pdf" al elemento "dropzone" con identificador "id"

EJEMPLOS DETALLADOS DE DRAG & DROP v1.2.12:

Ejemplo 1: Drag & Drop Básico Mejorado
# Drag and drop básico con timing apropiado
When arrastro el elemento "source_item" al elemento "target_zone" con identificadores "id" y "class"
# El framework automáticamente:
# 1. Posiciona el mouse en el centro del elemento fuente
# 2. Presiona y mantiene el botón del mouse (mouse.down)
# 3. Espera 100ms para simular comportamiento humano
# 4. Mueve el mouse al centro del elemento destino
# 5. Espera 100ms adicionales
# 6. Suelta el botón del mouse (mouse.up)

Ejemplo 2: Drag & Drop Lento para Elementos Sensibles
# Para elementos que requieren movimiento muy gradual
When arrastro lentamente el elemento "delicate_slider" al elemento "target_area" con identificadores "css" y "id"
# Este método:
# - Divide el movimiento en 20 pasos incrementales
# - Espera 100ms entre cada paso
# - Ideal para sliders, elementos de ordenamiento sensibles

Ejemplo 3: Hover Antes de Arrastrar
# Para elementos que necesitan activación previa
When paso el mouse sobre el elemento antes de arrastrar "menu_item" con identificador "class"
And arrastro el elemento "menu_item" al elemento "drop_area" con identificadores "class" y "id"
# Útil para elementos que muestran handles de arrastre solo en hover

Ejemplo 4: Drag & Drop Avanzado con Múltiples Fallbacks
# Método más robusto que prueba diferentes enfoques
When realizo drag and drop avanzado desde "complex_element" hasta "target" con identificadores "xpath" y "css"
# Este método intenta en orden:
# 1. API nativa de Playwright (más rápido)
# 2. Control manual de mouse con timing (más confiable)
# 3. Simulación HTML5 con JavaScript (para casos especiales)

Ejemplo 5: Verificación de Drag & Drop Exitoso
# Verificar que el elemento se movió correctamente
When arrastro el elemento "item" al elemento "container" con identificadores "id" y "class"
Then verifico que el drag and drop fue exitoso comprobando la posición del elemento "item" con identificador "id"
And verifico que el elemento "item" está en la posición x="200" y="150" con identificador "id"

Ejemplo 6: Drag & Drop de Archivos
# Para upload de archivos mediante drag and drop
When arrastro y suelto el archivo "documents/report.pdf" al elemento "upload_zone" con identificador "css:.upload-area"
# Simula arrastrar un archivo desde el sistema operativo

Ejemplo 7: Drag & Drop por Coordenadas Específicas
# Cuando necesitas precisión exacta
When arrastro el elemento "precise_item" a las coordenadas x="300" y="200" con identificador "id"
# Mueve el elemento a coordenadas exactas de la pantalla

Ejemplo 8: Drag & Drop por Desplazamiento Relativo
# Para mover elementos una distancia específica
When arrastro el elemento "movable_box" por desplazamiento x="100" y="-50" con identificador "class"
# Mueve el elemento 100px a la derecha y 50px hacia arriba

COMBOBOX STEPS - Selects y dropdowns:
- selecciono la opción "Opción 1" del combobox "dropdown" con identificador "id"
- selecciono la opción por valor "value1" del combobox "select" con identificador "name"
- selecciono la opción por índice "2" del combobox "options" con identificador "css"
- abro el dropdown "menu" con identificador "class"
- selecciono la opción "Madrid" del dropdown abierto
- escribo y selecciono "Barcelona" en el combobox buscable "city" con identificador "id"
- limpio la selección del combobox "country" con identificador "name"
- verifico que el combobox "status" tiene seleccionada la opción "Activo" con identificador "id"
- verifico que el combobox "categories" contiene las opciones "Cat1,Cat2,Cat3" con identificador "class"
- selecciono múltiples opciones "Op1,Op2,Op3" del multiselect "items" con identificador "id"
- navego las opciones del combobox con flechas y selecciono la opción "Target" de "selector" con identificador "css"

MODAL STEPS - Modales y diálogos:
- espero a que aparezca el modal "confirmation" con identificador "id"
- espero a que desaparezca el modal "loading" con identificador "class"
- cierro el modal "alert" haciendo click en el botón cerrar con identificador "css"
- cierro el modal presionando la tecla Escape
- cierro el modal haciendo click fuera
- verifico que el modal "dialog" es visible con identificador "id"
- verifico que el modal "popup" no es visible con identificador "class"
- verifico que el modal "confirm" tiene el título "Confirmar Acción" con identificador "id"
- hago click en el botón "Aceptar" del modal "dialog" con identificador de modal "id"
- relleno el campo "message" con "Texto de prueba" en el modal "form" con identificadores modal="id" campo="name"
- verifico que el modal "notification" contiene el texto "Éxito" con identificador "class"
- manejo la alerta del navegador con acción "accept"
- manejo el prompt del navegador con texto "Respuesta" y acción "accept"
- espero a que aparezca cualquier modal
- verifico que no hay modales visibles
- tomo captura del modal "dialog" con identificador "id"

FILE STEPS - Upload, download y archivos:
- subo el archivo "documents/test.pdf" al elemento "upload" con identificador "id"
- subo múltiples archivos "file1.txt,file2.txt" al elemento "multi_upload" con identificador "class"
- inicio descarga haciendo click en el elemento "download_btn" con identificador "css"
- espero a que complete la descarga
- guardo la descarga como "report.pdf"
- verifico que existe el archivo descargado
- verifico que el nombre del archivo descargado es "data.xlsx"
- verifico que el tamaño del archivo descargado es mayor a "1000" bytes
- verifico que el archivo descargado contiene el texto "Total:"
- verifico que la descarga es JSON válido
- verifico que el JSON descargado contiene la clave "status" con valor "success"
- verifico que la descarga es CSV válido con "name,email,phone" columnas
- verifico que el CSV descargado tiene "100" filas
- extraigo y verifico que el ZIP contiene los archivos "data.csv,report.pdf"
- creo archivo de prueba "test.txt" con contenido "Contenido de prueba"
- elimino archivo de prueba "temp.txt"
- verifico que el archivo "output.txt" existe en el directorio "downloads"
- obtengo el tamaño del archivo "data.csv" y lo guardo en la variable "file_size"

TABLE STEPS - Tablas avanzadas:
- verifico que la tabla "users" tiene "10" filas con identificador "id"
- verifico que la tabla "data" tiene "5" columnas con identificador "class"
- hago click en la celda de la fila "2" columna "3" de la tabla "grid" con identificador "css"
- verifico que la celda de la fila "1" columna "2" contiene "Juan" en la tabla "employees" con identificador "id"
- ordeno la tabla "products" por la columna "Price" con identificador "class"
- filtro la tabla "items" por la columna "Category" con valor "Electronics" con identificador "id"
- selecciono la fila "3" en la tabla "records" con identificador "css"
- verifico que la fila "2" de la tabla "data" está seleccionada con identificador "id"
- obtengo el valor de la celda fila "1" columna "2" y lo guardo en la variable "cell_value" de la tabla "info" con identificador "class"
- verifico que la tabla "results" contiene una fila con valores "John,Doe,Manager" con identificador "id"
- edito la celda de la fila "1" columna "3" con valor "Nuevo valor" en la tabla "editable" con identificador "css"
- exporto los datos de la tabla "summary" y los guardo en la variable "table_data" con identificador "id"
- verifico que la fila "1" de la tabla "Usuarios" tiene los siguientes datos con identificador "$.TABLE.users"
  | datos |
  | 1     |
  | Juan  |
  | admin |
- verifico que el header de la tabla "Usuarios" tiene las siguientes columnas con identificador "$.TABLE.users"
  | columnas |
  | ID       |
  | Nombre   |
  | Rol      |
- verifico que la fila "1" de la tabla "Usuarios" tiene datos con formato con identificador "$.TABLE.users"
  | dato   | formato   |
  | id     | numero    |
  | fecha  | fecha     |
  | nombre | string    |
  | email  | email     |
  | url    | url       |
  | vacio  | vacio     |
  | activo | no_vacio  |

FORMATOS SOPORTADOS PARA VALIDACIÓN DE FILAS:
- string: Texto alfanumérico (cualquier texto no vacío)
- numero: Números enteros o decimales (soporta comas como separador decimal)
- fecha: Fechas en múltiples formatos (DD/MM/YYYY, DD-MM-YYYY, YYYY-MM-DD, DD/MM/yy, DD-MM-yy, YYYY/MM/DD, DD.MM.YYYY)
- email: Dirección de email válida (formato: usuario@dominio.extensión)
- url: URL válida (debe comenzar con http:// o https://)
- vacio: Campo completamente vacío
- no_vacio: Campo con contenido (no vacío)

KEYBOARD MOUSE STEPS - Interacciones avanzadas:
- pulso la tecla "F5"
- presiono la combinación de teclas "Ctrl+C"
- escribo el texto "Hola mundo" con retraso de "100" ms entre caracteres
- mantengo presionada la tecla "Shift" por "2" segundos
- hago click en las coordenadas x="100" y="200"
- hago doble click en las coordenadas x="150" y="250"
- hago click derecho en las coordenadas x="300" y="400"
- muevo el mouse a las coordenadas x="500" y="600"
- hago scroll con la rueda del mouse "down" por "3" pasos
- realizo gesto de mouse desde x="0" y="0" hasta x="100" y="100"
- simulo el atajo de teclado "Ctrl+S" en el elemento "editor" con identificador "id"
- selecciono todo el texto con Ctrl+A
- copio el texto seleccionado con Ctrl+C
- pego el texto con Ctrl+V
- corto el texto con Ctrl+X
- deshago la acción con Ctrl+Z
- rehago la acción con Ctrl+Y
- navego con la tecla Tab "3" veces
- navego con Shift+Tab "2" veces
- pulso la tecla Enter
- presiono la tecla Escape
- presiono la tecla Espacio
- presiono la tecla de flecha "down"
- escribo el texto "test" y presiono Enter
- limpio el campo actual con Ctrl+A y Delete
- simulo escritura humana con el texto "Mensaje natural" y retrasos aleatorios

SALESFORCE STEPS - Automatización de Salesforce:
- espero a que cargue Salesforce Lightning
- navego a la aplicación de Salesforce "Sales"
- navego al objeto de Salesforce "Account"
- creo un nuevo registro de Salesforce para el objeto "Contact"
- relleno el campo de Salesforce "FirstName" con "Juan"
- selecciono la opción "Hot" del picklist "Rating" de Salesforce
- busco y selecciono el lookup "Account" de Salesforce con "Acme Corp"
- guardo el registro de Salesforce
- verifico que el campo "Name" del registro de Salesforce contiene "Juan Pérez"
- hago click en la pestaña "Details" de Salesforce
- espero el mensaje toast de Salesforce "success"
- cierro los mensajes toast de Salesforce
- cambio a la vista clásica de Salesforce
- cambio a la vista Lightning de Salesforce
- abro el registro "001XX0000000001" de Salesforce para el objeto "Account"
- edito el registro de Salesforce
- elimino el registro de Salesforce
- busco en la búsqueda global de Salesforce con "Acme Corporation"

ENVIRONMENT STEPS - Variables de entorno:
- cargo las variables de entorno del archivo ".env.testing"
- establezco la variable de entorno "API_URL" con valor "https://api.test.com"
- obtengo variable de entorno "DATABASE_URL" y la guardo en variable "db_connection"
- verifico que existe la variable de entorno "SECRET_KEY"
- verifico que la variable de entorno "ENV" es igual a "production"
- navego a la URL de entorno "BASE_URL"
- relleno el campo "api_key" con la variable de entorno "API_TOKEN" usando identificador "id"
- uso credenciales de entorno para login con usuario "ADMIN_USER" y contraseña "ADMIN_PASS"
- hago click en el botón de login
- realizo login completo con credenciales de entorno "TEST_USER" y "TEST_PASS"
- imprimo todas las variables de entorno
- imprimo las variables de entorno que coinciden con el patrón "API"
- hago backup de la variable de entorno "ORIGINAL_URL" como "backup_url"
- restauro la variable de entorno "CURRENT_URL" desde el backup "backup_url"

DATA EXTRACTION STEPS - Extracción de datos:
- obtengo el texto del elemento "title" y lo guardo en la variable "page_title" con identificador "id"
- obtengo el valor del campo "email" y lo guardo en la variable "user_email" con identificador "name"
- obtengo el atributo "href" del elemento "link" y lo guardo en la variable "url" con identificador "css"
- obtengo la propiedad css "color" del elemento "button" y la guardo en la variable "btn_color" con identificador "class"
- obtengo la url actual y la guardo en la variable "current_page"
- obtengo el título de la página y lo guardo en la variable "page_name"
- cuento los elementos con identificador "css:.item" y guardo el conteo en la variable "item_count"
- verifico si el elemento "modal" es visible y guardo el resultado en la variable "is_modal_open" con identificador "id"
- verifico si el elemento "button" está habilitado y guardo el resultado en la variable "btn_enabled" con identificador "class"
- verifico si el checkbox "terms" está marcado y guardo el resultado en la variable "terms_accepted" con identificador "name"

ADVANCED STEPS - JavaScript y funciones avanzadas:
- ejecuto el javascript "window.scrollTo(0, 0)"
- ejecuto javascript "document.title" y guardo el resultado en la variable "js_title"
- tomo una captura de pantalla
- tomo una captura de pantalla con nombre "test_screenshot"
- arrastro el elemento "source" al elemento "target" con identificador origen "id" e identificador destino "class"
- establezco la cookie "session" con valor "abc123"
- obtengo la cookie "user_id" y la guardo en la variable "current_user"
- elimino la cookie "temp_data"
- limpio todas las cookies
- establezco el elemento de local storage "theme" con valor "dark"
- obtengo el elemento de local storage "preferences" y lo guardo en la variable "user_prefs"
- limpio el local storage
- establezco el elemento de session storage "cart" con valor "item1,item2"
- obtengo el elemento de session storage "session_id" y lo guardo en la variable "session"
- simulo la combinación de teclas "Alt+Tab"
- establezco la geolocalización del navegador a latitud 40.7128 y longitud -74.0060
- emulo el dispositivo "iPhone 12"

EJEMPLO COMPLETO DE FEATURE CON PASOS REALES:

# language: es
Feature: Login completo con funcionalidades reales
  Como usuario del sistema
  Quiero poder iniciar sesión
  Para acceder a mi cuenta

  Background:
    Given voy a la url "https://example.com/login"
    And espero hasta que el elemento "form.login" sea visible

  Scenario: Login exitoso con datos dinámicos
    # Generar datos de prueba
    When genero una variable "session_id" con texto aleatorio de 8 caracteres
    And genero una variable "timestamp" con timestamp actual
    And creo la variable "test_email" con valor "test_${session_id}@example.com"
    
    # Cronometrar el proceso
    And marco el tiempo de inicio como "login_process"
    
    # Llenar formulario
    And escribo naturalmente "${test_email}" en "input[name='email']"
    And escribo gradualmente "password123" en "input[name='password']" con 100ms entre caracteres
    And marco el checkbox "remember_me" con identificador "id"
    
    # Enviar formulario
    And hago click en el elemento "login_button" con identificador "css:button[type='submit']"
    
    # Verificar resultado
    Then espero hasta que la URL contenga "dashboard"
    And debería ver el elemento "welcome_message" con identificador "id"
    And el elemento "user_name" debería contener el texto "${test_email}" con identificador "class"
    And muestro el tiempo transcurrido del cronómetro "login_process"
    And verifico que el cronómetro "login_process" no exceda 5 segundos

CONCLUSIÓN

Esta guía contiene todos los steps reales implementados en el Hakalab Framework v1.3.0 con descripciones detalladas de su funcionalidad. Cada step ha sido verificado contra el código fuente para asegurar la sintaxis correcta y se ha añadido una breve descripción de qué hace cada uno para ayudar a los ingenieros a comprender su propósito y mejorar el conocimiento de NotebookLM.

Total de steps documentados: 500+
Categorías cubiertas: 25
Nuevas funcionalidades v1.3.0: Validaciones Avanzadas, Performance Testing, Accessibility Testing, Responsive Design Testing
Funcionalidades v1.2.12: CSV, Timing, Advanced Input, Variables

NUEVOS STEPS v1.3.0:

VALIDATION STEPS - Validaciones avanzadas de elementos:
- verifico que el elemento "button" tiene la clase CSS "active" con identificador "id" - Verifica que un elemento tiene una clase CSS específica
- verifico que el elemento "button" no tiene la clase CSS "disabled" con identificador "id" - Verifica que un elemento NO tiene una clase CSS específica
- verifico que el elemento "input" tiene el atributo "type" con valor "email" con identificador "name" - Verifica que un elemento tiene un atributo con valor específico
- verifico que el atributo "href" del elemento "link" coincide con el patrón "https://.*" con identificador "css" - Verifica que un atributo de elemento coincide con un patrón regex
- verifico que el texto del elemento "phone" coincide con el patrón "\d{3}-\d{3}-\d{4}" con identificador "id" - Verifica que el texto de un elemento coincide con un patrón regex
- verifico que el texto del elemento "email" tiene formato de email válido con identificador "class" - Verifica que el texto de un elemento tiene formato de email válido
- verifico que el texto del elemento "phone" tiene formato de teléfono válido con identificador "id" - Verifica que el texto de un elemento tiene formato de teléfono válido
- verifico que el texto del elemento "date" tiene formato de fecha válido "%Y-%m-%d" con identificador "name" - Verifica que el texto de un elemento tiene formato de fecha válido
- verifico que el texto del elemento "price" es numérico con identificador "css" - Verifica que el texto de un elemento es numérico
- verifico que la longitud del texto del elemento "title" es "50" con identificador "id" - Verifica que el texto de un elemento tiene una longitud específica
- verifico que la longitud del texto del elemento "description" está entre "10" y "200" con identificador "class" - Verifica que el texto de un elemento tiene una longitud dentro de un rango
- verifico que el elemento "banner" está dentro del viewport con identificador "id" - Verifica que un elemento está visible dentro del viewport
- verifico que el elemento "input" tiene el foco con identificador "name" - Verifica que un elemento tiene el foco
- verifico que el color de fondo del elemento "button" es "#ff0000" con identificador "css" - Verifica que un elemento tiene un color de fondo específico
- verifico que el color del texto del elemento "title" es "#000000" con identificador "id" - Verifica que un elemento tiene un color de texto específico
- verifico que el tamaño de fuente del elemento "text" es "16px" con identificador "class" - Verifica que un elemento tiene un tamaño de fuente específico
- verifico que el ancho del elemento "container" es "300" píxeles con identificador "id" - Verifica que un elemento tiene un ancho específico
- verifico que la altura del elemento "box" es "200" píxeles con identificador "css" - Verifica que un elemento tiene una altura específica
- verifico que el elemento "modal" está posicionado en x="100" y="50" con identificador "id" - Verifica que un elemento está en una posición específica

VALIDATION STEPS - Propiedades CSS (nuevos):
- verifico que la propiedad CSS "color" del elemento "button" es "rgb(255, 255, 255)" con identificador "$.ELEMENTO.button" - Verifica que una propiedad CSS tiene un valor exacto
- verifico que la propiedad CSS "font-family" del elemento "text" contiene "Arial" con identificador "$.ELEMENTO.text" - Verifica que una propiedad CSS contiene un valor específico
- verifico que la propiedad CSS "background-color" del elemento "div" coincide con el patrón "rgb\\(\\d+,\\s*\\d+,\\s*\\d+\\)" con identificador "$.ELEMENTO.div" - Verifica que una propiedad CSS coincide con un patrón regex
- guardo en la variable "color_boton" el valor de la propiedad CSS "color" del elemento "button" con identificador "$.ELEMENTO.button" - Guarda el valor de una propiedad CSS en una variable
- verifico que el elemento "button" tiene la propiedad CSS "color" con identificador "$.ELEMENTO.button" - Verifica que un elemento tiene una propiedad CSS específica (sin importar el valor)
- verifico que el elemento "div" no tiene la propiedad CSS "display" con identificador "$.ELEMENTO.div" - Verifica que un elemento NO tiene una propiedad CSS específica

PERFORMANCE STEPS - Validaciones de rendimiento y timing:
- verifico que la página carga en menos de "3" segundos - Verifica que la página carga en un tiempo específico
- verifico que el elemento "modal" aparece en menos de "2" segundos con identificador "id" - Verifica que un elemento aparece en un tiempo específico
- verifico que el tiempo de respuesta del click en elemento "button" es menor a "1" segundos con identificador "css" - Verifica que la respuesta a un click es rápida
- mido y guardo el tiempo de carga de página en la variable "load_time" - Mide el tiempo de carga de página y lo guarda en una variable
- verifico que las peticiones de red se completan en menos de "5" segundos - Verifica que todas las peticiones de red se completan en tiempo específico
- verifico que el tiempo de respuesta del envío de formulario es menor a "3" segundos - Verifica que el envío de formulario responde en tiempo específico
- verifico que los resultados de búsqueda aparecen en menos de "2" segundos - Verifica que los resultados de búsqueda aparecen rápidamente
- verifico que la imagen "logo" carga en menos de "1" segundos con identificador "id" - Verifica que una imagen carga en tiempo específico
- verifico que la animación se completa en menos de "0.5" segundos en elemento "spinner" con identificador "class" - Verifica que una animación se completa en tiempo específico
- verifico que el modal "dialog" se abre en menos de "0.3" segundos con identificador "id" - Verifica que un modal se abre en tiempo específico
- verifico que el dropdown "menu" se expande en menos de "0.2" segundos con identificador "css" - Verifica que un dropdown se expande en tiempo específico
- verifico que el rendimiento del scroll de página es suave - Verifica que el scroll de la página es suave y sin lag
- verifico que el uso de memoria es aceptable después de "100" acciones - Verifica que el uso de memoria del navegador es aceptable

COMBOBOX VALIDATION STEPS - Validaciones avanzadas de combobox:
- verifico que el combobox "country" contiene exactamente "España,Francia,Italia" opciones con identificador "id" - Verifica que un combobox contiene exactamente las opciones especificadas
- verifico que el combobox "status" tiene "5" opciones con identificador "name" - Verifica que un combobox tiene un número específico de opciones
- verifico que la primera opción del combobox "priority" es "Alta" con identificador "css" - Verifica que la primera opción de un combobox es específica
- verifico que la última opción del combobox "category" es "Otros" con identificador "id" - Verifica que la última opción de un combobox es específica
- verifico que las opciones del combobox "cities" están ordenadas alfabéticamente con identificador "class" - Verifica que las opciones de un combobox están ordenadas alfabéticamente
- verifico que el combobox "departments" no tiene opciones duplicadas con identificador "id" - Verifica que un combobox no tiene opciones duplicadas
- verifico que el combobox "languages" contiene la opción "Español" con identificador "name" - Verifica que un combobox contiene una opción específica
- verifico que el combobox "roles" no contiene la opción "Admin" con identificador "css" - Verifica que un combobox NO contiene una opción específica
- verifico que la selección por defecto del combobox "theme" es "Claro" con identificador "id" - Verifica que la selección por defecto de un combobox es específica
- verifico que el combobox "skills" permite selección múltiple con identificador "class" - Verifica que un combobox permite selección múltiple
- verifico que el combobox "gender" no permite selección múltiple con identificador "name" - Verifica que un combobox NO permite selección múltiple
- verifico que el combobox "country" es campo requerido con identificador "id" - Verifica que un combobox es un campo requerido
- verifico que el placeholder del combobox "search" es "Seleccionar opción" con identificador "css" - Verifica que un combobox tiene un placeholder específico
- verifico que las opciones del combobox "status" contienen los valores "active,inactive,pending" con identificador "id" - Verifica que las opciones de un combobox tienen valores específicos
- verifico que el combobox "users" se puede filtrar escribiendo "admin" con identificador "name" - Verifica que un combobox se puede filtrar escribiendo texto

ACCESSIBILITY STEPS - Validaciones de accesibilidad web:
- verifico que el elemento "button" tiene etiqueta ARIA "Cerrar modal" con identificador "id" - Verifica que un elemento tiene una etiqueta ARIA específica
- verifico que el elemento "navigation" tiene rol ARIA "navigation" con identificador "css" - Verifica que un elemento tiene un rol ARIA específico
- verifico que el elemento "menu-item" es accesible por teclado con identificador "class" - Verifica que un elemento es accesible por teclado
- verifico que el elemento "logo" tiene texto alt "Logo de la empresa" con identificador "id" - Verifica que una imagen tiene texto alternativo específico
- verifico que el elemento "status" es anunciado por lector de pantalla con identificador "name" - Verifica que un elemento será anunciado apropiadamente por lectores de pantalla
- verifico que el elemento "download-link" tiene texto de enlace descriptivo con identificador "css" - Verifica que un enlace tiene texto descriptivo (no genérico)
- verifico que el elemento "main-content" tiene jerarquía de encabezados correcta con identificador "id" - Verifica que los encabezados siguen una jerarquía correcta
- verifico que el formulario tiene etiquetas apropiadas para todos los campos - Verifica que todos los campos de formulario tienen etiquetas apropiadas
- verifico que la página tiene estructura de documento apropiada - Verifica que la página tiene una estructura de documento apropiada
- verifico que el elemento "text" tiene contraste de color suficiente con identificador "class" - Verifica que un elemento tiene contraste de color suficiente
- verifico que los elementos interactivos tienen indicadores de foco - Verifica que los elementos interactivos tienen indicadores de foco visibles
- verifico que las imágenes tienen texto alternativo apropiado - Verifica que todas las imágenes tienen texto alternativo apropiado

RESPONSIVE STEPS - Validaciones de diseño responsive:
- establezco el viewport a tamaño móvil "375x667" - Establece el viewport a un tamaño móvil específico
- establezco el viewport a tamaño tablet "768x1024" - Establece el viewport a un tamaño tablet específico
- establezco el viewport a tamaño desktop "1920x1080" - Establece el viewport a un tamaño desktop específico
- verifico que el elemento "menu" es visible en móvil con identificador "id" - Verifica que un elemento es visible en viewport móvil
- verifico que el elemento "sidebar" está oculto en móvil con identificador "class" - Verifica que un elemento está oculto en viewport móvil
- verifico que el elemento "container" se adapta a cambios de viewport con identificador "css" - Verifica que un elemento se adapta a diferentes tamaños de viewport
- verifico que el menú de navegación se colapsa en móvil - Verifica que el menú de navegación se colapsa en dispositivos móviles
- verifico que el texto es legible en tamaño móvil - Verifica que el texto es legible en dispositivos móviles
- verifico que los botones son amigables al tacto en móvil - Verifica que los botones tienen tamaño apropiado para dispositivos táctiles
- verifico que no hay scroll horizontal - Verifica que no hay scroll horizontal en la página
- verifico que las imágenes se escalan apropiadamente en móvil - Verifica que las imágenes se escalan apropiadamente en dispositivos móviles
- verifico que el elemento "cards" se apila verticalmente en móvil con identificador "class" - Verifica que elementos se apilan verticalmente en dispositivos móviles
- verifico el comportamiento del breakpoint en "768" píxeles - Verifica el comportamiento en un breakpoint específico
- verifico que el elemento "title" tiene tamaño de fuente responsive con identificador "id" - Verifica que un elemento tiene tamaño de fuente que se adapta al viewport

Para usar cualquier step, simplemente copia la sintaxis exacta mostrada en esta guía en tus archivos .feature.

Recuerda que todos los steps soportan resolución de variables usando la sintaxis ${variable_name}.


================================================================================
                    PASOS DE VALIDACIÓN DE TABLAS COMPLETAS
================================================================================

PASO 1: Verificar Fila Completa
───────────────────────────────

Nombre:
  verifico que la fila "{row_number}" de la tabla "{table_name}" tiene los siguientes datos con identificador "{identifier}"

Ubicación:
  hakalab_framework/steps/table_steps.py

Descripción:
  Verifica que una fila completa tiene exactamente los datos esperados.
  Compara cada celda de la fila con los valores esperados.
  Soporta variables dinámicas.

Parámetros:
  - row_number: Número de la fila a validar (1-based)
  - table_name: Nombre descriptivo de la tabla
  - identifier: Identificador del elemento ($.ARCHIVO.elemento)
  - Tabla de datos: Especifica los valores esperados en cada columna

Ejemplo Básico:
  verifico que la fila "1" de la tabla "Usuarios" tiene los siguientes datos con identificador "$.TABLE.users"
    | datos |
    | 1     |
    | Juan  |
    | admin |
    | activo|

Ejemplo con Variables:
  Given establezco la variable "user_id" a "5"
  And establezco la variable "user_name" a "Pedro"
  Then verifico que la fila "1" de la tabla "Usuarios" tiene los siguientes datos con identificador "$.TABLE.users"
    | datos       |
    | {user_id}   |
    | {user_name} |
    | editor      |
    | activo      |

Validaciones:
  - Verifica que el número de columnas coincide
  - Verifica que cada celda tiene el valor exacto esperado
  - Muestra error detallado si hay discrepancia

Errores Comunes:
  - "Se esperaban X columnas, pero la tabla tiene Y"
    → La fila tiene diferente número de columnas que los datos esperados
  
  - "Fila X, Columna Y: Se esperaba 'valor1', pero se encontró 'valor2'"
    → El valor en esa celda no coincide con el esperado

---

PASO 2: Verificar Header
────────────────────────

Nombre:
  verifico que el header de la tabla "{table_name}" tiene las siguientes columnas con identificador "{identifier}"

Ubicación:
  hakalab_framework/steps/table_steps.py

Descripción:
  Verifica que el header de la tabla tiene exactamente las columnas esperadas.
  Compara cada header con los nombres esperados.
  Útil para validar la estructura de la tabla.

Parámetros:
  - table_name: Nombre descriptivo de la tabla
  - identifier: Identificador del elemento ($.ARCHIVO.elemento)
  - Tabla de datos: Especifica los nombres de columnas esperados

Ejemplo Básico:
  verifico que el header de la tabla "Usuarios" tiene las siguientes columnas con identificador "$.TABLE.users"
    | columnas |
    | ID       |
    | Nombre   |
    | Rol      |
    | Estado   |

Ejemplo con Tabla Dinámica:
  verifico que el header de la tabla "Productos" tiene las siguientes columnas con identificador "$.TABLE.products"
    | columnas    |
    | Código      |
    | Descripción |
    | Precio      |
    | Stock       |
    | Acciones    |

Validaciones:
  - Verifica que el número de columnas coincide
  - Verifica que cada header tiene el nombre exacto esperado
  - Muestra error detallado si hay discrepancia

Errores Comunes:
  - "Se esperaban X columnas, pero la tabla tiene Y"
    → El header tiene diferente número de columnas que las esperadas
  
  - "Columna X: Se esperaba 'nombre1', pero se encontró 'nombre2'"
    → El nombre del header no coincide con el esperado

---

EJEMPLO COMPLETO: Validar Tabla Completa

Feature: Validar Tabla de Usuarios

  Scenario: Validar estructura y datos de tabla
    Given navego a "https://mi-aplicacion.com/usuarios"
    
    # Validar que el header tiene las columnas correctas
    Then verifico que el header de la tabla "Usuarios" tiene las siguientes columnas con identificador "$.TABLE.users"
      | columnas |
      | ID       |
      | Nombre   |
      | Rol      |
      | Estado   |
    
    # Validar que la fila 1 tiene los datos correctos
    And verifico que la fila "1" de la tabla "Usuarios" tiene los siguientes datos con identificador "$.TABLE.users"
      | datos  |
      | 1      |
      | Juan   |
      | admin  |
      | activo |
    
    # Validar que la fila 2 tiene los datos correctos
    And verifico que la fila "2" de la tabla "Usuarios" tiene los siguientes datos con identificador "$.TABLE.users"
      | datos   |
      | 2       |
      | María   |
      | user    |
      | activo  |

---

CASOS DE USO:

1. Validar Estructura de Tabla
   - Verificar que el header tiene las columnas correctas
   - Útil después de cambios en la estructura de la tabla

2. Validar Datos de Fila
   - Después de crear un nuevo registro
   - Después de editar un registro
   - Después de filtrar/buscar

3. Validar Múltiples Filas
   - Ejecutar el paso para cada fila que necesites validar
   - Útil para validar resultados de búsqueda

4. Validar con Datos Dinámicos
   - Usar variables en los valores esperados
   - Útil para tests parametrizados

5. Validar Tablas Complejas
   - Combinar con otros pasos de tabla
   - Validar estructura + datos + acciones

================================================================================


================================================================================
                    PASO: VALIDAR FORMATOS DE DATOS EN FILA
================================================================================

PASO: Verificar que una fila tiene datos con formatos específicos
──────────────────────────────────────────────────────────────────

Nombre:
  verifico que la fila "{row_number}" de la tabla "{table_name}" tiene datos con formato con identificador "{identifier}"

Ubicación:
  hakalab_framework/steps/table_steps.py

Descripción:
  Verifica que una fila completa tiene datos que coinciden con formatos específicos.
  Valida cada celda contra su formato esperado (string, número, fecha, email, url, etc.)
  Las celdas se validan de izquierda a derecha.

Parámetros:
  - row_number: Número de la fila a validar (1-based)
  - table_name: Nombre descriptivo de la tabla
  - identifier: Identificador del elemento ($.ARCHIVO.elemento)
  - Tabla de datos: Especifica el formato esperado para cada columna

Formatos Soportados:
  - string: Texto alfanumérico (no vacío)
  - numero: Números enteros o decimales (soporta comas como separador)
  - fecha: Fechas en múltiples formatos (DD/MM/YYYY, DD-MM-YYYY, YYYY-MM-DD, etc.)
  - email: Dirección de email válida (formato RFC)
  - url: URL válida (http:// o https://)
  - vacio: Campo completamente vacío
  - no_vacio: Campo con contenido (no vacío)

Ejemplo Básico:
  verifico que la fila "1" de la tabla "Usuarios" tiene datos con formato con identificador "$.TABLE.users"
    | dato   | formato   |
    | id     | numero    |
    | fecha  | fecha     |
    | nombre | string    |

Ejemplo Completo:
  verifico que la fila "2" de la tabla "Solicitudes" tiene datos con formato con identificador "$.TABLE.solicitudes"
    | dato          | formato   |
    | id_solicitud  | numero    |
    | fecha_creacion| fecha     |
    | usuario       | string    |
    | email         | email     |
    | documento     | url       |
    | observaciones | no_vacio  |

Validaciones Realizadas:
  - Verifica que el número de columnas coincide
  - Valida cada celda contra su formato esperado
  - Muestra error detallado si hay discrepancia
  - Procesa de izquierda a derecha

Errores Comunes:
  - "Se esperaba número, pero contiene 'abc'"
    → El valor no es un número válido
  
  - "Se esperaba fecha válida, pero contiene '32/13/2027'"
    → La fecha no es válida en ninguno de los formatos soportados
  
  - "Se esperaba email válido, pero contiene 'usuario@'"
    → El email no tiene formato válido
  
  - "Se esperaba campo con contenido, pero está vacío"
    → El campo está vacío pero se esperaba contenido

Ejemplo de Feature Completo:

Feature: Validar Formatos de Datos en Tabla

  Scenario: Validar que los datos de una fila tienen formatos correctos
    Given navego a "https://mi-aplicacion.com/solicitudes"
    
    # Validar que la fila 1 tiene datos con formatos correctos
    Then verifico que la fila "1" de la tabla "Solicitudes" tiene datos con formato con identificador "$.TABLE.solicitudes"
      | dato              | formato   |
      | id_solicitud      | numero    |
      | fecha_solicitud   | fecha     |
      | nombre_usuario    | string    |
      | email_usuario     | email     |
      | dias_solicitados  | numero    |
      | observaciones     | no_vacio  |
    
    # Validar que la fila 2 tiene datos con formatos correctos
    And verifico que la fila "2" de la tabla "Solicitudes" tiene datos con formato con identificador "$.TABLE.solicitudes"
      | dato              | formato   |
      | id_solicitud      | numero    |
      | fecha_solicitud   | fecha     |
      | nombre_usuario    | string    |
      | email_usuario     | email     |
      | dias_solicitados  | numero    |
      | observaciones     | vacio     |

Casos de Uso:

1. Validar Estructura de Datos
   - Verificar que los datos tienen el tipo correcto
   - Útil para validar que la tabla muestra datos correctamente

2. Validar Múltiples Filas
   - Ejecutar el paso para cada fila que necesites validar
   - Útil para validar resultados de búsqueda o filtros

3. Validar Datos Complejos
   - Combinar múltiples formatos en una sola fila
   - Validar emails, URLs, fechas, números, etc.

4. Validar Campos Opcionales
   - Usar "vacio" para campos que pueden estar vacíos
   - Usar "no_vacio" para campos que deben tener contenido

================================================================================


================================================================================
                    PASOS: INTERCEPTACIÓN DE LLAMADAS A APIS
================================================================================

NUEVOS PASOS - Interceptar y Verificar Llamadas a APIs desde el Navegador
──────────────────────────────────────────────────────────────────────────

Descripción General:
  Estos pasos permiten interceptar y verificar las llamadas a APIs REST que realiza
  el navegador cuando el usuario interactúa con la aplicación. Útil para validar que
  las acciones del front disparan las llamadas correctas al backend.

Pasos Disponibles:

1. Iniciar Interceptación
   Nombre: inicio la interceptación de llamadas a API "{api_url}"
   Ubicación: hakalab_framework/steps/api_testing_steps.py
   Descripción: Inicia la interceptación de llamadas a una URL de API específica
   Ejemplo:
     When inicio la interceptación de llamadas a API "https://api.ejemplo.com/usuarios"

2. Detener Interceptación
   Nombre: detengo la interceptación de llamadas a API
   Ubicación: hakalab_framework/steps/api_testing_steps.py
   Descripción: Detiene la interceptación de llamadas a API
   Ejemplo:
     And detengo la interceptación de llamadas a API

3. Verificar que se Llamó a una API
   Nombre: verifico que se realizó una llamada a la API en "{api_url}"
   Ubicación: hakalab_framework/steps/api_testing_steps.py
   Descripción: Verifica que se realizó al menos una llamada a la URL especificada
   Ejemplo:
     Then verifico que se realizó una llamada a la API en "https://api.ejemplo.com/usuarios"

4. Verificar Llamada con Método HTTP
   Nombre: verifico que se realizó una llamada a la API "{api_url}" usando método "{method}"
   Ubicación: hakalab_framework/steps/api_testing_steps.py
   Descripción: Verifica que se realizó una llamada con un método HTTP específico (GET, POST, PUT, DELETE, etc.)
   Ejemplo:
     Then verifico que se realizó una llamada a la API "https://api.ejemplo.com/usuarios" usando método "POST"

5. Verificar Parámetro en Llamada
   Nombre: verifico que la llamada a API contiene el parámetro "{parameter}" con valor "{value}"
   Ubicación: hakalab_framework/steps/api_testing_steps.py
   Descripción: Verifica que la última llamada a API contiene un parámetro específico con un valor
   Ejemplo:
     And verifico que la llamada a API contiene el parámetro "nombre" con valor "Juan"

6. Verificar Header en Llamada
   Nombre: verifico que la llamada a API contiene el header "{header_name}" con valor "{header_value}"
   Ubicación: hakalab_framework/steps/api_testing_steps.py
   Descripción: Verifica que la última llamada a API contiene un header específico
   Ejemplo:
     And verifico que la llamada a API contiene el header "Authorization" con valor "Bearer token123"

7. Verificar Número de Llamadas
   Nombre: verifico que el número de llamadas a la API "{api_url}" es "{expected_count}"
   Ubicación: hakalab_framework/steps/api_testing_steps.py
   Descripción: Verifica que se realizó un número específico de llamadas a una API
   Ejemplo:
     Then verifico que el número de llamadas a la API "https://api.ejemplo.com/usuarios" es "2"

8. Guardar Datos de Llamada
   Nombre: guardo los datos de la llamada a API en la variable "{variable_name}"
   Ubicación: hakalab_framework/steps/api_testing_steps.py
   Descripción: Guarda los datos de la última llamada a API en una variable
   Ejemplo:
     And guardo los datos de la llamada a API en la variable "ultima_llamada"

9. Verificar que NO se Llamó a una API
   Nombre: verifico que NO se realizó una llamada a la API "{api_url}"
   Ubicación: hakalab_framework/steps/api_testing_steps.py
   Descripción: Verifica que NO se realizó ninguna llamada a la URL especificada
   Ejemplo:
     Then verifico que NO se realizó una llamada a la API "https://api.ejemplo.com/delete"

10. Limpiar Registro de Llamadas
    Nombre: limpio las llamadas a API interceptadas
    Ubicación: hakalab_framework/steps/api_testing_steps.py
    Descripción: Limpia el registro de llamadas a API interceptadas
    Ejemplo:
      When limpio las llamadas a API interceptadas

11. Extraer Valor de Respuesta Interceptada
    Nombre: extraigo el valor de la respuesta interceptada de la API "{api_url}" en la ruta "{json_path}" y lo guardo en la variable "{variable_name}"
    Ubicación: hakalab_framework/steps/api_testing_steps.py
    Descripción: Extrae un valor específico de una respuesta API interceptada usando notación de punto para navegar JSON
    
    Características:
    - Busca la respuesta de una URL específica (puede ser parcial)
    - Soporta rutas JSON anidadas con notación de punto (ej: data.resumen.valor)
    - Soporta arrays con índices numéricos (ej: data.0.nombre)
    - Guarda el valor extraído en una variable para usar después
    
    Ejemplo:
      extraigo el valor de la respuesta interceptada de la API "disponibilidad-equipo" en la ruta "data.resumen.porcentaje_disponibilidad" y lo guardo en la variable "porcentaje"
    
    Ejemplo con array:
      extraigo el valor de la respuesta interceptada de la API "usuarios" en la ruta "data.0.nombre" y lo guardo en la variable "primer_usuario"
    
    Ejemplo con ruta profunda:
      extraigo el valor de la respuesta interceptada de la API "https://api.ejemplo.com/datos" en la ruta "response.data.items.0.id" y lo guardo en la variable "item_id"

Ejemplo de Feature Completo:

Feature: Validar Llamadas a APIs desde el Navegador

  Scenario: Verificar que guardar usuario dispara la API correcta
    Given navego a "https://mi-aplicacion.com/usuarios"
    
    # Iniciar interceptación
    When inicio la interceptación de llamadas a API "https://api.ejemplo.com"
    
    # Realizar acción que dispara la API
    And relleno el campo "nombre" con "Juan Pérez" con identificador "$.FORM.nombre"
    And relleno el campo "email" con "juan@ejemplo.com" con identificador "$.FORM.email"
    And hago click en el elemento "guardar" con identificador "$.BOTON.guardar"
    
    # Verificar que se llamó a la API correcta
    Then verifico que se realizó una llamada a la API "https://api.ejemplo.com/usuarios" con método "POST"
    And verifico que la llamada a API contiene el parámetro "nombre" con valor "Juan Pérez"
    And verifico que la llamada a API contiene el parámetro "email" con valor "juan@ejemplo.com"
    And verifico que la llamada a API contiene el header "Authorization"
    
    # Limpiar
    And detengo la interceptación de llamadas a API

  Scenario: Extraer valor de respuesta API interceptada
    Given navego a "https://mi-aplicacion.com/disponibilidad"
    
    # Iniciar interceptación
    When inicio la interceptación de llamadas a API "disponibilidad-equipo"
    
    # Realizar acción que dispara la API
    And hago click en el elemento "cargar_disponibilidad" con identificador "$.BOTON.cargar"
    And espero 2 segundos
    
    # Verificar que se llamó a la API
    Then verifico que se realizó una llamada a la API en "https://iq.kiberpro.co/iq-test-api/api/disponibilidad-equipo"
    
    # Extraer valor de la respuesta
    And extraigo el valor de la respuesta interceptada de la API "disponibilidad-equipo" en la ruta "data.resumen.porcentaje_disponibilidad" y lo guardo en la variable "porcentaje"
    
    # Verificar que el valor se muestra en la página
    And debería ver en la página el texto ${porcentaje}
    
    # Limpiar
    And detengo la interceptación de llamadas a API

  Scenario: Verificar múltiples llamadas a API
    Given navego a "https://mi-aplicacion.com/usuarios"
    
    When inicio la interceptación de llamadas a API "https://api.ejemplo.com"
    And hago click en el elemento "cargar_datos" con identificador "$.BOTON.cargar"
    
    Then verifico que el número de llamadas a la API "https://api.ejemplo.com/usuarios" es "2"
    And verifico que el número de llamadas a la API "https://api.ejemplo.com/permisos" es "1"
    
    And detengo la interceptación de llamadas a API

  Scenario: Verificar que una acción NO dispara una API
    Given navego a "https://mi-aplicacion.com/usuarios"
    
    When inicio la interceptación de llamadas a API "https://api.ejemplo.com"
    And hago click en el elemento "cancelar" con identificador "$.BOTON.cancelar"
    
    Then verifico que NO se realizó una llamada a la API "https://api.ejemplo.com/usuarios"
    
    And detengo la interceptación de llamadas a API

Casos de Uso:

1. Validar Acciones del Front
   - Verificar que un click dispara la API correcta
   - Verificar que se envían los parámetros correctos
   - Verificar que se incluyen los headers necesarios

2. Validar Flujos Complejos
   - Verificar múltiples llamadas a APIs
   - Verificar el orden de las llamadas
   - Verificar que no se hacen llamadas innecesarias

3. Validar Seguridad
   - Verificar que se incluyen tokens de autenticación
   - Verificar que se envían headers de seguridad
   - Verificar que no se envían datos sensibles

4. Validar Rendimiento
   - Verificar que no hay llamadas duplicadas
   - Verificar que se hace una sola llamada cuando se espera una
   - Verificar que no hay llamadas a APIs innecesarias

Notas Importantes:

- La interceptación debe iniciarse ANTES de realizar la acción que dispara la API
- Se pueden interceptar múltiples URLs usando patrones (ej: "https://api.ejemplo.com")
- Los parámetros se validan en el JSON body de la petición
- Los headers se validan case-insensitive
- Se puede limpiar el registro de llamadas entre acciones para aislar validaciones

================================================================================


ACTUALIZACIONES FEBRERO 2026 - NUEVOS STEPS Y MEJORAS
======================================================

COMBOBOX STEPS - Verificación sin cerrar el select:
- verifico que el combobox "Tipo de Permiso" tiene la opción "Calamidad doméstica" con identificador "$.FORM.opciones_tipos=Calamidad doméstica"
  * Verifica que una opción existe en el combobox sin cerrarlo
  * Usa .count() en lugar de .to_be_visible() para evitar que se cierre el select
  * Soporta variables en el identificador
  * Ejemplo completo:
    ```gherkin
    When hago click en el elemento "Tipo de Permiso" con identificador "$.FORM.combo_tipos"
    Then verifico que el combobox "Tipo de Permiso" tiene la opción "Calamidad doméstica" con identificador "$.FORM.opciones_tipos=Calamidad doméstica"
    And verifico que el combobox "Tipo de Permiso" tiene la opción "Compensatorio" con identificador "$.FORM.opciones_tipos=Compensatorio"
    ```

TABLE STEPS - Verificación con variables:
- verifico que la tabla "Pendientes" tiene "${num_pendientes}" filas con identificador "$.TABLA.tabla_pendientes"
  * Ahora soporta variables usando la sintaxis ${variable_name}
  * Resuelve la variable antes de convertir a entero
  * Ejemplo completo:
    ```gherkin
    When obtengo el texto del elemento "Contador" y lo guardo en la variable "num_pendientes" con identificador "$.TABLA.valor_pendientes"
    Then verifico que la tabla "Pendientes" tiene "${num_pendientes}" filas con identificador "$.TABLA.tabla_pendientes"
    ```

ASSERTION STEPS - Resolución de variables en identificadores:
- debería ver el elemento "Nombre" con identificador "$.MODAL.nombre_empleado=${empleado}"
- no debería ver el elemento "Error" con identificador "$.ALERT.error_message=${tipo_error}"
  * Ahora resuelven variables en el identificador antes de buscar el elemento
  * Soporta placeholders dinámicos en el localizador
  * Ejemplo completo:
    ```gherkin
    When obtengo el texto del elemento "Empleado" y lo guardo en la variable "empleado" con identificador "$.FORM.dato_empleado"
    Then debería ver el elemento "Nombre del empleado" con identificador "$.MODAL.nombre_empleado=${empleado}"
    ```

VALIDATION STEPS - Soporte para textareas e inputs:
- verifico que la longitud del texto del elemento "Observaciones" es "200" con identificador "$.FORM.textarea_observaciones"
- verifico que la longitud del texto del elemento "Comentario" está entre "10" y "500" con identificador "$.FORM.textarea_comentario"
  * Ahora funciona con textareas, inputs y elementos de texto normales
  * Usa input_value() para campos de entrada
  * Fallback a text_content() para elementos normales
  * Ejemplo completo:
    ```gherkin
    When relleno el campo "Observaciones" con "Este es un texto de prueba muy largo..." con identificador "$.FORM.textarea_observaciones"
    Then verifico que la longitud del texto del elemento "Observaciones" es "200" con identificador "$.FORM.textarea_observaciones"
    ```

INTERACTION STEPS - Campos de fecha con eventos de Angular:
- relleno el campo de fecha "Fecha Inicio" con "2026-02-10" con identificador "$.FORM.fecha_inicio"
  * Ahora dispara eventos de Angular: input, change, blur
  * Espera 100ms para que Angular procese los eventos
  * Soluciona problemas con campos de fecha que no gatillan acciones automáticas
  * Soporta formatos DD-MM-YYYY y YYYY-MM-DD
  * Ejemplo completo:
    ```gherkin
    When relleno el campo de fecha "Fecha Inicio" con "10-02-2026" con identificador "$.FORM.fecha_inicio"
    And relleno el campo de fecha "Fecha Fin" con "2026-02-15" con identificador "$.FORM.fecha_fin"
    Then debería ver el elemento "Días calculados" con identificador "$.FORM.dias_calculados"
    ```

KEYBOARD_MOUSE STEPS - Incrementar/decrementar campos numéricos:
- incremento el campo numérico "Días hábiles" "5" veces con identificador "$.FORM.dias_solicitados"
- decremento el campo numérico "Días hábiles" "3" veces con identificador "$.FORM.dias_solicitados"
- aumento el valor del campo "Cantidad" "10" veces con identificador "$.FORM.cantidad"
- disminuyo el valor del campo "Stock" "2" veces con identificador "$.FORM.stock"
  * Simula clicks en las flechas de inputs type="number"
  * Usa ArrowUp para incrementar, ArrowDown para decrementar
  * Espera 50ms entre cada pulsación para que Angular procese
  * Ejemplo completo:
    ```gherkin
    When hago click en el elemento "Días hábiles" con identificador "$.FORM.dias_solicitados"
    And incremento el campo numérico "Días hábiles" "5" veces con identificador "$.FORM.dias_solicitados"
    Then el campo "Días hábiles" debería tener el valor "5" con identificador "$.FORM.dias_solicitados"
    
    When decremento el campo numérico "Días hábiles" "2" veces con identificador "$.FORM.dias_solicitados"
    Then el campo "Días hábiles" debería tener el valor "3" con identificador "$.FORM.dias_solicitados"
    ```

API TESTING STEPS - Escucha de API con limpieza automática:
- inicio la escucha de llamadas a API
- detengo la escucha de llamadas a API
  * Ahora verifica que context.api_calls existe antes de guardar
  * Usa flag api_listening_active para controlar la escucha
  * Evita errores en consola cuando la página persiste entre escenarios
  * Limpieza automática al inicio de cada escenario
  * Ejemplo completo:
    ```gherkin
    Scenario: Verificar llamadas a API
      When inicio la escucha de llamadas a API
      And hago click en el elemento "Cargar datos" con identificador "$.BUTTON.load"
      And espero 2 segundos
      Then verifico que se realizó una llamada a la API en "permisos/solicitudes"
      And detengo la escucha de llamadas a API
    
    Scenario: Otro escenario sin escucha
      # La escucha se limpió automáticamente, no hay errores en consola
      When hago click en el elemento "Guardar" con identificador "$.BUTTON.save"
    ```

ELEMENT_LOCATOR - Placeholders de enteros en XPath:
- <valor>: Agrega comillas al valor (para strings en XPath)
- <valor_int>: No agrega comillas (para índices numéricos en XPath)
  * Ejemplo en JSON:
    ```json
    {
      "check_solicitud": "(//input[@type='checkbox'])[<valor_int>]",
      "nombre_empleado": "//div[contains(text(),<valor>)]"
    }
    ```
  * Ejemplo en feature:
    ```gherkin
    When hago click en el elemento "check solicitud" con identificador "$.FORM.check_solicitud=2"
    # Resultado: (//input[@type='checkbox'])[2]
    
    Then debería ver el elemento "Nombre" con identificador "$.MODAL.nombre_empleado=Juan Pérez"
    # Resultado: //div[contains(text(),'Juan Pérez')]
    ```

GESTIÓN DE SESIÓN DEL NAVEGADOR - Mantener sesión entre escenarios:
  * Los escenarios del mismo feature ahora comparten la sesión del navegador
  * No es necesario hacer login en cada escenario
  * El navegador se cierra solo al finalizar cada feature
  * Cada feature empieza con un navegador limpio
  * Cambia automáticamente al primer tab si hay múltiples tabs abiertos
  * Ejemplo completo:
    ```gherkin
    Feature: Gestión de Permisos
      
      Scenario: Login y crear solicitud
        Given hago login en "${ENV.BASE_URL}" con usuario "${ENV.USER}"
        When creo una nueva solicitud de permiso
        Then debería ver "Solicitud creada exitosamente"
      
      Scenario: Aprobar solicitud (sin login)
        # La sesión se mantiene del escenario anterior
        # No es necesario hacer login de nuevo
        When busco la solicitud pendiente
        And hago click en el botón "Aprobar"
        Then debería ver "Solicitud aprobada"
      
      Scenario: Rechazar solicitud (sin login)
        # La sesión sigue activa
        When busco otra solicitud pendiente
        And hago click en el botón "Rechazar"
        Then debería ver "Solicitud rechazada"
    
    Feature: Gestión de Usuarios
      # Este feature empieza con un navegador limpio
      # Necesita hacer login de nuevo
      
      Scenario: Login como administrador
        Given hago login en "${ENV.BASE_URL}" con usuario "${ENV.ADMIN_USER}"
    ```

CASOS DE USO AVANZADOS
=======================

CASO 1: Verificar opciones de combobox dinámico
```gherkin
Scenario Outline: Verificar tipos de permisos disponibles
  Given hago login en "${ENV.BASE_URL}" con usuario "${ENV.USER}"
  When hago click en el elemento "Nueva Solicitud" con identificador "$.BUTTON.nueva_solicitud"
  And hago click en el elemento "Tipo de Permiso" con identificador "$.FORM.combo_tipos"
  Then verifico que el combobox "Tipo de Permiso" tiene la opción "<tipo>" con identificador "$.FORM.opciones_tipos=<tipo>"
  
  Examples:
    | tipo                |
    | Calamidad doméstica |
    | Compensatorio       |
    | Estudio             |
    | Luto                |
    | Maternidad          |
```

CASO 2: Validar tabla con datos dinámicos
```gherkin
Scenario: Verificar cantidad de solicitudes pendientes
  Given hago login en "${ENV.BASE_URL}" con usuario "${ENV.JEFE}"
  When hago click en el elemento "Solicitudes" con identificador "$.MENU.solicitudes"
  And obtengo el texto del elemento "Contador Pendientes" y lo guardo en la variable "num_pendientes" con identificador "$.TABLA.contador_pendientes"
  Then verifico que la tabla "Solicitudes Pendientes" tiene "${num_pendientes}" filas con identificador "$.TABLA.tabla_pendientes"
```

CASO 3: Formulario con campos de fecha y cálculo automático
```gherkin
Scenario: Crear solicitud de permiso con cálculo de días
  Given hago login en "${ENV.BASE_URL}" con usuario "${ENV.USER}"
  When hago click en el elemento "Nueva Solicitud" con identificador "$.BUTTON.nueva_solicitud"
  And relleno el campo de fecha "Fecha Inicio" con "10-02-2026" con identificador "$.FORM.fecha_inicio"
  And relleno el campo de fecha "Fecha Fin" con "14-02-2026" con identificador "$.FORM.fecha_fin"
  # Angular calcula automáticamente los días
  Then el campo "Días Solicitados" debería tener el valor "5" con identificador "$.FORM.dias_solicitados"
```

CASO 4: Incrementar días usando las flechas del input
```gherkin
Scenario: Ajustar días de permiso usando controles numéricos
  Given hago login en "${ENV.BASE_URL}" con usuario "${ENV.USER}"
  When hago click en el elemento "Nueva Solicitud" con identificador "$.BUTTON.nueva_solicitud"
  And hago click en el elemento "Días Solicitados" con identificador "$.FORM.dias_solicitados"
  And incremento el campo numérico "Días Solicitados" "5" veces con identificador "$.FORM.dias_solicitados"
  Then el campo "Días Solicitados" debería tener el valor "5" con identificador "$.FORM.dias_solicitados"
  
  When decremento el campo numérico "Días Solicitados" "2" veces con identificador "$.FORM.dias_solicitados"
  Then el campo "Días Solicitados" debería tener el valor "3" con identificador "$.FORM.dias_solicitados"
```

CASO 5: Verificar elementos con datos dinámicos
```gherkin
Scenario: Verificar datos del empleado en modal de confirmación
  Given hago login en "${ENV.BASE_URL}" con usuario "${ENV.JEFE}"
  When hago click en el elemento "Solicitudes" con identificador "$.MENU.solicitudes"
  And obtengo el texto del elemento "Empleado" y lo guardo en la variable "empleado" con identificador "$.TABLA.dato_empleado"
  And obtengo el texto del elemento "Tipo Permiso" y lo guardo en la variable "tipo_permiso" con identificador "$.TABLA.dato_tipo_permiso"
  And hago click en el elemento "Aprobar" con identificador "$.BUTTON.aprobar"
  Then debería ver el elemento "Nombre Empleado" con identificador "$.MODAL.nombre_empleado=${empleado}"
  And debería ver el elemento "Tipo Permiso" con identificador "$.MODAL.tipo_permiso=${tipo_permiso}"
```

CASO 6: Escucha de API y validación de respuestas
```gherkin
Scenario: Verificar llamadas a API al cargar solicitudes
  Given hago login en "${ENV.BASE_URL}" con usuario "${ENV.JEFE}"
  When inicio la escucha de llamadas a API
  And hago click en el elemento "Solicitudes" con identificador "$.MENU.solicitudes"
  And espero 2 segundos
  Then verifico que se realizó una llamada a la API en "permisos/solicitudes/equipo/pendientes"
  And verifico que se realizó una llamada a la API en "permisos/tipos"
  And detengo la escucha de llamadas a API
```

CASO 7: Validar longitud de textarea
```gherkin
Scenario: Verificar límite de caracteres en observaciones
  Given hago login en "${ENV.BASE_URL}" con usuario "${ENV.USER}"
  When hago click en el elemento "Nueva Solicitud" con identificador "$.BUTTON.nueva_solicitud"
  And relleno el campo "Observaciones" con "Este es un texto de prueba que tiene exactamente doscientos caracteres para verificar que el límite funciona correctamente en el textarea de observaciones del formulario de solicitud de permisos" con identificador "$.FORM.textarea_observaciones"
  Then verifico que la longitud del texto del elemento "Observaciones" es "200" con identificador "$.FORM.textarea_observaciones"
```

CASO 8: Usar placeholders de enteros en XPath
```gherkin
Scenario: Seleccionar múltiples checkboxes por índice
  Given hago login en "${ENV.BASE_URL}" con usuario "${ENV.JEFE}"
  When hago click en el elemento "Solicitudes" con identificador "$.MENU.solicitudes"
  And hago click en el elemento "check solicitud" con identificador "$.TABLA.check_solicitud=1"
  And hago click en el elemento "check solicitud" con identificador "$.TABLA.check_solicitud=2"
  And hago click en el elemento "check solicitud" con identificador "$.TABLA.check_solicitud=3"
  And hago click en el elemento "Aprobar Seleccionadas" con identificador "$.BUTTON.aprobar_seleccionadas"
  Then debería ver el texto "3 solicitudes aprobadas"
```

MEJORES PRÁCTICAS
==================

1. MANTENER SESIÓN ENTRE ESCENARIOS:
   - Agrupa escenarios relacionados en el mismo feature
   - El primer escenario hace login, los demás reutilizan la sesión
   - Cada feature es independiente y tiene su propia sesión

2. USAR VARIABLES PARA DATOS DINÁMICOS:
   - Extrae valores con "obtengo el texto" y guárdalos en variables
   - Usa ${variable} en identificadores y valores
   - Verifica elementos con datos dinámicos usando variables

3. CAMPOS DE FECHA EN ANGULAR:
   - Usa "relleno el campo de fecha" en lugar de "relleno el campo"
   - Esto dispara los eventos necesarios para Angular
   - Espera a que Angular calcule valores dependientes

4. CAMPOS NUMÉRICOS CON CONTROLES:
   - Usa "incremento/decremento el campo numérico" para simular clicks en flechas
   - Esto dispara eventos de Angular correctamente
   - Más confiable que rellenar el valor directamente

5. VERIFICAR OPCIONES DE COMBOBOX:
   - Usa "verifico que el combobox tiene la opción" después de abrir el select
   - No intentes hacer click en la opción para verificar
   - Esto evita que el select se cierre prematuramente

6. ESCUCHA DE API:
   - Inicia la escucha antes de la acción que genera las llamadas
   - Espera unos segundos para que las llamadas se completen
   - Detén la escucha al final del escenario (opcional, se limpia automáticamente)

7. PLACEHOLDERS EN XPATH:
   - Usa <valor> para strings (agrega comillas automáticamente)
   - Usa <valor_int> para índices numéricos (sin comillas)
   - Define los localizadores en JSON con placeholders

ÚLTIMA ACTUALIZACIÓN: Febrero 2026
VERSIÓN DEL FRAMEWORK: 1.3.0+
TOTAL DE STEPS: 1110+ variantes


================================================================================
ACTUALIZACIONES FEBRERO 2026 - NUEVOS PASOS Y MEJORAS
================================================================================

TABLA STEPS - Verificación con Formatos Múltiples
--------------------------------------------------

verifico que la fila "{row}" de la tabla "{table}" tiene datos con formato con identificador "{identifier}"
  | formato       |
  | button/div    |  # Acepta <button> O <div>
  | string/numero |  # Acepta texto O número
  | fecha         |  # Valida formato de fecha

Formatos soportados:
- Elementos HTML: button, a, link, span, div, p, label, input, textarea, select, strong, em, h1-h6
- Datos: vacio, no_vacio, numero, string, texto, fecha, email, url, cualquiera
- Múltiples: Usa / para aceptar varios formatos (ej: "button/div")

Ejemplo completo:
  Scenario: Verificar tabla con formatos mixtos
    Given voy a la url "https://example.com/tabla"
    Then verifico que la fila "1" de la tabla "Solicitudes" tiene datos con formato con identificador "$.TABLA.solicitudes"
      | formato       |
      | button/div    |
      | string        |
      | fecha         |
      | email/url     |

guardo en la variable "{var}" el valor de la columna "{col}" de la fila "{row}" en la tabla con identificador "{id}"

Ejemplo:
  When guardo en la variable "nombre_usuario" el valor de la columna "2" de la fila "3" en la tabla con identificador "//table[@id='usuarios']//tbody"
  Then verifico que la variable "nombre_usuario" contiene "Juan"

ASSERTION STEPS - Verificación Negativa de Valores
---------------------------------------------------

el campo "{field}" no debería tener el valor "{value}" con identificador "{identifier}"

Ejemplo:
  Scenario: Verificar que un campo no tiene cierto valor
    Given voy a la url "https://example.com/form"
    When relleno el campo "Email" con "user@example.com" con identificador "$.FORM.email"
    Then el campo "Email" no debería tener el valor "admin@example.com" con identificador "$.FORM.email"
    And el campo "Email" no debería tener el valor "${email_prohibido}" con identificador "$.FORM.email"

COMBOBOX STEPS - Selección Mejorada con Eventos de Angular
-----------------------------------------------------------

selecciono la opción "{option}" del combobox "{name}" con identificador "{identifier}"

Mejoras:
- Simula interacción humana completa (hover, focus, mousedown, mouseup, click)
- Dispara TODOS los eventos: input, change, blur, focusout
- Dispara eventos de Angular Material: selectionChange, valueChange
- Espera 200ms para que Angular procese

Ejemplo:
  Scenario: Seleccionar opción de combobox con Angular
    Given voy a la url "https://example.com/form"
    When selecciono la opción "Calamidad doméstica" del combobox "Tipo de Permiso" con identificador "$.FORM.combo_tipo"
    Then el combobox "Tipo de Permiso" tiene seleccionada la opción "Calamidad doméstica" con identificador "$.FORM.combo_tipo"

INTERACTION STEPS - Campos de Fecha con Eventos
------------------------------------------------

relleno el campo de fecha "{field}" con "{date}" con identificador "{identifier}"

Mejoras:
- Dispara eventos de Angular: input, change, blur
- Espera 100ms para que Angular procese
- Soluciona problemas con campos que no gatillan acciones

abro el calendario y relleno el campo de fecha "{field}" con "{date}" con identificador "{identifier}"

Nuevo paso que:
- Presiona Alt+ArrowDown para abrir el calendario nativo
- Luego rellena el campo con la fecha
- Útil para campos que requieren interacción visual

Ejemplo:
  Scenario: Rellenar campo de fecha con eventos
    Given voy a la url "https://example.com/solicitud"
    When relleno el campo de fecha "Fecha Inicio" con "2026-02-06" con identificador "$.FORM.fecha_inicio"
    # O usar el método alternativo:
    When abro el calendario y relleno el campo de fecha "Fecha Inicio" con "2026-02-06" con identificador "$.FORM.fecha_inicio"

KEYBOARD_MOUSE STEPS - Incrementar/Decrementar Campos Numéricos
----------------------------------------------------------------

incremento el campo numérico "{field}" "{times}" veces con identificador "{identifier}"
decremento el campo numérico "{field}" "{times}" veces con identificador "{identifier}"

Ejemplo:
  Scenario: Ajustar días solicitados
    Given voy a la url "https://example.com/solicitud"
    When incremento el campo numérico "Días Solicitados" "5" veces con identificador "$.FORM.dias_solicitados"
    Then el campo "Días Solicitados" debería tener el valor "5" con identificador "$.FORM.dias_solicitados"
    
    When decremento el campo numérico "Días Solicitados" "2" veces con identificador "$.FORM.dias_solicitados"
    Then el campo "Días Solicitados" debería tener el valor "3" con identificador "$.FORM.dias_solicitados"

BROWSER CONTROL STEPS - Ejecución de JavaScript
------------------------------------------------

ejecuto JavaScript "{script}" y guardo el resultado en la variable "{var}"

Ejemplo de una línea:
  When ejecuto JavaScript "document.getElementById('filtroFechaFin').getAttribute('placeholder')" y guardo el resultado en la variable "formato_fecha"

ejecuto el siguiente JavaScript y guardo el resultado en la variable "{var}"
  """
  {código JavaScript multilínea}
  """

Ejemplo multilínea:
  Scenario: Obtener información con JavaScript
    Given voy a la url "https://example.com/filtros"
    When ejecuto el siguiente JavaScript y guardo el resultado en la variable "formato_fecha"
      """
      const input = document.getElementById('filtroFechaFin');
      return input.getAttribute('placeholder') || 'dd-mm-aaaa';
      """
    Then verifico que la variable "formato_fecha" contiene "dd-mm-aaaa"

Características:
- Envuelve automáticamente el código en una función si contiene 'return'
- Soporta variables en el script
- Convierte resultados complejos (dict, list) a JSON

VALIDATION STEPS - Longitud de Texto en Textareas
--------------------------------------------------

verifico que la longitud del texto del elemento "{name}" es "{length}" con identificador "{id}"
verifico que la longitud del texto del elemento "{name}" está entre "{min}" y "{max}" con identificador "{id}"

Mejoras:
- Ahora soporta textareas e inputs usando input_value()
- Fallback a text_content() para elementos normales

Ejemplo:
  Scenario: Verificar longitud de textarea
    Given voy a la url "https://example.com/form"
    When relleno el campo "Observaciones" con "Este es un comentario de prueba" con identificador "$.FORM.textarea_obs"
    Then verifico que la longitud del texto del elemento "Observaciones" es "30" con identificador "$.FORM.textarea_obs"
    And verifico que la longitud del texto del elemento "Observaciones" está entre "20" y "200" con identificador "$.FORM.textarea_obs"

API TESTING STEPS - Escucha de Llamadas con Limpieza Automática
----------------------------------------------------------------

inicio la escucha de llamadas a API
detengo la escucha de llamadas a API

Mejoras:
- Verifica que context.api_calls existe antes de guardar
- Usa flag api_listening_active para controlar la escucha
- Limpieza automática al inicio de cada escenario
- Evita errores en consola cuando la página persiste

Ejemplo:
  Scenario: Monitorear llamadas API
    Given voy a la url "https://example.com/dashboard"
    When inicio la escucha de llamadas a API
    And hago click en el elemento "Cargar Datos" con identificador "$.BUTTONS.cargar"
    Then verifico que se realizó una llamada a la API en "https://api.example.com/data"
    And detengo la escucha de llamadas a API

CASOS DE USO COMPLETOS - EJEMPLOS REALES
=========================================

Caso 1: Verificar Tabla con Elementos HTML Mixtos
--------------------------------------------------

Feature: Verificación de tabla de solicitudes
  Scenario: Validar fila con botones y datos
    Given voy a la url "https://example.com/solicitudes"
    
    # Verificar que la primera fila tiene los formatos correctos
    Then verifico que la fila "1" de la tabla "Solicitudes" tiene datos con formato con identificador "$.TABLA.solicitudes"
      | formato       |
      | button/div    |  # Columna de acciones (puede ser button o div)
      | string        |  # Nombre del solicitante
      | fecha         |  # Fecha de solicitud
      | numero        |  # Días solicitados
      | button/a      |  # Botón de aprobar (puede ser button o link)
    
    # Guardar el nombre del solicitante
    When guardo en la variable "solicitante" el valor de la columna "2" de la fila "1" en la tabla con identificador "$.TABLA.solicitudes//tbody"
    Then verifico que la variable "solicitante" contiene "Juan"

Caso 2: Formulario con Campos de Fecha y Eventos de Angular
------------------------------------------------------------

Feature: Solicitud de vacaciones
  Scenario: Crear solicitud con fechas
    Given voy a la url "https://example.com/nueva-solicitud"
    
    # Rellenar campos básicos
    When selecciono la opción "Vacaciones" del combobox "Tipo de Permiso" con identificador "$.FORM.combo_tipo"
    
    # Rellenar fechas (dispara eventos de Angular)
    And relleno el campo de fecha "Fecha Inicio" con "2026-03-01" con identificador "$.FORM.fecha_inicio"
    And relleno el campo de fecha "Fecha Fin" con "2026-03-15" con identificador "$.FORM.fecha_fin"
    
    # Ajustar días solicitados
    And incremento el campo numérico "Días Solicitados" "14" veces con identificador "$.FORM.dias"
    
    # Verificar que los campos tienen los valores correctos
    Then el campo "Fecha Inicio" debería tener el valor "2026-03-01" con identificador "$.FORM.fecha_inicio"
    And el campo "Días Solicitados" debería tener el valor "14" con identificador "$.FORM.dias"
    
    # Verificar que NO tiene valores incorrectos
    And el campo "Fecha Inicio" no debería tener el valor "2026-02-01" con identificador "$.FORM.fecha_inicio"

Caso 3: Validación con JavaScript y Variables
----------------------------------------------

Feature: Validación de formato de fecha
  Scenario: Verificar placeholder de campo de fecha
    Given voy a la url "https://example.com/filtros"
    
    # Obtener el formato del placeholder con JavaScript
    When ejecuto el siguiente JavaScript y guardo el resultado en la variable "formato_fecha"
      """
      const input = document.getElementById('filtroFechaFin');
      return input.getAttribute('placeholder') || 'dd-mm-aaaa';
      """
    
    # Verificar el formato
    Then verifico que la variable "formato_fecha" contiene "dd-mm-aaaa"
    
    # Usar el formato en otro paso
    And muestro en consola "Formato detectado: ${formato_fecha}"

Caso 4: Gestión de Sesión entre Escenarios
-------------------------------------------

Feature: Navegación con sesión persistente
  # El navegador se mantiene abierto entre escenarios del mismo feature
  
  Scenario: Login
    Given voy a la url "https://example.com/login"
    When relleno el campo "Usuario" con "admin" con identificador "$.LOGIN.usuario"
    And relleno el campo "Contraseña" con "password" con identificador "$.LOGIN.password"
    And hago click en el elemento "Iniciar Sesión" con identificador "$.LOGIN.btn_login"
    Then debería ver el texto "Bienvenido"
  
  Scenario: Navegar a solicitudes (sin login)
    # La sesión se mantiene del escenario anterior
    Given voy a la url "https://example.com/solicitudes"
    Then debería ver el texto "Solicitudes Pendientes"
    # No es necesario hacer login nuevamente

MEJORES PRÁCTICAS - FEBRERO 2026
=================================

1. Usar Múltiples Formatos en Tablas
   - Usa "/" para aceptar varios formatos: "button/div"
   - Útil cuando el HTML puede variar entre versiones

2. Verificar Valores Negativos
   - Usa "no debería tener el valor" para validaciones negativas
   - Más claro que verificar que el valor es diferente

3. Disparar Eventos de Angular
   - Los pasos de fecha y combobox ahora disparan eventos automáticamente
   - No necesitas pasos adicionales para gatillar acciones

4. Ejecutar JavaScript Complejo
   - Usa el paso multilínea para scripts complejos
   - El framework envuelve automáticamente el código en una función

5. Aprovechar la Sesión Persistente
   - Los escenarios del mismo feature comparten sesión
   - Haz login una vez y reutiliza la sesión
   - Cada feature empieza con navegador limpio

6. Nombres de Reportes Descriptivos
   - Los reportes ahora incluyen el tag del escenario
   - Formato: Reporte_MVYPKC-391_06022026_1815.html
   - Fácil de identificar en Jira

7. Integración con Jira Mejorada
   - Los reportes se suben a los issues de los ESCENARIOS
   - No solo al issue del feature
   - Mejor trazabilidad de resultados

================================================================================
FIN DE ACTUALIZACIONES FEBRERO 2026
================================================================================
