===========================================
GUÍA COMPLETA DE USO
HAKA PLAYWRIGHT ENGINE v1.3.17
===========================================

Esta guía responde todas las preguntas frecuentes sobre el uso del framework,
incluyendo variables, datos, steps personalizados y todas las particularidades.

TABLA DE CONTENIDOS
===================

1. INTRODUCCIÓN
2. VARIABLES Y DATOS
3. LOCALIZADORES DE ELEMENTOS
4. ESTRUCTURA DE FEATURES
5. STEPS PERSONALIZADOS
6. CONFIGURACIÓN
7. INTEGRACIONES
8. CASOS DE USO
9. TROUBLESHOOTING
10. REFERENCIA RÁPIDA

===========================================
CAPÍTULO 1: INTRODUCCIÓN
===========================================

¿QUÉ ES HAKA PLAYWRIGHT ENGINE?
--------------------------------

Haka Playwright Engine es un framework completo de testing funcional que combina:
- Playwright: Automatización web moderna y confiable
- Behave: Framework BDD (Behavior Driven Development) para Python
- Gherkin: Lenguaje natural para escribir tests

ARQUITECTURA GENERAL
--------------------

El framework está organizado en capas:

1. CAPA DE FEATURES (.feature)
   - Archivos Gherkin con scenarios de prueba
   - Lenguaje natural (español o inglés)
   - Ubicación: features/

2. CAPA DE STEPS (steps/)
   - Implementación de cada paso
   - 674 steps predefinidos
   - Steps personalizados en features/steps/

3. CAPA DE CORE (core/)
   - Variable Manager: Manejo de variables
   - Element Locator: Localización de elementos
   - Context Helpers: Utilidades de contexto

4. CAPA DE CONFIGURACIÓN
   - .env: Variables de entorno
   - behave.ini: Configuración de Behave
   - environment.py: Hooks y setup

CONCEPTOS BÁSICOS
-----------------

FEATURE: Archivo que describe una funcionalidad a testear
SCENARIO: Caso de prueba específico
STEP: Acción o verificación individual
CONTEXT: Objeto que comparte datos entre steps
VARIABLE: Dato almacenado para usar en múltiples steps


===========================================
CAPÍTULO 2: VARIABLES Y DATOS
===========================================

PREGUNTA 1: ¿Cómo creo una variable?
-------------------------------------

HAY 3 FORMAS DE CREAR VARIABLES:

FORMA 1: Crear variable con valor fijo
```gherkin
Given creo la variable "nombre_usuario" con valor "Juan Pérez"
Given establezco "email" = "juan@example.com"
```

FORMA 2: Generar variable aleatoria
```gherkin
# Texto aleatorio
Given genero una variable "codigo" con texto aleatorio de 10 caracteres

# Número aleatorio
Given genero una variable "edad" con número aleatorio entre 18 y 65

# Timestamp
Given genero una variable "timestamp" con timestamp actual
```

FORMA 3: Guardar dato de un step
```gherkin
# Desde API
When realizo una petición GET a "${API_URL}/users/1"
And extraigo el valor "name" del JSON de respuesta y lo guardo en "nombre"

# Desde elemento web
When obtengo el texto del elemento "titulo" y lo guardo en "texto_titulo" con identificador "id"
```

PREGUNTA 2: ¿Cómo uso una variable?
------------------------------------

USA LA SINTAXIS ${variable_name}

```gherkin
# Crear variable
Given creo la variable "usuario" con valor "admin"

# Usar variable en URL
When voy a la url "${BASE_URL}/users/${usuario}"

# Usar variable en formulario
When relleno el campo "username" con "${usuario}" con identificador "id"

# Usar variable en validación
Then debería ver el texto "Bienvenido ${usuario}"
```

PREGUNTA 3: ¿Cómo guardo datos durante la ejecución?
-----------------------------------------------------

MÉTODO 1: Guardar en variable desde API
```gherkin
Scenario: Crear usuario y usar su ID
  # Crear usuario
  When realizo una petición POST a "${API_URL}/users" con el body:
    """
    {
      "name": "Juan",
      "email": "juan@test.com"
    }
    """
  # Guardar el ID del usuario creado
  And extraigo el valor "id" del JSON de respuesta y lo guardo en "user_id"
  
  # Usar el ID en otra petición
  When realizo una petición GET a "${API_URL}/users/${user_id}"
  Then el código de estado de la respuesta debería ser 200
```

MÉTODO 2: Guardar desde elemento web
```gherkin
Scenario: Extraer y validar datos
  Given voy a la url "${BASE_URL}/dashboard"
  
  # Extraer texto de un elemento
  When obtengo el texto del elemento "saldo" y lo guardo en "saldo_actual" con identificador "id"
  
  # Usar el dato extraído
  Then verifico que la variable "saldo_actual" contiene "$"
```

MÉTODO 3: Guardar desde CSV
```gherkin
Scenario: Procesar datos de CSV
  # Cargar CSV
  Given cargo el archivo CSV "datos/usuarios.csv" en la variable "usuarios"
  
  # Obtener valor específico
  When obtengo el valor de la fila 0 columna "email" del CSV "usuarios" y lo guardo en "primer_email"
  
  # Usar el dato
  When relleno el campo "email" con "${primer_email}" con identificador "id"
```

PREGUNTA 4: ¿Cómo uso variables de entorno?
--------------------------------------------

PASO 1: Definir en archivo .env
```bash
# .env
BASE_URL=https://example.com
TEST_USER=admin
TEST_PASSWORD=secret123
API_KEY=abc123xyz
```

PASO 2: Usar en features
```gherkin
Scenario: Login con credenciales de .env
  Given voy a la url "${BASE_URL}/login"
  When relleno el campo "username" con "${TEST_USER}" con identificador "id"
  And relleno el campo "password" con "${TEST_PASSWORD}" con identificador "id"
  And hago click en el elemento "login_button" con identificador "id"
  Then la url actual debería contener "dashboard"
```

PASO 3: Usar en API Testing
```gherkin
Scenario: Petición autenticada
  Given establezco el header de API "Authorization" a "Bearer ${API_KEY}"
  When realizo una petición GET a "${BASE_URL}/api/users"
  Then el código de estado de la respuesta debería ser 200
```

PREGUNTA 5: ¿Cuál es el scope de las variables?
------------------------------------------------

HAY 3 NIVELES DE SCOPE:

NIVEL 1: SCENARIO SCOPE (por defecto)
- La variable existe solo en el scenario actual
- Se destruye al terminar el scenario

```gherkin
Scenario: Scope de scenario
  Given creo la variable "temp" con valor "test"
  Then verifico que la variable "temp" contiene "test"
  # ✅ Funciona

Scenario: Otro scenario
  Then verifico que la variable "temp" contiene "test"
  # ❌ Error: variable no existe
```

NIVEL 2: FEATURE SCOPE (usando Background)
- La variable se crea en Background
- Disponible para todos los scenarios del feature

```gherkin
Feature: Testing con datos compartidos

  Background:
    Given creo la variable "base_url" con valor "https://example.com"
  
  Scenario: Test 1
    When voy a la url "${base_url}/page1"
    # ✅ Funciona
  
  Scenario: Test 2
    When voy a la url "${base_url}/page2"
    # ✅ Funciona
```

NIVEL 3: GLOBAL SCOPE (variables de entorno)
- Definidas en .env
- Disponibles en todos los features

```bash
# .env
GLOBAL_VAR=valor_global
```

```gherkin
# feature1.feature
Scenario: Test en feature 1
  Then verifico que la variable "GLOBAL_VAR" contiene "valor_global"
  # ✅ Funciona

# feature2.feature
Scenario: Test en feature 2
  Then verifico que la variable "GLOBAL_VAR" contiene "valor_global"
  # ✅ Funciona
```

PREGUNTA 6: ¿Cómo comparto datos entre scenarios?
--------------------------------------------------

OPCIÓN 1: Usar Background (recomendado)
```gherkin
Feature: Compartir datos

  Background:
    Given creo la variable "token" con valor "abc123"
  
  Scenario: Usar token en test 1
    When establezco el header de API "Authorization" a "Bearer ${token}"
  
  Scenario: Usar token en test 2
    When establezco el header de API "Authorization" a "Bearer ${token}"
```

OPCIÓN 2: Usar variables de entorno
```bash
# .env
SHARED_TOKEN=abc123
```

```gherkin
Scenario: Test 1
  When establezco el header de API "Authorization" a "Bearer ${SHARED_TOKEN}"

Scenario: Test 2
  When establezco el header de API "Authorization" a "Bearer ${SHARED_TOKEN}"
```

OPCIÓN 3: Usar archivos externos
```gherkin
Scenario: Test 1
  Given cargo JSON del archivo "datos/config.json" en la variable "config"
  # Todos los scenarios pueden cargar el mismo archivo

Scenario: Test 2
  Given cargo JSON del archivo "datos/config.json" en la variable "config"
```

PREGUNTA 7: ¿Cómo uso variables anidadas?
------------------------------------------

