Los formularios son donde viven los bugs
Los formularios son la forma principal en que los usuarios interactúan con las aplicaciones web — login, registro, búsqueda, checkout, actualización de perfil, formularios de contacto. También son donde viven la mayoría de los bugs. Cada campo de formulario es un punto de entrada para datos inválidos, caracteres inesperados y casos límite.
Un tester de formularios exhaustivo no solo llena datos válidos y hace clic en enviar. Piensa en cada posible input que un usuario — o un atacante — podría proporcionar.
Anatomía de un formulario web
Un formulario típico incluye:
- Inputs de texto: Nombres, emails, direcciones, texto libre
- Selectores: Dropdowns, radio buttons, checkboxes
- Inputs especiales: Date pickers, carga de archivos, color pickers, range sliders
- Botones: Enviar, resetear, cancelar
- Campos ocultos: Tokens CSRF, IDs de usuario, datos de tracking
Cada tipo de elemento tiene su propia clase de bugs y casos de prueba.
Validación del lado del cliente vs. del servidor
Validación del lado del cliente
Ocurre en el navegador usando atributos HTML y JavaScript. Proporciona feedback instantáneo pero puede evadirse.
Atributos de validación HTML:
<input type="email" required minlength="5" maxlength="255" pattern="[a-z@.]+">
Validación JavaScript:
if (password.length < 8) {
showError('La contraseña debe tener al menos 8 caracteres');
return false;
}
Validación del lado del servidor
Ocurre en el servidor después del envío del formulario. Esta es la frontera de seguridad — no puede ser evadida por el usuario.
Regla crítica de testing: Siempre prueba la validación del servidor evadiendo la validación del cliente. En la consola de DevTools:
document.querySelector('form').noValidate = true;
// O remover atributos 'required':
document.querySelectorAll('[required]').forEach(el => el.removeAttribute('required'));
Luego envía el formulario con datos inválidos. El servidor debe seguir rechazándolos.
Casos de prueba por tipo de campo
Campos de texto
| Caso de prueba | Input | Resultado esperado |
|---|---|---|
| Campo requerido vacío | (nada) | Error de validación |
| Longitud mínima | 1 carácter | Aceptar o rechazar según spec |
| Longitud máxima | Max + 1 caracteres | Rechazar o truncar |
| Caracteres especiales | <script>alert('xss')</script> | Sanitizado, sin ejecución de script |
| Caracteres Unicode | 名前 Ñoño Ünïcödë | Aceptar si se soportan nombres internacionales |
| Espacios al inicio/final | Juan | Aceptar pero limpiar, o rechazar según spec |
| Solo espacios | | Rechazar (vacío después de limpiar) |
| Input muy largo | 10,000+ caracteres | Manejar correctamente, sin crash |
| SQL injection | '; DROP TABLE users; -- | Manejado de forma segura |
| Entidades HTML | & < ' | Mostradas correctamente |
| Emojis | Juan 🎉 Pérez | Aceptar o rechazar consistentemente |
Campos de email
| Caso de prueba | Input | Esperado |
|---|---|---|
| Email válido | user@example.com | Aceptar |
| Sin @ | userexample.com | Rechazar |
| Sin dominio | user@ | Rechazar |
| Sin parte local | @example.com | Rechazar |
| Puntos dobles | user@example..com | Rechazar |
| Subdominio | user@mail.example.com | Aceptar |
| Plus addressing | user+tag@example.com | Aceptar |
| Email muy largo | 255+ caracteres | Según límite RFC |
Campos de contraseña
| Caso de prueba | Input | Esperado |
|---|---|---|
| Longitud mínima | 7 chars (si min es 8) | Rechazar con mensaje |
| Longitud máxima | Muy largo (1000+ chars) | Aceptar o aplicar máximo |
| Sin mayúscula | password123! | Según política |
| Sin número | Password!!! | Según política |
| Contraseñas comunes | password123, 123456 | Rechazar si existe blocklist |
| Espacios en contraseña | Mi Password 1! | Aceptar (espacios son válidos) |
| Pegar deshabilitado? | (Pegar desde portapapeles) | Debería permitir pegar |
| Toggle mostrar/ocultar | (Clic ícono ojo) | Revela/oculta texto |
Campos numéricos
Prueba los límites cuidadosamente: valor mínimo, valor máximo, min-1, max+1, cero, números negativos, decimales, caracteres no numéricos.
Testing de envío de formularios
Estados del botón de envío
- Antes de interacción: Enviar debería estar habilitado (o deshabilitado si se requieren campos específicos)
- Durante el envío: Botón deshabilitado para prevenir envío doble; mostrar indicador de carga
- Después de éxito: Redirigir o mostrar mensaje de éxito
- Después de fallo: Mostrar mensajes de error; preservar input del usuario; rehabilitar botón
Envío doble
Haz clic en el botón de enviar rápidamente múltiples veces. ¿El formulario:
- ¿Envía solo una vez? (Correcto)
- ¿Envía múltiples veces, creando registros duplicados? (Bug)
- ¿Muestra un estado de carga que previene re-clic? (Buena UX)
Testing avanzado de formularios
Orden de tabulación y navegación por teclado
- Haz clic en el primer campo y presiona Tab repetidamente
- Verifica que el focus se mueva por los campos en orden lógico
- Verifica que puedas enviar el formulario usando Enter
- Verifica que los dropdowns se puedan navegar con flechas
- Verifica que los checkboxes se alternen con Espacio
- Verifica que los radio buttons cambien con flechas
Testing de autofill
Los navegadores auto-completan formularios con datos guardados. Prueba:
- ¿El formulario acepta valores autocompletados correctamente?
- ¿Los nombres de campos son suficientemente semánticos para que el navegador autocomplete apropiadamente?
- ¿El autofill dispara validación del lado del cliente?
- ¿El formulario se rompe si autofill provee valores inesperados?
Calidad de mensajes de error
Buenos mensajes de error son:
- Específicos: “El email debe incluir un símbolo @” no “Input inválido”
- Ubicados cerca del campo: Errores inline, no solo una lista arriba
- Persistentes: Permanecen visibles hasta que el error se corrige
- Accesibles: Los lectores de pantalla pueden anunciarlos (usar
aria-describedby) - Sin culpar: “Por favor ingresa un email válido” no “Ingresaste un email inválido”
Testing de formularios multi-paso
Formularios tipo wizard con múltiples pasos necesitan testing adicional:
- ¿Puedes navegar a pasos anteriores sin perder datos?
- ¿La validación ocurre por paso o solo al final?
- ¿Qué pasa si refrescas a mitad del wizard?
- Si abres la URL en una nueva pestaña, ¿empieza desde el paso 1 o recuerda el progreso?
Ejercicio: Auditoría completa de formulario
Encuentra un formulario de registro o checkout y pruébalo:
- Campos requeridos: Envía el formulario con cada campo requerido vacío, uno a la vez
- Valores límite: Prueba longitudes mínimas y máximas para cada campo de texto
- Caracteres especiales: Ingresa
<script>alert(1)</script>en cada campo - SQL injection: Ingresa
' OR 1=1 --en cada campo - Validación del servidor: Evade validación del cliente en DevTools y reenvía
- Envío doble: Haz clic en enviar 5 veces rápidamente
- Orden de tabulación: Navega todo el formulario solo con teclado
- Mensajes de error: Dispara cada error de validación y documenta la calidad del mensaje
- Autofill: Deja que el navegador autocomplete y verifica corrección
- Botón atrás: Envía exitosamente, luego presiona atrás en el navegador
| Campo | Test | Resultado | ¿Bug? |
|---|---|---|---|
SQL injection ' OR 1=1 -- | Servidor retorna error 500 | Sí - Crítico | |
| Nombre | 1000 caracteres | Aceptado, pero rompe layout del perfil | Sí - Medio |
| Contraseña | Pegar deshabilitado | No se puede pegar contraseña | Sí - Problema UX |
| Todos | Envío doble | Dos cuentas creadas | Sí - Crítico |
Tips profesionales
Tip 1: Prueba el envío de formularios con throttling de red. Las conexiones lentas exponen bugs de timing como envío doble.
Tip 2: Verifica lo que el servidor realmente recibe. En la pestaña Network, inspecciona el payload del request — los datos enviados podrían diferir de lo mostrado.
Tip 3: Prueba los indicadores de campos requeridos. Si un campo muestra un asterisco rojo (*), debe realmente ser requerido.
Puntos clave
- Los formularios son el área de mayor densidad de bugs en aplicaciones web
- Siempre prueba validación del cliente y del servidor de forma independiente
- Valores límite, caracteres especiales y campos vacíos son donde se ocultan la mayoría de los bugs
- La prevención de envío doble debe probarse en cada formulario
- La navegación por teclado y orden de tabulación afectan usabilidad y accesibilidad
- Los mensajes de error deben ser específicos, bien posicionados y accesibles
- Evadir validación del cliente para probar la del servidor es una técnica crítica de testing de seguridad