PUEDES ANIDAR VARIABLES USANDO ${variable}

```gherkin
Scenario: Variables anidadas
  # Crear variables base
  Given creo la variable "ambiente" con valor "staging"
  And creo la variable "url_staging" con valor "https://staging.example.com"
  And creo la variable "url_production" con valor "https://example.com"
  
  # Usar variable anidada
  When voy a la url "${url_${ambiente}}"
  # Resultado: https://staging.example.com
```

EJEMPLO COMPLETO: Sistema de Login
-----------------------------------

```gherkin
Feature: Sistema de Login

  Background:
    # Variables de entorno desde .env
    Given voy a la url "${BASE_URL}/login"
  
  Scenario: Login exitoso con datos generados
    # Generar datos de prueba
    Given genero una variable "email" con texto aleatorio de 10 caracteres
    And creo la variable "email_completo" con valor "${email}@test.com"
    And genero una variable "password" con texto aleatorio de 12 caracteres
    
    # Registrar usuario
    When realizo una petición POST a "${BASE_URL}/api/register" con el body:
      """
      {
        "email": "${email_completo}",
        "password": "${password}"
      }
      """
    Then el código de estado de la respuesta debería ser 201
    And extraigo el valor "id" del JSON de respuesta y lo guardo en "user_id"
    
    # Login con credenciales generadas
    When relleno el campo "email" con "${email_completo}" con identificador "id"
    And relleno el campo "password" con "${password}" con identificador "id"
    And hago click en el elemento "login_button" con identificador "id"
    
    # Validar login exitoso
    Then la url actual debería contener "dashboard"
    And debería ver el texto "Bienvenido"
    
    # Guardar token de sesión
    When obtengo el valor de localStorage "auth_token" y lo guardo en "session_token"
    
    # Usar token en API
    When establezco el header de API "Authorization" a "Bearer ${session_token}"
    And realizo una petición GET a "${BASE_URL}/api/users/${user_id}"
    Then el código de estado de la respuesta debería ser 200
```


===========================================
CAPÍTULO 3: LOCALIZADORES DE ELEMENTOS
===========================================

PREGUNTA 1: ¿Qué es la sintaxis $.ARCHIVO.elemento?
----------------------------------------------------

ES UN SISTEMA DE PAGE OBJECT MODEL (POM) EN JSON

En lugar de escribir selectores CSS/XPath directamente en los features,
los defines en archivos JSON y los referencias con $.ARCHIVO.elemento

VENTAJAS:
✅ Mantenimiento centralizado
✅ Reutilización de selectores
✅ Features más legibles
✅ Cambios en un solo lugar

PREGUNTA 2: ¿Cómo creo archivos JSON POM?
------------------------------------------

PASO 1: Crear archivo en json_poms/

Archivo: json_poms/LOGIN.json
```json
{
  "email_field": "#email",
  "password_field": "#password",
  "login_button": "button[type='submit']",
  "error_message": "//div[@class='error']"
}
```

NOTA IMPORTANTE:
✅ Formato CORRECTO: Valor directo como string
   "elemento": "selector_aqui"

❌ Formato INCORRECTO: No usar objetos con "selector" y "type"
   "elemento": {"selector": "...", "type": "..."}  # NO FUNCIONA

El framework detecta automáticamente si es CSS o XPath:
- Si empieza con "//" o "(" → XPath
- Si no → CSS

PASO 2: Usar en features
```gherkin
Scenario: Login
  When relleno el campo "email" con "test@example.com" con identificador "$.LOGIN.email_field"
  And relleno el campo "password" con "secret" con identificador "$.LOGIN.password_field"
  And hago click en el elemento "login_button" con identificador "$.LOGIN.login_button"
```

PREGUNTA 2.1: ¿Cómo uso FALLBACKS para selectores más robustos?
----------------------------------------------------------------

NUEVO: Puedes definir selectores con fallbacks automáticos para mayor robustez.
Si el selector principal falla, el framework intentará automáticamente los fallbacks.

Archivo: json_poms/LOGIN.json
```json
{
  "email_field": "#email",
  "password_field": "#password",
  
  "submit_button": {
    "selector": "button[type='submit']",
    "fallbacks": [
      "#login-button",
      "//button[contains(text(), 'Login')]",
      "button.btn-primary"
    ]
  },
  
  "error_message": {
    "selector": ".error-message",
    "fallbacks": [
      "//div[@class='error']",
      "[data-testid='error']"
    ]
  }
}
```

CÓMO FUNCIONA:
1. El framework intenta el selector principal primero
2. Si no encuentra el elemento, prueba el primer fallback
3. Si tampoco funciona, prueba el segundo fallback
4. Y así sucesivamente hasta encontrar el elemento

VENTAJAS:
✅ Mayor robustez ante cambios en la UI
✅ Soporta múltiples versiones de la aplicación
✅ Reduce falsos negativos en pruebas
✅ Automático - no necesitas cambiar tus steps

USO EN FEATURES (igual que antes):
```gherkin
Scenario: Login con fallbacks automáticos
  When relleno el campo "email" con "test@example.com" con identificador "$.LOGIN.email_field"
  And hago click en el elemento "submit_button" con identificador "$.LOGIN.submit_button"
  # Si button[type='submit'] no existe, probará automáticamente #login-button, luego //button[contains...], etc.
```

CUÁNDO USAR FALLBACKS:
✅ Elementos que cambian frecuentemente
✅ Aplicaciones con múltiples versiones
✅ Elementos con selectores inestables
✅ Testing cross-browser con diferencias de DOM

CUÁNDO NO USAR FALLBACKS:
❌ Elementos estables que nunca cambian
❌ Cuando quieres detectar cambios en la UI
❌ Selectores únicos y confiables

PREGUNTA 3: ¿Cuándo usar CSS vs XPath?
---------------------------------------

USA CSS CUANDO:
✅ El elemento tiene ID o clase
✅ Necesitas seleccionar por atributos simples
✅ Quieres mejor performance
✅ El selector es simple

EJEMPLOS CSS:
```json
{
  "por_id": {
    "selector": "#mi-elemento",
    "type": "css"
  },
  "por_clase": {
    "selector": ".mi-clase",
    "type": "css"
  },
  "por_atributo": {
    "selector": "[data-test='boton']",
    "type": "css"
  },
  "combinado": {
    "selector": "div.container > button#submit",
    "type": "css"
  }
}
```

USA XPATH CUANDO:
✅ Necesitas navegar hacia arriba en el DOM (parent)
✅ Necesitas seleccionar por texto
✅ Necesitas lógica compleja (contains, starts-with)
✅ CSS no es suficiente

EJEMPLOS XPATH:
```json
{
  "por_texto": {
    "selector": "//button[text()='Enviar']",
    "type": "xpath"
  },
  "contiene_texto": {
    "selector": "//div[contains(text(), 'Error')]",
    "type": "xpath"
  },
  "parent": {
    "selector": "//input[@id='email']/parent::div",
    "type": "xpath"
  },
  "siguiente_hermano": {
    "selector": "//label[text()='Email']/following-sibling::input",
    "type": "xpath"
  }
}
```

PREGUNTA 4: ¿Cómo uso localizadores dinámicos?
-----------------------------------------------

USA PLACEHOLDERS CON =valor

EJEMPLO: Seleccionar fila de tabla por ID

Archivo: json_poms/TABLA.json
```json
{
  "fila_por_id": {
    "selector": "tr[data-id='{{id}}']",
    "type": "css"
  },
  "boton_editar": {
    "selector": "//tr[@data-id='{{id}}']//button[text()='Editar']",
    "type": "xpath"
  }
}
```

Uso en feature:
```gherkin
Scenario: Editar usuario específico
  # Usar localizador dinámico
  When hago click en el elemento "boton_editar" con identificador "$.TABLA.boton_editar=123"
  # Resultado: Busca tr[data-id='123']//button[text()='Editar']
```

EJEMPLO COMPLETO: Formulario dinámico
```json
{
  "campo_por_nombre": {
    "selector": "input[name='{{field_name}}']",
    "type": "css"
  },
  "error_campo": {
    "selector": "//input[@name='{{field_name}}']/following-sibling::span[@class='error']",
    "type": "xpath"
  }
}
```

```gherkin
Scenario: Validar errores de formulario
  When relleno el campo "email" con "invalido" con identificador "$.FORM.campo_por_nombre=email"
  And hago click en el elemento "submit" con identificador "id"
  Then debería ver el elemento "error" con identificador "$.FORM.error_campo=email"
```

PREGUNTA 5: ¿Qué hacer si un elemento no se encuentra?
-------------------------------------------------------

ESTRATEGIA 1: Usar múltiples selectores (fallback)
```json
{
  "boton_submit": {
    "selector": "#submit-btn",
    "type": "css",
    "fallback": [
      {
        "selector": "button[type='submit']",
        "type": "css"
      },
      {
        "selector": "//button[contains(text(), 'Enviar')]",
        "type": "xpath"
      }
    ]
  }
}
```

ESTRATEGIA 2: Esperar a que aparezca
```gherkin
# Esperar hasta 30 segundos
When espero a que el elemento "boton" sea visible con identificador "$.PAGE.boton"
```

ESTRATEGIA 3: Verificar si existe antes de interactuar
```gherkin
# Verificar existencia
Then el elemento "boton" debería estar visible con identificador "$.PAGE.boton"

# Si existe, hacer click
When hago click en el elemento "boton" con identificador "$.PAGE.boton"
```

ESTRATEGIA 4: Usar localizadores más robustos
```json
{
  "boton_robusto": {
    "selector": "[data-testid='submit-button']",
    "type": "css"
  }
}
```

MEJORES PRÁCTICAS PARA LOCALIZADORES
-------------------------------------

1. PRIORIDAD DE SELECTORES (de mejor a peor):
   1. data-testid (agregado específicamente para testing)
   2. ID único
   3. Clase específica
   4. Atributos únicos
   5. XPath por texto (último recurso)

2. EVITAR:
   ❌ Selectores frágiles: div > div > div > button
   ❌ Índices: :nth-child(3)
   ❌ Clases generadas: .css-abc123
   ❌ XPath absolutos: /html/body/div[1]/div[2]/button

3. PREFERIR:
   ✅ Atributos de testing: [data-testid='submit']
   ✅ IDs semánticos: #login-button
   ✅ Clases semánticas: .submit-button
   ✅ Atributos ARIA: [aria-label='Submit']

EJEMPLO COMPLETO: Page Object Model
------------------------------------

Archivo: json_poms/ECOMMERCE.json
```json
{
  "buscador": {
    "selector": "#search-input",
    "type": "css"
  },
  "boton_buscar": {
    "selector": "button[aria-label='Search']",
    "type": "css"
  },
  "producto_por_nombre": {
    "selector": "//div[@class='product'][.//h3[contains(text(), '{{nombre}}')]]",
    "type": "xpath"
  },
  "boton_agregar_carrito": {
    "selector": "//div[@class='product'][.//h3[contains(text(), '{{nombre}}')]]//button[text()='Add to Cart']",
    "type": "xpath"
  },
  "contador_carrito": {
    "selector": ".cart-count",
    "type": "css"
  },
  "total_carrito": {
    "selector": "#cart-total",
    "type": "css"
  }
}
```

Feature usando el POM:
```gherkin
Feature: Compra en E-commerce

  Background:
    Given voy a la url "${BASE_URL}"
  
  Scenario: Buscar y agregar producto al carrito
    # Buscar producto
    When relleno el campo "buscador" con "Laptop" con identificador "$.ECOMMERCE.buscador"
    And hago click en el elemento "boton_buscar" con identificador "$.ECOMMERCE.boton_buscar"
    And espero 2 segundos
    
    # Verificar que aparece el producto
    Then debería ver el elemento "producto" con identificador "$.ECOMMERCE.producto_por_nombre=Laptop"
    
    # Agregar al carrito
    When hago click en el elemento "agregar" con identificador "$.ECOMMERCE.boton_agregar_carrito=Laptop"
    And espero 1 segundos
    
    # Verificar contador de carrito
    Then el elemento "contador" debería contener el texto "1" con identificador "$.ECOMMERCE.contador_carrito"
    
    # Verificar total
    When obtengo el texto del elemento "total" y lo guardo en "total_carrito" con identificador "$.ECOMMERCE.total_carrito"
    Then verifico que la variable "total_carrito" contiene "$"
```


===========================================
CAPÍTULO 5: STEPS PERSONALIZADOS
===========================================

PREGUNTA 1: ¿Cómo creo un step personalizado?
----------------------------------------------

PASO 1: Crear archivo en features/steps/

Archivo: features/steps/custom_steps.py
```python
from behave import step

@step('verifico que el usuario "{username}" tiene permisos de "{role}"')
def step_verify_user_role(context, username, role):
    """Verifica que un usuario tiene un rol específico"""
    # Tu lógica aquí
    api_url = f"{context.base_url}/api/users/{username}/roles"
    response = context.api_client.get(api_url)
    
    assert role in response.json()['roles'], \
        f"Usuario {username} no tiene rol {role}"
    
    print(f"✅ Usuario {username} tiene rol {role}")
```

PASO 2: Usar en feature
```gherkin
Scenario: Verificar permisos
  When verifico que el usuario "admin" tiene permisos de "administrator"
```

PREGUNTA 2: ¿Cuál es la estructura de un step?
-----------------------------------------------

ANATOMÍA DE UN STEP:

```python
from behave import step  # 1. Importar decorador

@step('mi paso con "{parametro1}" y "{parametro2}"')  # 2. Decorador con texto
def step_mi_paso_personalizado(context, parametro1, parametro2):  # 3. Función
    """Descripción de qué hace el step"""  # 4. Docstring
    
    # 5. Acceder a datos del context
    page = context.page
    variable_manager = context.variable_manager
    
    # 6. Resolver variables
    valor1 = variable_manager.resolve_variables(parametro1)
    valor2 = variable_manager.resolve_variables(parametro2)
    
    # 7. Lógica del step
    # ... tu código aquí ...
    
    # 8. Guardar datos en context si es necesario
    context.mi_dato = "valor"
    
    # 9. Imprimir resultado (opcional)
    print(f"✅ Step ejecutado correctamente")
```

PREGUNTA 3: ¿Cómo accedo al context?
-------------------------------------

EL CONTEXT TIENE ACCESO A TODO:

```python
@step('mi step personalizado')
def step_custom(context):
    # NAVEGADOR
    page = context.page  # Página de Playwright
    browser = context.browser  # Navegador
    
    # VARIABLES
    variable_manager = context.variable_manager
    valor = variable_manager.get_variable('mi_variable')
    variable_manager.set_variable('nueva_var', 'valor')
    
    # LOCALIZADOR DE ELEMENTOS
    element_locator = context.element_locator
    elemento = element_locator.find(page, '$.ARCHIVO.elemento')
    
    # CONFIGURACIÓN
    base_url = context.base_url  # Desde .env
    timeout = context.timeout
    
    # DATOS DEL SCENARIO
    scenario_name = context.scenario.name
    feature_name = context.feature.name
    
    # DATOS PERSONALIZADOS
    # Puedes agregar tus propios datos
    context.mi_dato_custom = "valor"
```

PREGUNTA 4: ¿Cómo uso parámetros en steps?
-------------------------------------------

HAY 3 TIPOS DE PARÁMETROS:

TIPO 1: Parámetros de texto (string)
```python
@step('verifico el mensaje "{mensaje}"')
def step_verify_message(context, mensaje):
    # mensaje es un string
    assert mensaje in context.page.content()
```

TIPO 2: Parámetros numéricos (int, float)
```python
@step('espero {segundos:d} segundos')
def step_wait_seconds(context, segundos):
    # segundos es un int
    context.page.wait_for_timeout(segundos * 1000)

@step('verifico que el precio es {precio:f}')
def step_verify_price(context, precio):
    # precio es un float
    assert precio > 0
```

TIPO 3: Parámetros con texto multilínea
```python
@step('envío el siguiente JSON')
def step_send_json(context):
    # context.text contiene el texto multilínea
    json_data = context.text
    # Usar json_data...
```

Uso en feature:
```gherkin
When envío el siguiente JSON
  """
  {
    "name": "Juan",
    "email": "juan@test.com"
  }
  """
```

PREGUNTA 5: ¿Cómo registro mis steps personalizados?
-----------------------------------------------------

NO NECESITAS REGISTRO MANUAL

Behave automáticamente encuentra todos los archivos .py en:
- features/steps/
- Cualquier subdirectorio de features/steps/

ESTRUCTURA RECOMENDADA:
```
features/
├── steps/
│   ├── __init__.py  (vacío)
│   ├── custom_login_steps.py
│   ├── custom_api_steps.py
│   └── custom_validation_steps.py
├── login.feature
└── api_tests.feature
```

PREGUNTA 6: ¿Cómo evito conflictos con steps existentes?
---------------------------------------------------------

REGLA DE ORO: USA PALABRAS CLAVE ÚNICAS

❌ MAL (conflicto con step existente):
```python
@step('verifico que el elemento "{name}" está visible')
def my_step(context, name):
    pass
# ❌ Ya existe un step similar en el framework
```

✅ BIEN (palabra clave única):
```python
@step('verifico en mi aplicación que el elemento "{name}" está visible')
def my_step(context, name):
    pass
# ✅ "en mi aplicación" hace el step único
```

MEJORES PRÁCTICAS:
1. Agrega prefijo único: "en mi app", "para mi sistema", etc.
2. Usa nombres descriptivos específicos de tu dominio
3. Revisa steps existentes antes de crear nuevos

EJEMPLOS DE STEPS PERSONALIZADOS
---------------------------------

EJEMPLO 1: Step para login específico de tu app
```python
from behave import step

@step('inicio sesión en mi aplicación como "{role}"')
def step_login_as_role(context, role):
    """Login con credenciales según el rol"""
    # Mapeo de roles a credenciales
    credentials = {
        'admin': ('admin@app.com', 'admin123'),
        'user': ('user@app.com', 'user123'),
        'guest': ('guest@app.com', 'guest123')
    }
    
    email, password = credentials.get(role, ('', ''))
    
    # Usar steps existentes del framework
    context.execute_steps(f'''
        Given voy a la url "${{BASE_URL}}/login"
        When relleno el campo "email" con "{email}" con identificador "id"
        And relleno el campo "password" con "{password}" con identificador "id"
        And hago click en el elemento "login_button" con identificador "id"
        Then la url actual debería contener "dashboard"
    ''')
    
    print(f"✅ Login exitoso como {role}")
```

Uso:
```gherkin
Scenario: Test como admin
  Given inicio sesión en mi aplicación como "admin"
  # Ya estás logueado
```

EJEMPLO 2: Step para validación de negocio
```python
@step('verifico que el pedido "{order_id}" está en estado "{expected_status}"')
def step_verify_order_status(context, order_id, expected_status):
    """Verifica el estado de un pedido via API"""
    # Resolver variables
    order_id = context.variable_manager.resolve_variables(order_id)
    
    # Llamar a API
    api_url = f"{context.base_url}/api/orders/{order_id}"
    response = context.api_client.get(api_url)
    
    # Validar
    actual_status = response.json()['status']
    assert actual_status == expected_status, \
        f"Pedido {order_id}: esperado '{expected_status}', actual '{actual_status}'"
    
    # Guardar datos para uso posterior
    context.variable_manager.set_variable('order_status', actual_status)
    context.variable_manager.set_variable('order_total', response.json()['total'])
    
    print(f"✅ Pedido {order_id} en estado {actual_status}")
```

Uso:
```gherkin
Scenario: Verificar pedido
  When verifico que el pedido "${order_id}" está en estado "completed"
  Then verifico que la variable "order_total" es mayor que "0"
```

EJEMPLO 3: Step con lógica compleja
```python
@step('proceso el carrito de compras y verifico el total')
def step_process_cart(context):
    """Calcula el total del carrito y lo valida"""
    # Obtener todos los items del carrito
    items = context.page.locator('.cart-item').all()
    
    total_calculado = 0
    for item in items:
        # Extraer precio y cantidad
        precio_text = item.locator('.price').inner_text()
        cantidad_text = item.locator('.quantity').inner_text()
        
        # Limpiar y convertir
        precio = float(precio_text.replace('$', '').replace(',', ''))
        cantidad = int(cantidad_text)
        
        # Sumar al total
        total_calculado += precio * cantidad
    
    # Obtener total mostrado
    total_mostrado_text = context.page.locator('#cart-total').inner_text()
    total_mostrado = float(total_mostrado_text.replace('$', '').replace(',', ''))
    
    # Validar
    assert abs(total_calculado - total_mostrado) < 0.01, \
        f"Total calculado ${total_calculado} != Total mostrado ${total_mostrado}"
    
    # Guardar para uso posterior
    context.variable_manager.set_variable('cart_total', str(total_mostrado))
    
    print(f"✅ Total del carrito validado: ${total_mostrado}")
```

EJEMPLO 4: Step que usa otros steps
```python
@step('completo el flujo de checkout con datos de prueba')
def step_complete_checkout(context):
    """Completa todo el flujo de checkout"""
    # Generar datos de prueba
    import random
    card_number = f"4532{random.randint(1000, 9999)}{random.randint(1000, 9999)}{random.randint(1000, 9999)}"
    
    # Ejecutar múltiples steps
    context.execute_steps(f'''
        When relleno el campo "card_number" con "{card_number}" con identificador "id"
        And relleno el campo "card_name" con "Test User" con identificador "id"
        And relleno el campo "card_expiry" con "12/25" con identificador "id"
        And relleno el campo "card_cvv" con "123" con identificador "id"
        And hago click en el elemento "submit_payment" con identificador "id"
        And espero 3 segundos
        Then debería ver el texto "Pago exitoso"
    ''')
    
    print("✅ Checkout completado")
```

===========================================
CAPÍTULO 6: CONFIGURACIÓN
===========================================

PREGUNTA 1: ¿Qué va en el archivo .env?
----------------------------------------

EL ARCHIVO .env CONTIENE TODAS LAS CONFIGURACIONES

```bash
# === NAVEGADOR ===
BROWSER=chromium              # chromium, firefox, webkit
HEADLESS=false               # true/false
TIMEOUT=30000                # Timeout en milisegundos
WINDOW_SIZE=1920,1080        # Tamaño de ventana

# === URLS Y AMBIENTES ===
BASE_URL=https://example.com
API_URL=https://api.example.com
STAGING_URL=https://staging.example.com

# === CREDENCIALES ===
TEST_USER=admin@test.com
TEST_PASSWORD=secret123
API_KEY=abc123xyz

# === GEMINI AI ===
GEMINI_API_KEY=tu_api_key
GEMINI_JUDGE_MODEL=gemini-1.5-pro-002
GEMINI_CACHE_THRESHOLD=32000

# === SUPABASE ===
SUPABASE_URL=https://tu-proyecto.supabase.co
SUPABASE_KEY=tu_supabase_key

# === JIRA/XRAY ===
JIRA_ENABLED=true
JIRA_URL=https://empresa.atlassian.net
JIRA_EMAIL=tu-email@empresa.com
JIRA_TOKEN=tu_jira_token
JIRA_PROJECT=PROJ

# === REPORTES ===
SCREENSHOTS_DIR=screenshots
HTML_REPORTS_DIR=html-reports
VIDEO_RECORDING=false
SCREENSHOT_FULL_PAGE=true

# === RUTAS ===
JSON_POMS_PATH=json_poms
DOWNLOADS_DIR=downloads
```

PREGUNTA 2: ¿Cómo configuro diferentes ambientes?
--------------------------------------------------

OPCIÓN 1: Múltiples archivos .env
```bash
# .env.staging
BASE_URL=https://staging.example.com
API_URL=https://api-staging.example.com

# .env.production
BASE_URL=https://example.com
API_URL=https://api.example.com
```

Ejecutar con ambiente específico:
```bash
# Linux/Mac
export ENV_FILE=.env.staging
behave

# Windows
set ENV_FILE=.env.staging
behave
```

OPCIÓN 2: Variables en .env
```bash
# .env
ENVIRONMENT=staging
STAGING_URL=https://staging.example.com
PRODUCTION_URL=https://example.com
```

Usar en features:
```gherkin
Scenario: Test en ambiente dinámico
  Given voy a la url "${${ENVIRONMENT}_URL}"
```

PREGUNTA 3: ¿Cómo cambio el navegador?
---------------------------------------

CAMBIAR EN .env:
```bash
BROWSER=chromium  # chromium, firefox, webkit
```

O EJECUTAR CON PARÁMETRO:
```bash
behave -D browser=firefox
```

CONFIGURACIÓN AVANZADA DE NAVEGADOR:
```bash
# .env
BROWSER=chromium
HEADLESS=false
SLOW_MO=100                  # Ralentizar acciones (ms)
WINDOW_SIZE=1920,1080
DEVICE_SCALE_FACTOR=2        # Para retina displays
LOCALE=es-ES                 # Idioma del navegador
TIMEZONE=America/Mexico_City # Zona horaria
```

PREGUNTA 4: ¿Cómo configuro timeouts?
--------------------------------------

HAY 3 TIPOS DE TIMEOUTS:

TIMEOUT GLOBAL (para todo):
```bash
# .env
TIMEOUT=30000  # 30 segundos
```

TIMEOUT POR STEP:
```gherkin
# Esperar hasta 60 segundos para este elemento
When espero a que el elemento "slow_element" sea visible con identificador "id"
```

TIMEOUT PERSONALIZADO EN STEP:
```python
@step('espero elemento lento "{name}"')
def step_wait_slow(context, name):
    # Timeout de 60 segundos solo para este step
    context.page.wait_for_selector(name, timeout=60000)
```

PREGUNTA 5: ¿Cómo habilito screenshots?
----------------------------------------

CONFIGURAR EN .env:
```bash
# Screenshots automáticos
HTML_REPORT_CAPTURE_ALL_STEPS=true   # Screenshot en cada step
SCREENSHOT_FULL_PAGE=true             # Screenshot de página completa

# Directorio
SCREENSHOTS_DIR=screenshots
```

SCREENSHOTS MANUALES EN FEATURES:
```gherkin
Scenario: Test con screenshot
  When voy a la url "${BASE_URL}"
  And tomo una captura de pantalla con nombre "homepage"
  # Screenshot guardado en screenshots/homepage.png
```

PREGUNTA 6: ¿Cómo configuro reportes HTML?
-------------------------------------------

CONFIGURAR EN .env:
```bash
HTML_REPORTS_DIR=html-reports
HTML_REPORT_CAPTURE_ALL_STEPS=true
```

EJECUTAR CON REPORTE:
```bash
behave -f html -o html-reports/report.html
```

ABRIR REPORTE:
```bash
# Windows
start html-reports/report.html

# Mac
open html-reports/report.html

# Linux
xdg-open html-reports/report.html
```


===========================================
CAPÍTULO 7: INTEGRACIONES
===========================================

PREGUNTA 1: ¿Cómo integro con Jira/Xray?
-----------------------------------------

PASO 1: Configurar en .env
```bash
JIRA_ENABLED=true
JIRA_URL=https://empresa.atlassian.net
JIRA_EMAIL=tu-email@empresa.com
JIRA_TOKEN=tu_jira_token
JIRA_PROJECT=PROJ
```

PASO 2: Usar tags en features
```gherkin
@PROJ-123
Scenario: Test vinculado a Jira
  Given voy a la url "${BASE_URL}"
  Then debería ver el texto "Welcome"
```

PASO 3: Ejecutar y subir resultados
```bash
behave --tags=@PROJ-123
# Los resultados se suben automáticamente a Jira
```

PREGUNTA 2: ¿Cómo uso Gemini AI?
---------------------------------

PASO 1: Configurar API Key
```bash
# .env
GEMINI_API_KEY=tu_api_key_aqui
GEMINI_JUDGE_MODEL=gemini-1.5-pro-002
```

PASO 2: Cargar contexto
```gherkin
@no_browser
Scenario: Test con Gemini
  Given cargo el contexto de Gemini desde el archivo "docs/api_spec.txt"
```

PASO 3: Validar con Gemini como Juez
```gherkin
When valido con Gemini que la respuesta cumple con "El usuario debe tener email válido"
```


PREGUNTA 3: ¿Cómo conecto a Supabase?
--------------------------------------

PASO 1: Configurar credenciales
```bash
# .env
SUPABASE_URL=https://tu-proyecto.supabase.co
SUPABASE_KEY=tu_supabase_key
```

PASO 2: Conectar en feature
```gherkin
Scenario: Búsqueda vectorial
  Given me conecto a Supabase con url "${SUPABASE_URL}" y key "${SUPABASE_KEY}"
```

PASO 3: Realizar búsqueda vectorial
```gherkin
When realizo una búsqueda vectorial en la tabla "documentos" con la consulta "¿Cómo hacer login?" y límite 5
Then guardo los resultados de la búsqueda vectorial en "resultados"
```

PREGUNTA 4: ¿Cómo testeo APIs?
-------------------------------

EJEMPLO COMPLETO DE API TESTING:

```gherkin
Feature: API Testing

  Background:
    Given establezco el header de API "Content-Type" a "application/json"
    And establezco el header de API "Authorization" a "Bearer ${API_KEY}"
  
  Scenario: CRUD completo de usuario
    # CREATE
    When realizo una petición POST a "${API_URL}/users" con el body:
      """
      {
        "name": "Juan Pérez",
        "email": "juan@test.com"
      }
      """
    Then el código de estado de la respuesta debería ser 201
    And extraigo el valor "id" del JSON de respuesta y lo guardo en "user_id"
    
    # READ
    When realizo una petición GET a "${API_URL}/users/${user_id}"
    Then el código de estado de la respuesta debería ser 200
    And el JSON de respuesta debería contener el campo "name" con valor "Juan Pérez"
    
    # UPDATE
    When realizo una petición PUT a "${API_URL}/users/${user_id}" con el body:
      """
      {
        "name": "Juan Actualizado"
      }
      """
    Then el código de estado de la respuesta debería ser 200
    
    # DELETE
    When realizo una petición DELETE a "${API_URL}/users/${user_id}"
    Then el código de estado de la respuesta debería ser 204
```



===========================================
CAPÍTULO 8: CASOS DE USO
===========================================

CASO DE USO 1: Login y Autenticación
-------------------------------------

```gherkin
Feature: Sistema de Login

  Background:
    Given voy a la url "${BASE_URL}/login"
  
  Scenario: Login exitoso
    When relleno el campo "email" con "${TEST_USER}" con identificador "id"
    And relleno el campo "password" con "${TEST_PASSWORD}" con identificador "id"
    And hago click en el elemento "login_button" con identificador "id"
    Then la url actual debería contener "dashboard"
    And debería ver el texto "Bienvenido"
  
  Scenario: Login con credenciales incorrectas
    When relleno el campo "email" con "wrong@test.com" con identificador "id"
    And relleno el campo "password" con "wrongpass" con identificador "id"
    And hago click en el elemento "login_button" con identificador "id"
    Then debería ver el texto "Credenciales inválidas"
    And la url actual debería contener "login"
```

CASO DE USO 2: Formularios Complejos
-------------------------------------

```gherkin
Feature: Registro de Usuario

  Scenario: Completar formulario de registro
    Given voy a la url "${BASE_URL}/register"
    
    # Datos personales
    When relleno el campo "first_name" con "Juan" con identificador "id"
    And relleno el campo "last_name" con "Pérez" con identificador "id"
    And relleno el campo "email" con "juan@test.com" con identificador "id"
    
    # Seleccionar país
    And selecciono la opción "México" del dropdown "country" con identificador "id"
    
    # Checkbox de términos
    And marco el checkbox "terms" con identificador "id"
    
    # Radio button de género
    And selecciono el radio button "gender" con valor "male" con identificador "name"
    
    # Subir archivo
    And subo el archivo "docs/id.pdf" al campo "id_document" con identificador "id"
    
    # Enviar formulario
    And hago click en el elemento "submit" con identificador "id"
    And espero 3 segundos
    
    # Validar
    Then debería ver el texto "Registro exitoso"
```


CASO DE USO 3: API Testing Completo
------------------------------------

```gherkin
Feature: API de Productos

  Background:
    Given establezco el header de API "Content-Type" a "application/json"
    And establezco el header de API "Authorization" a "Bearer ${API_KEY}"
  
  Scenario: Crear y validar producto
    # Generar datos únicos
    Given genero una variable "product_name" con texto aleatorio de 10 caracteres
    And creo la variable "product_price" con valor "99.99"
    
    # Crear producto
    When realizo una petición POST a "${API_URL}/products" con el body:
      """
      {
        "name": "${product_name}",
        "price": ${product_price},
        "category": "electronics"
      }
      """
    Then el código de estado de la respuesta debería ser 201
    And el JSON de respuesta debería contener el campo "id"
    And extraigo el valor "id" del JSON de respuesta y lo guardo en "product_id"
    
    # Obtener producto creado
    When realizo una petición GET a "${API_URL}/products/${product_id}"
    Then el código de estado de la respuesta debería ser 200
    And el JSON de respuesta debería contener el campo "name" con valor "${product_name}"
    And el JSON de respuesta debería contener el campo "price" con valor "99.99"
    
    # Actualizar precio
    When realizo una petición PATCH a "${API_URL}/products/${product_id}" con el body:
      """
      {
        "price": 79.99
      }
      """
    Then el código de estado de la respuesta debería ser 200
    
    # Verificar actualización
    When realizo una petición GET a "${API_URL}/products/${product_id}"
    Then el JSON de respuesta debería contener el campo "price" con valor "79.99"
    
    # Eliminar producto
    When realizo una petición DELETE a "${API_URL}/products/${product_id}"
    Then el código de estado de la respuesta debería ser 204
```

CASO DE USO 4: Drag & Drop
---------------------------

```gherkin
Feature: Drag and Drop

  Scenario: Reorganizar elementos
    Given voy a la url "${BASE_URL}/kanban"
    
    # Arrastrar tarea de "To Do" a "In Progress"
    When arrastro el elemento "task_1" y lo suelto en "column_in_progress" con identificador "id"
    And espero 1 segundos
    
    # Validar que se movió
    Then el elemento "task_1" debería estar dentro de "column_in_progress" con identificador "id"
```


CASO DE USO 5: Upload/Download de Archivos
-------------------------------------------

```gherkin
Feature: Manejo de Archivos

  Scenario: Subir archivo
    Given voy a la url "${BASE_URL}/upload"
    When subo el archivo "test_data/document.pdf" al campo "file_input" con identificador "id"
    And hago click en el elemento "upload_button" con identificador "id"
    And espero 3 segundos
    Then debería ver el texto "Archivo subido exitosamente"
  
  Scenario: Descargar archivo
    Given voy a la url "${BASE_URL}/files"
    When hago click en el elemento "download_button" con identificador "id"
    And espero 2 segundos
    Then el archivo "document.pdf" debería existir en la carpeta de descargas
```

CASO DE USO 6: Testing de Tablas
---------------------------------

```gherkin
Feature: Validación de Tablas

  Scenario: Verificar datos en tabla
    Given voy a la url "${BASE_URL}/users"
    
    # Contar filas
    When cuento las filas de la tabla "users_table" con identificador "id"
    Then la tabla debería tener al menos 5 filas
    
    # Buscar en tabla
    When busco "juan@test.com" en la columna "email" de la tabla "users_table" con identificador "id"
    Then debería encontrar al menos 1 resultado
    
    # Obtener valor de celda específica
    When obtengo el valor de la fila 1 columna "name" de la tabla "users_table" con identificador "id"
    And lo guardo en "first_user_name"
    Then verifico que la variable "first_user_name" no está vacía
```

CASO DE USO 7: Testing Responsive
----------------------------------

```gherkin
Feature: Diseño Responsive

  Scenario Outline: Validar en diferentes dispositivos
    Given configuro el viewport a <ancho> x <alto>
    When voy a la url "${BASE_URL}"
    Then debería ver el elemento "menu_<tipo>" con identificador "id"
    
    Examples:
      | ancho | alto | tipo    |
      | 1920  | 1080 | desktop |
      | 768   | 1024 | tablet  |
      | 375   | 667  | mobile  |
```


CASO DE USO 8: RAG Testing con Supabase + Gemini
-------------------------------------------------

```gherkin
@no_browser
Feature: Sistema RAG (Retrieval Augmented Generation)

  Background:
    # Conectar a Supabase
    Given me conecto a Supabase con url "${SUPABASE_URL}" y key "${SUPABASE_KEY}"
    
    # Cargar contexto para Gemini
    And cargo el contexto de Gemini desde el archivo "docs/product_manual.txt"
  
  Scenario: Búsqueda vectorial y validación con IA
    # Realizar búsqueda vectorial
    When realizo una búsqueda vectorial en la tabla "documentos" con la consulta "¿Cómo resetear la contraseña?" y límite 3
    And guardo los resultados de la búsqueda vectorial en "resultados"
    
    # Validar con Gemini
    When valido con Gemini que los resultados cumplen con "Los resultados deben mencionar el proceso de reseteo de contraseña"
    Then la validación de Gemini debería ser exitosa
  
  Scenario: Validar respuesta de chatbot
    # Simular pregunta de usuario
    Given creo la variable "pregunta" con valor "¿Cuál es el horario de atención?"
    
    # Buscar contexto relevante
    When realizo una búsqueda vectorial en la tabla "documentos" con la consulta "${pregunta}" y límite 5
    And guardo los resultados de la búsqueda vectorial en "contexto"
    
    # Generar respuesta (esto sería tu chatbot)
    And creo la variable "respuesta_chatbot" con valor "Nuestro horario es de 9am a 6pm"
    
    # Validar con Gemini que la respuesta es correcta según el contexto
    When valido con Gemini que la respuesta "${respuesta_chatbot}" es correcta según el contexto "${contexto}"
    Then la validación de Gemini debería ser exitosa
```


===========================================
CAPÍTULO 9: TROUBLESHOOTING
===========================================

ERROR 1: Elemento no encontrado
--------------------------------

SÍNTOMA:
```
Error: Element not found: #my-button
```

SOLUCIONES:

1. Verificar que el selector es correcto
```gherkin
# Usar inspector del navegador para obtener selector correcto
```

2. Esperar a que el elemento aparezca
```gherkin
When espero a que el elemento "my_button" sea visible con identificador "id"
```

3. Aumentar timeout
```bash
# .env
TIMEOUT=60000  # 60 segundos
```

4. Verificar que estás en la página correcta
```gherkin
Then la url actual debería contener "expected-page"
```


ERROR 2: Variable no encontrada
--------------------------------

SÍNTOMA:
```
Error: Variable 'user_id' not found
```

SOLUCIONES:

1. Verificar que la variable fue creada antes de usarla
```gherkin
# ❌ MAL
When uso la variable "${user_id}"

# ✅ BIEN
Given creo la variable "user_id" con valor "123"
When uso la variable "${user_id}"
```

2. Verificar scope de la variable
```gherkin
# Las variables de un scenario no existen en otro
# Usa Background para compartir variables
```

3. Verificar que la variable se guardó correctamente
```gherkin
# Después de guardar, verificar
When extraigo el valor "id" del JSON de respuesta y lo guardo en "user_id"
Then verifico que la variable "user_id" no está vacía
```

ERROR 3: Test falla intermitentemente
--------------------------------------

CAUSAS COMUNES:

1. Timing issues (elementos que aparecen/desaparecen)
```gherkin
# Agregar esperas explícitas
When espero a que el elemento "loader" no sea visible con identificador "id"
And espero a que el elemento "content" sea visible con identificador "id"
```

2. Datos no determinísticos
```gherkin
# Usar datos fijos en lugar de aleatorios para debugging
Given creo la variable "test_email" con valor "test@example.com"
# En lugar de generar aleatorio
```

3. Estado compartido entre tests
```gherkin
# Limpiar estado en Background
Background:
  Given limpio las cookies del navegador
  And limpio el localStorage
```

ERROR 4: API devuelve error 401
--------------------------------

SOLUCIONES:

1. Verificar que el token es válido
```gherkin
# Imprimir token para debug
When extraigo el valor "token" del JSON de respuesta y lo guardo en "auth_token"
And imprimo el valor de la variable "auth_token"
```

2. Verificar que el header está configurado correctamente
```gherkin
Given establezco el header de API "Authorization" a "Bearer ${auth_token}"
# Verificar que no hay espacios extra
```

3. Verificar que el token no expiró
```gherkin
# Renovar token antes de cada test
Background:
  Given realizo login y obtengo token fresco
```


ERROR 5: Step no encontrado
----------------------------

SÍNTOMA:
```
Error: No step definition found for "mi paso personalizado"
```

SOLUCIONES:

1. Verificar que el archivo de steps existe en features/steps/
```bash
# Estructura correcta
features/
├── steps/
│   ├── __init__.py
│   └── custom_steps.py
```

2. Verificar que el decorador @step está correcto
```python
from behave import step

@step('mi paso personalizado')  # ✅ Correcto
def my_step(context):
    pass
```

3. Verificar que el texto del step coincide exactamente
```gherkin
# En feature
When mi paso personalizado

# En step definition
@step('mi paso personalizado')  # Debe coincidir exactamente
```

ERROR 6: AmbiguousStep
----------------------

SÍNTOMA:
```
Error: AmbiguousStep: Multiple step definitions found
```

CAUSA:
Dos steps tienen decoradores que se solapan

SOLUCIÓN:
Hacer los steps más específicos
```python
# ❌ MAL (ambiguo)
@step('verifico que el elemento "{name}" está visible')
@step('verifico que el elemento "{name}" está visible en la página')

# ✅ BIEN (específico)
@step('verifico que el elemento "{name}" está visible')
@step('verifico en la página actual que el elemento "{name}" está visible')
```

DEBUGGING: Cómo encontrar problemas
------------------------------------

1. MODO VERBOSE
```bash
behave --verbose
```

2. EJECUTAR UN SOLO SCENARIO
```bash
behave features/login.feature:10  # Línea 10
```

3. EJECUTAR CON TAG
```bash
behave --tags=@debug
```

4. MODO NO HEADLESS (ver el navegador)
```bash
# .env
HEADLESS=false
```

5. SCREENSHOTS EN CADA PASO
```bash
# .env
HTML_REPORT_CAPTURE_ALL_STEPS=true
```

6. IMPRIMIR VARIABLES
```gherkin
When imprimo el valor de la variable "user_id"
```

7. PAUSAR EJECUCIÓN
```gherkin
When pauso la ejecución por 10 segundos
# Tiempo para inspeccionar manualmente
```


LOGS: Dónde encontrarlos
-------------------------

1. LOGS DE BEHAVE
```
# Salida estándar en consola
behave > output.log 2>&1
```

2. LOGS DE PLAYWRIGHT
```bash
# .env
DEBUG=pw:api  # Logs detallados de Playwright
```

3. SCREENSHOTS
```
screenshots/
├── scenario_name_step_1.png
├── scenario_name_step_2.png
└── ...
```

4. REPORTES HTML
```
html-reports/
└── report.html  # Abrir en navegador
```

5. VIDEOS (si está habilitado)
```bash
# .env
VIDEO_RECORDING=true
```

PERFORMANCE: Optimización
--------------------------

1. EJECUTAR EN PARALELO
```bash
behave --processes 4
```

2. USAR HEADLESS
```bash
# .env
HEADLESS=true  # Más rápido
```

3. DESHABILITAR SCREENSHOTS INNECESARIOS
```bash
# .env
HTML_REPORT_CAPTURE_ALL_STEPS=false
```

4. REDUCIR TIMEOUTS
```bash
# .env
TIMEOUT=10000  # Solo si tus tests son rápidos
```

5. USAR TAGS PARA EJECUTAR SUBCONJUNTOS
```bash
behave --tags=@smoke  # Solo tests críticos
```


===========================================
CAPÍTULO 10: REFERENCIA RÁPIDA
===========================================

COMANDOS ÚTILES
---------------

```bash
# Ejecutar todos los tests
behave

# Ejecutar un feature específico
behave features/login.feature

# Ejecutar con tags
behave --tags=@smoke
behave --tags=@regression
behave --tags="@api and not @slow"

# Ejecutar en paralelo
behave --processes 4

# Generar reporte HTML
behave -f html -o report.html

# Modo verbose
behave --verbose

# Ejecutar scenario específico (por línea)
behave features/login.feature:15

# Listar todos los scenarios
behave --dry-run

# Ejecutar con variables
behave -D browser=firefox -D headless=true
```


SINTAXIS GHERKIN - CHEAT SHEET
-------------------------------

```gherkin
# ESTRUCTURA BÁSICA
Feature: Nombre del feature
  Descripción opcional del feature

  Background:
    # Steps que se ejecutan antes de cada scenario
    Given paso inicial común
  
  Scenario: Nombre del scenario
    Given contexto inicial
    When acción del usuario
    Then resultado esperado
    And paso adicional
    But excepción
  
  Scenario Outline: Scenario con datos
    Given voy a "${url}"
    When busco "<producto>"
    Then veo "<resultado>"
    
    Examples:
      | url                  | producto | resultado |
      | https://example.com  | laptop   | Laptop    |
      | https://example.com  | phone    | Phone     |

# TAGS
@smoke @regression
Scenario: Test importante
  # ...

# COMENTARIOS
# Esto es un comentario

# TEXTO MULTILÍNEA
When envío el JSON:
  """
  {
    "key": "value"
  }
  """

# TABLAS
When cargo los siguientes usuarios:
  | name  | email           |
  | Juan  | juan@test.com   |
  | María | maria@test.com  |
```

VARIABLES - CHEAT SHEET
------------------------

```gherkin
# CREAR VARIABLE
Given creo la variable "nombre" con valor "Juan"
Given establezco "edad" = "25"

# USAR VARIABLE
When uso "${nombre}" en el campo
When voy a "${BASE_URL}/users/${user_id}"

# VARIABLES ALEATORIAS
Given genero una variable "codigo" con texto aleatorio de 10 caracteres
Given genero una variable "numero" con número aleatorio entre 1 y 100
Given genero una variable "timestamp" con timestamp actual

# GUARDAR DESDE API
When extraigo el valor "id" del JSON de respuesta y lo guardo en "user_id"

# GUARDAR DESDE WEB
When obtengo el texto del elemento "titulo" y lo guardo en "texto" con identificador "id"

# VALIDAR VARIABLE
Then verifico que la variable "nombre" contiene "Juan"
Then verifico que la variable "edad" es mayor que "18"
```


LOCALIZADORES - CHEAT SHEET
----------------------------

```gherkin
# POR ID
When hago click en el elemento "login_button" con identificador "id"

# POR CLASE
When hago click en el elemento "btn-primary" con identificador "class"

# POR NOMBRE
When hago click en el elemento "submit" con identificador "name"

# POR XPATH
When hago click en el elemento "//button[@type='submit']" con identificador "xpath"

# POR CSS
When hago click en el elemento "button.primary" con identificador "css"

# POR TEXTO
When hago click en el elemento "Enviar" con identificador "text"

# JSON POM
When hago click en el elemento "boton" con identificador "$.LOGIN.login_button"

# LOCALIZADOR DINÁMICO
When hago click en el elemento "fila" con identificador "$.TABLA.fila_por_id=123"
```

API TESTING - CHEAT SHEET
--------------------------

```gherkin
# CONFIGURAR HEADERS
Given establezco el header de API "Content-Type" a "application/json"
Given establezco el header de API "Authorization" a "Bearer ${token}"

# PETICIONES
When realizo una petición GET a "${API_URL}/users"
When realizo una petición POST a "${API_URL}/users" con el body:
  """
  {"name": "Juan"}
  """
When realizo una petición PUT a "${API_URL}/users/1" con el body:
  """
  {"name": "Juan Actualizado"}
  """
When realizo una petición PATCH a "${API_URL}/users/1" con el body:
  """
  {"email": "nuevo@email.com"}
  """
When realizo una petición DELETE a "${API_URL}/users/1"

# VALIDACIONES
Then el código de estado de la respuesta debería ser 200
Then el JSON de respuesta debería contener el campo "id"
Then el JSON de respuesta debería contener el campo "name" con valor "Juan"

# EXTRAER DATOS
When extraigo el valor "id" del JSON de respuesta y lo guardo en "user_id"
When extraigo el valor "data.users[0].email" del JSON de respuesta y lo guardo en "email"
```

NAVEGACIÓN - CHEAT SHEET
-------------------------

```gherkin
# IR A URL
Given voy a la url "${BASE_URL}"
Given voy a la url "https://example.com"

# NAVEGACIÓN
When hago click en el botón de retroceso del navegador
When hago click en el botón de avance del navegador
When recargo la página

# VALIDAR URL
Then la url actual debería ser "${BASE_URL}/dashboard"
Then la url actual debería contener "dashboard"

# ESPERAS
When espero 2 segundos
When espero a que el elemento "loader" no sea visible con identificador "id"
When espero a que el elemento "content" sea visible con identificador "id"
```


INTERACCIONES - CHEAT SHEET
----------------------------

```gherkin
# CLICK
When hago click en el elemento "button" con identificador "id"
When hago doble click en el elemento "item" con identificador "id"
When hago click derecho en el elemento "menu" con identificador "id"

# FORMULARIOS
When relleno el campo "email" con "test@example.com" con identificador "id"
When limpio el campo "search" con identificador "id"
When marco el checkbox "terms" con identificador "id"
When desmarco el checkbox "newsletter" con identificador "id"
When selecciono la opción "México" del dropdown "country" con identificador "id"
When selecciono el radio button "gender" con valor "male" con identificador "name"

# ARCHIVOS
When subo el archivo "docs/test.pdf" al campo "file_input" con identificador "id"

# DRAG & DROP
When arrastro el elemento "item1" y lo suelto en "container" con identificador "id"

# HOVER
When paso el mouse sobre el elemento "menu" con identificador "id"

# SCROLL
When hago scroll hasta el elemento "footer" con identificador "id"
When hago scroll hacia abajo 500 pixeles
```

VALIDACIONES - CHEAT SHEET
---------------------------

```gherkin
# TEXTO
Then debería ver el texto "Bienvenido"
Then no debería ver el texto "Error"
Then el elemento "title" debería contener el texto "Dashboard" con identificador "id"

# VISIBILIDAD
Then el elemento "modal" debería estar visible con identificador "id"
Then el elemento "loader" no debería estar visible con identificador "id"

# EXISTENCIA
Then el elemento "button" debería existir con identificador "id"
Then el elemento "error" no debería existir con identificador "id"

# ATRIBUTOS
Then el elemento "input" debería tener el atributo "disabled" con identificador "id"
Then el elemento "link" debería tener el atributo "href" con valor "/home" con identificador "id"

# CLASES
Then el elemento "button" debería tener la clase "active" con identificador "id"

# CONTEO
Then debería haber 5 elementos "item" con identificador "class"
Then debería haber al menos 3 elementos "row" con identificador "class"
```

SUPABASE - CHEAT SHEET
-----------------------

```gherkin
# CONECTAR
Given me conecto a Supabase con url "${SUPABASE_URL}" y key "${SUPABASE_KEY}"

# BÚSQUEDA VECTORIAL
When realizo una búsqueda vectorial en la tabla "docs" con la consulta "¿Cómo hacer login?" y límite 5
Then guardo los resultados de la búsqueda vectorial en "resultados"

# CONSULTAS SQL
When ejecuto la consulta SQL "SELECT * FROM users WHERE active = true" en Supabase
Then guardo los resultados de la consulta SQL en "usuarios_activos"
```


GEMINI AI - CHEAT SHEET
------------------------

```gherkin
# CONFIGURAR (en .env)
GEMINI_API_KEY=tu_api_key
GEMINI_JUDGE_MODEL=gemini-1.5-pro-002

# CARGAR CONTEXTO
@no_browser
Scenario: Test con IA
  Given cargo el contexto de Gemini desde el archivo "docs/manual.txt"
  
  # VALIDAR CON GEMINI
  When valido con Gemini que la respuesta cumple con "El email debe ser válido"
  Then la validación de Gemini debería ser exitosa
```

TAGS ESPECIALES
----------------

```gherkin
# NO USAR NAVEGADOR (para API testing, IA, etc.)
@no_browser
Scenario: Test sin navegador
  # No se abre navegador, más rápido

# SMOKE TESTS (tests críticos)
@smoke
Scenario: Test crítico
  # Ejecutar: behave --tags=@smoke

# REGRESSION (suite completa)
@regression
Scenario: Test de regresión
  # Ejecutar: behave --tags=@regression

# SKIP (omitir temporalmente)
@skip
Scenario: Test en desarrollo
  # No se ejecuta

# SLOW (tests lentos)
@slow
Scenario: Test que tarda mucho
  # Ejecutar por separado: behave --tags=@slow

# JIRA (vincular con issue)
@PROJ-123
Scenario: Test vinculado a Jira
  # Se reporta automáticamente a Jira
```

SNIPPETS ÚTILES
----------------

SNIPPET 1: Login reutilizable
```gherkin
Background:
  Given voy a la url "${BASE_URL}/login"
  When relleno el campo "email" con "${TEST_USER}" con identificador "id"
  And relleno el campo "password" con "${TEST_PASSWORD}" con identificador "id"
  And hago click en el elemento "login_button" con identificador "id"
  Then la url actual debería contener "dashboard"
```

SNIPPET 2: Crear y usar datos
```gherkin
# Generar datos únicos
Given genero una variable "unique_id" con texto aleatorio de 8 caracteres
And creo la variable "test_email" con valor "test_${unique_id}@example.com"

# Usar datos
When relleno el campo "email" con "${test_email}" con identificador "id"
```

SNIPPET 3: Validación completa de formulario
```gherkin
# Enviar formulario vacío
When hago click en el elemento "submit" con identificador "id"

# Validar errores
Then debería ver el texto "El email es requerido"
And debería ver el texto "La contraseña es requerida"
And el elemento "email_error" debería estar visible con identificador "id"
```


SNIPPET 4: API CRUD completo
```gherkin
Scenario: CRUD de recurso
  # CREATE
  When realizo una petición POST a "${API_URL}/items" con el body:
    """
    {"name": "Test Item"}
    """
  Then el código de estado de la respuesta debería ser 201
  And extraigo el valor "id" del JSON de respuesta y lo guardo en "item_id"
  
  # READ
  When realizo una petición GET a "${API_URL}/items/${item_id}"
  Then el código de estado de la respuesta debería ser 200
  
  # UPDATE
  When realizo una petición PUT a "${API_URL}/items/${item_id}" con el body:
    """
    {"name": "Updated Item"}
    """
  Then el código de estado de la respuesta debería ser 200
  
  # DELETE
  When realizo una petición DELETE a "${API_URL}/items/${item_id}"
  Then el código de estado de la respuesta debería ser 204
```

SNIPPET 5: Esperar y validar
```gherkin
# Esperar a que desaparezca loader
When espero a que el elemento "loader" no sea visible con identificador "id"

# Esperar a que aparezca contenido
And espero a que el elemento "content" sea visible con identificador "id"

# Validar contenido
Then el elemento "title" debería contener el texto "Dashboard" con identificador "id"
```

MEJORES PRÁCTICAS
------------------

1. USAR VARIABLES DE ENTORNO
   ✅ Given voy a la url "${BASE_URL}"
   ❌ Given voy a la url "https://hardcoded.com"

2. USAR JSON POM PARA SELECTORES
   ✅ When hago click en el elemento "btn" con identificador "$.LOGIN.login_button"
   ❌ When hago click en el elemento "button" con identificador "#login-btn-123-xyz"

3. GENERAR DATOS ÚNICOS
   ✅ Given genero una variable "email" con texto aleatorio de 10 caracteres
   ❌ Given creo la variable "email" con valor "test@test.com"

4. USAR BACKGROUND PARA SETUP COMÚN
   ✅ Background: Given estoy logueado
   ❌ Repetir login en cada scenario

5. AGREGAR ESPERAS EXPLÍCITAS
   ✅ When espero a que el elemento "modal" sea visible con identificador "id"
   ❌ When espero 5 segundos

6. VALIDAR ANTES DE INTERACTUAR
   ✅ Then el elemento "button" debería estar visible con identificador "id"
       When hago click en el elemento "button" con identificador "id"
   ❌ When hago click en el elemento "button" con identificador "id"

7. USAR TAGS PARA ORGANIZAR
   ✅ @smoke @login
   ❌ Sin tags

8. NOMBRES DESCRIPTIVOS
   ✅ Scenario: Login exitoso con credenciales válidas
   ❌ Scenario: Test 1


ANTI-PATRONES (EVITAR)
-----------------------

❌ ANTI-PATRÓN 1: Hardcodear valores
```gherkin
Given voy a la url "https://production.com"  # ❌ MAL
Given voy a la url "${BASE_URL}"             # ✅ BIEN
```

❌ ANTI-PATRÓN 2: Selectores frágiles
```gherkin
When hago click en el elemento "div > div > button" con identificador "css"  # ❌ MAL
When hago click en el elemento "submit" con identificador "$.FORM.submit_button"  # ✅ BIEN
```

❌ ANTI-PATRÓN 3: Esperas fijas innecesarias
```gherkin
When espero 10 segundos  # ❌ MAL (ralentiza tests)
When espero a que el elemento "content" sea visible con identificador "id"  # ✅ BIEN
```

❌ ANTI-PATRÓN 4: No validar antes de continuar
```gherkin
When hago click en el elemento "button" con identificador "id"
And hago click en el elemento "next" con identificador "id"  # ❌ MAL (puede fallar)

When hago click en el elemento "button" con identificador "id"
Then el elemento "next" debería estar visible con identificador "id"
When hago click en el elemento "next" con identificador "id"  # ✅ BIEN
```

❌ ANTI-PATRÓN 5: Scenarios muy largos
```gherkin
Scenario: Test gigante con 50 steps  # ❌ MAL
  # Dividir en múltiples scenarios

Scenario: Login  # ✅ BIEN
  # 5-10 steps

Scenario: Crear producto  # ✅ BIEN
  # 5-10 steps
```

❌ ANTI-PATRÓN 6: No limpiar estado
```gherkin
Scenario: Test que deja datos basura  # ❌ MAL
  # Crear usuario pero no eliminarlo

Scenario: Test con cleanup  # ✅ BIEN
  # Crear usuario
  # Hacer test
  # Eliminar usuario
```

ESTRUCTURA DE PROYECTO RECOMENDADA
-----------------------------------

```
proyecto/
├── .env                          # Variables de entorno
├── behave.ini                    # Configuración de Behave
├── requirements.txt              # Dependencias Python
├── features/
│   ├── environment.py            # Hooks de Behave
│   ├── steps/
│   │   ├── __init__.py
│   │   ├── custom_login_steps.py
│   │   ├── custom_api_steps.py
│   │   └── custom_validation_steps.py
│   ├── login.feature
│   ├── products.feature
│   └── api_tests.feature
├── json_poms/
│   ├── LOGIN.json
│   ├── PRODUCTS.json
│   └── COMMON.json
├── test_data/
│   ├── users.csv
│   ├── products.json
│   └── test_files/
│       ├── document.pdf
│       └── image.png
├── docs/
│   ├── api_spec.txt
│   └── manual.txt
├── screenshots/                  # Generado automáticamente
├── html-reports/                 # Generado automáticamente
└── downloads/                    # Generado automáticamente
```


FAQ - PREGUNTAS FRECUENTES
---------------------------

P: ¿Puedo usar el framework para testing de APIs sin navegador?
R: Sí, usa el tag @no_browser en tu scenario.

P: ¿Cómo ejecuto solo los tests críticos?
R: Usa tags: behave --tags=@smoke

P: ¿Puedo ejecutar tests en paralelo?
R: Sí: behave --processes 4

P: ¿Cómo debuggeo un test que falla?
R: Usa HEADLESS=false en .env y HTML_REPORT_CAPTURE_ALL_STEPS=true

P: ¿Puedo usar diferentes navegadores?
R: Sí, configura BROWSER=chromium|firefox|webkit en .env

P: ¿Cómo integro con CI/CD?
R: Ejecuta behave en tu pipeline, genera reportes HTML y súbelos como artifacts

P: ¿Puedo testear aplicaciones móviles?
R: Sí, configura emuladores de dispositivos móviles en .env

P: ¿Cómo manejo autenticación compleja?
R: Crea steps personalizados para tu flujo de autenticación específico

P: ¿Puedo usar el framework con Docker?
R: Sí, crea un Dockerfile con Python y las dependencias

P: ¿Cómo reporto bugs encontrados?
R: Los reportes HTML incluyen screenshots y logs detallados

RECURSOS ADICIONALES
---------------------

DOCUMENTACIÓN COMPLETA:
- hakalab_framework/documentacion/GUIA_*.txt

INVENTARIO DE STEPS:
- hakalab_framework/documentacion/INVENTARIO_COMPLETO_PASOS.txt
- hakalab_framework/documentacion/INVENTARIO_COMPLETO_PASOS.md

EJEMPLOS:
- hakalab_framework/examples/

CÓDIGO FUENTE:
- hakalab_framework/steps/        # Steps predefinidos
- hakalab_framework/core/         # Core del framework

CONFIGURACIÓN:
- .env                            # Variables de entorno
- behave.ini                      # Configuración de Behave
- features/environment.py         # Hooks personalizados


===========================================
FIN DE LA GUÍA
===========================================

Versión: 1.0
Última actualización: 2026-03-03
Framework: Haka Playwright Engine v1.3.17

Para más información, consulta la documentación en:
hakalab_framework/documentacion/

¡Feliz testing! 🚀
