La API de Escena Viva vende entradas, persiste pedidos con transacciones que impiden la sobreventa, autentica usuarios, rota tokens de refresco y autoriza operaciones según roles y propiedad del recurso. Hace muchísimas cosas. Y nadie ha comprobado nunca que funcione. Ni una sola vez.
npm test sigue fallando a propósito desde el módulo 5 con el mensaje Sin pruebas todavia — Modulo 9, y cada línea de seguridad que escribimos en el módulo anterior —el señuelo de bcrypt, la detección de reutilización del refresco, cada celda de la matriz de permisos— descansa hoy sobre la confianza de que la escribimos bien. Un if invertido en puedeGestionarEvento abriría el catálogo entero de eventos a cualquier organizador y nada avisaría.
En esta lección no escribiremos todavía la primera prueba ejecutable ni instalaremos nada: eso es la lección siguiente. Aquí construimos los cimientos conceptuales, que es lo que separa un proyecto con muchas pruebas de un proyecto con buenas pruebas.
Contenido
- Por qué se prueba: cambiar el código sin miedo
- Qué es una prueba automatizada y la estructura AAA
- Tipos de prueba y la pirámide
- Qué probar y qué no: el criterio del riesgo
- Qué hace buena a una prueba
- Pruebas frágiles y falsos positivos
- TDD explicado con honestidad
- El panorama de herramientas para Node
- El plan de pruebas de Escena Viva
Por qué se prueba: cambiar el código sin miedo
Existe una idea muy extendida de que las pruebas sirven "por si acaso", como un seguro que quizá algún día se cobre. Es una descripción pobre y explica por qué tantos equipos las abandonan a las tres semanas. El valor real de una batería de pruebas es otro y es medible en el día a día: te devuelve la capacidad de modificar el código.
Hagamos la prueba del algodón con nuestro propio proyecto. Responde con honestidad:
- ¿Te atreverías hoy a reescribir
comprarEntradaspara agrupar varias sesiones en un solo pedido? - ¿Te atreverías a refactorizar
PERMISOS_POR_ROLpara añadir el roltaquillerosin revisar manualmente las 30 combinaciones? - ¿Te atreverías a cambiar el orden de dos middlewares en
crearAplicacionpara queautenticarcorra antes quelimiteCompra? - ¿Te atreverías a subir la versión mayor de Mongoose?
Si la respuesta honesta es "no, o solo con mucho cuidado y probando a mano en el navegador", el código ya te está gobernando a ti. Esa parálisis tiene un coste que no aparece en ninguna factura: las funciones se van copiando en lugar de reutilizarse, los if se acumulan porque nadie borra ramas antiguas, y la deuda técnica crece porque tocar lo que ya funciona da miedo.
Una batería de pruebas convierte la pregunta "¿habré roto algo?" en un comando de diez segundos. Ese es el producto que compramos en este módulo. Los beneficios secundarios son reales pero secundarios:
| Beneficio | Qué aporta de verdad |
|---|---|
| Detectar regresiones | Un fallo que ya arreglaste no vuelve sin que te enteres |
| Documentación viva | it('rechaza la venta si el aforo es insuficiente') no se desactualiza, porque si miente falla |
| Presión de diseño | El código difícil de probar suele estar mal acoplado; probar lo revela pronto |
| Confianza en el despliegue | CI puede bloquear un despliegue roto sin intervención humana |
| Onboarding | Quien llega nuevo lee las pruebas para entender el comportamiento esperado |
Y hay algo que las pruebas no hacen, conviene decirlo desde el principio: no demuestran que el programa sea correcto. Demuestran que los casos que se te ocurrieron se comportan como esperabas. Es muchísimo, pero no es una garantía matemática.
Qué es una prueba automatizada y la estructura AAA
Una prueba automatizada es simplemente un programa que ejecuta otro programa y comprueba el resultado, terminando con éxito o con error sin que nadie mire la pantalla. No hay magia: un fichero de pruebas es JavaScript normal.
La estructura universal se conoce como AAA (Arrange, Act, Assert), que en español llamaremos preparar, actuar y comprobar:
- Preparar: construir el escenario. Datos, objetos, dobles de prueba, estado inicial.
- Actuar: ejecutar exactamente una operación, la que se está probando.
- Comprobar: verificar que el resultado observable es el esperado.
Veamos el primer ejemplo sobre una pieza real de nuestro dominio, Sesion.vender(). Todavía no es código ejecutable con Mocha —falta la instalación—, pero la anatomía ya es la definitiva:
// Boceto conceptual de una prueba sobre Sesion.vender()
// (la sintaxis ejecutable con Mocha y Chai llega en 09-02)
const { Sesion } = require('../../src/dominio/sesion.js');
function pruebaVenderDescuentaDelAforo() {
// 1. PREPARAR: una sesión conocida y controlada
const sesion = new Sesion({
id: 'ses-001-1',
eventoId: 'evt-001',
inicio: '2026-10-17T20:00:00.000Z',
aforo: 400,
vendidas: 100,
precioCentimos: 2500,
});
// 2. ACTUAR: una sola operación
sesion.vender(3);
// 3. COMPROBAR: el efecto observable
if (sesion.libres !== 297) {
throw new Error('Se esperaban 297 localidades libres');
}
}Tres observaciones importantes sobre este boceto:
- La preparación es explícita y local. No leemos la sesión de la base de datos ni dependemos de la semilla. Si mañana alguien cambia el aforo de
ses-001-1enscripts/semilla.js, esta prueba sigue siendo válida. Una prueba que depende de datos lejanos es una prueba que fallará por motivos ajenos a lo que dice probar. - Actuar es una sola línea. Si necesitas cinco llamadas para actuar, probablemente estés probando cinco cosas y el fallo no te dirá cuál.
- Comprobamos el comportamiento observable,
libres, no el campo privado#vendidas. De hecho no podríamos: es privado. Eso es una ventaja, no un obstáculo.
Un cuarto paso implícito, la limpieza, aparecerá cuando haya recursos que liberar (conexiones, relojes falsos, ficheros). En el dominio puro no hace falta, y ese es justo su encanto.
Tipos de prueba y la pirámide
No todas las pruebas cuestan lo mismo ni detectan lo mismo. Esta tabla es el mapa del módulo entero:
| Tipo | Qué ejercita | Velocidad | Coste de escritura | Fragilidad | Qué detecta |
|---|---|---|---|---|---|
| Unitaria | Una función o clase aislada | Milisegundos | Bajo | Baja | Errores de lógica y de cálculo |
| Integración | Varias piezas juntas (rutas + middleware + repositorio + BD) | Décimas a segundos | Medio | Media | Cableado, contratos entre capas, orden de middlewares |
| Extremo a extremo | El sistema completo con navegador o cliente real | Segundos a minutos | Alto | Alta | Flujos de usuario completos, problemas de despliegue |
| De contrato | El formato acordado entre dos servicios | Rápida | Medio | Baja | Cambios de API que romperían a un consumidor |
| De carga | El sistema bajo presión | Minutos | Alto | Alta | Cuellos de botella, degradación, límites de recursos |
Las tres primeras forman la pirámide de pruebas: muchas unitarias en la base, bastantes de integración en el medio, muy pocas de extremo a extremo en la punta.
graph TD
E2E["Extremo a extremo<br/>pocas · lentas · frágiles<br/>flujos críticos de compra"]
INT["Integración<br/>bastantes · medias<br/>rutas, middleware, repositorios, BD"]
UNI["Unitarias<br/>muchas · rapidísimas · estables<br/>dominio, política, utilidades"]
E2E --> INT
INT --> UNI
style E2E fill:#f8d7da,stroke:#842029
style INT fill:#fff3cd,stroke:#664d03
style UNI fill:#d1e7dd,stroke:#0f5132
La forma no es un capricho estético: es economía. Una prueba unitaria de puedeGestionarEvento tarda menos de un milisegundo y, cuando falla, te señala una función concreta. Una prueba de extremo a extremo del mismo permiso tarda diez segundos, puede fallar porque el navegador tardó en cargar, y cuando falla te dice "el botón no aparecía", que puede significar cincuenta cosas distintas.
El antipatrón del cono de helado
Cuando un equipo invierte la pirámide —muchísimas pruebas de extremo a extremo, algunas de integración, casi ninguna unitaria— obtiene el llamado cono de helado. Es un desastre reconocible por sus síntomas:
- La batería tarda 40 minutos y la gente deja de ejecutarla en local.
- Un cambio de una línea en una plantilla rompe treinta pruebas.
- Aparecen pruebas intermitentes (flaky): fallan una de cada cinco veces sin motivo aparente.
- Como fallan a menudo por ruido, el equipo empieza a reintentar hasta que pasen. En ese momento la batería ha dejado de aportar información y solo aporta espera.
La regla práctica: cada comportamiento se prueba al nivel más bajo que pueda demostrarlo. Sube de nivel solo cuando el nivel inferior no puede ver el problema.
Qué probar y qué no: el criterio del riesgo
Probarlo todo es imposible y perseguirlo produce baterías caras que envejecen mal. El criterio que usaremos es el riesgo, entendido como probabilidad de fallo multiplicada por el daño que causaría.
Sí se prueba:
- Lógica de negocio con reglas.
Sesion.vender()valida cantidad, aforo y estado. Si se equivoca, vendemos entradas que no existen. - La matriz de permisos. Un error aquí es una brecha de seguridad silenciosa.
- Cálculos. Totales en céntimos, límites de 6 entradas por pedido, ocupación, umbral de aforo bajo.
- El manejo de errores. Que
RecursoNoEncontradoacabe siendo un 404 con el formato{ error: { codigo, mensaje, estado, detalles } }. - Casos límite y frontera. Vender exactamente las últimas entradas, vender una más, cantidad cero, cantidad negativa.
- Todo fallo que haya ocurrido en producción. Antes de arreglarlo, una prueba que lo reproduzca. Volveremos a esto en 09-06.
No se prueba (o se prueba muy poco):
- Getters triviales. Si
get precioEuros() { return this.precioCentimos / 100; }merece una prueba es discutible; si tuviera redondeo, sí, porque ahí hay una decisión. - Librerías de terceros. No es tu trabajo comprobar que Express enruta o que bcrypt hashea. Sí lo es comprobar cómo las usas.
- Configuración estática. Que
PERMISOStenga cinco claves no dice nada; que un rol pueda o no usarlas, sí. - Detalles de implementación. Que un método llame internamente a otro método privado no es un comportamiento; es una decisión que quieres poder cambiar.
- Código generado. Migraciones autogeneradas, ficheros de arranque triviales.
Qué hace buena a una prueba
Cuatro propiedades, en orden de importancia:
- Rápida. Si la batería unitaria tarda más de unos segundos, dejarás de ejecutarla mientras programas.
- Determinista. El mismo código con la misma entrada da siempre el mismo resultado. Nada de
Date.now(),Math.random(), red o dependencia del orden. Todo eso lo domesticaremos con Sinon en 09-03. - Aislada. No depende de que otra prueba se haya ejecutado antes ni deja residuos para la siguiente.
- Con un solo motivo de fallo. Cuando se pone roja, debe quedar claro qué comportamiento se rompió.
Y una quinta que no es técnica pero decide si la batería sobrevive: el nombre debe describir el comportamiento esperado, no el método invocado. El nombre es lo único que verás en la salida cuando falle a las tres de la mañana.
| Nombre malo | Por qué es malo | Nombre bueno |
|---|---|---|
prueba vender |
No dice qué se espera | descuenta las localidades vendidas del aforo disponible |
test 1 |
No dice nada en absoluto | lanza ConflictoDeEstado si no quedan localidades suficientes |
funciona |
No es falsable | marca la sesion como agotada al vender la ultima entrada |
politica |
Demasiado amplio | permite al organizador de la sala editar su propio evento |
no falla |
Ausencia de error no es comportamiento | devuelve 422 si se piden mas de 6 entradas |
caso 3 del ticket 481 |
El ticket desaparecerá | impide que un asistente vea el pedido de otro asistente |
Fíjate en que todos los nombres buenos empiezan por un verbo en tercera persona y describen el efecto observable. Leídos junto al describe que los contiene forman una frase: Sesion vender — lanza ConflictoDeEstado si no quedan localidades suficientes.
Pruebas frágiles y falsos positivos
Hay dos fallos de calidad que arruinan baterías enteras.
Prueba frágil es la que se rompe cuando el código cambia sin que el comportamiento cambie. Casi siempre nace de probar la implementación en lugar del comportamiento:
// FRÁGIL: comprueba cómo está hecho por dentro
// Si mañana el gestor calcula el total con reduce en vez de un bucle,
// esta prueba falla sin que nada se haya roto para el usuario.
prueba('gestor llama a calcularSubtotal una vez por linea', () => {
const espia = espiarMetodoPrivado(gestor, 'calcularSubtotal');
gestor.registrarVenta(pedido);
comprobar(espia.llamadas === 2);
});
// ROBUSTO: comprueba qué se obtiene
prueba('el total del pedido suma el precio de todas sus lineas', () => {
const pedido = gestor.registrarVenta({ lineas: [
{ cantidad: 2, precioCentimos: 2500 },
{ cantidad: 1, precioCentimos: 1800 },
] });
comprobar(pedido.totalCentimos === 6800);
});Falso positivo (o falso verde) es la prueba que pasa siempre, incluso con el código roto. Es peor que no tener prueba, porque genera confianza infundada. Las causas más habituales en Node:
- Una promesa no esperada: el
ittermina antes de que la aserción se ejecute. Lo veremos en detalle en 09-02. - Una aserción dentro de un
catchque nunca se ejecuta. - Simular tanto la dependencia que la prueba solo comprueba tus propias suposiciones (el peligro central de 09-03).
Truco profesional que usaremos varias veces en el módulo: cuando escribas una prueba, rómpela a propósito. Cambia un signo en el código de producción y comprueba que se pone roja. Una prueba que nunca has visto fallar no es una prueba, es una esperanza.
TDD explicado con honestidad
El desarrollo dirigido por pruebas (Test-Driven Development) invierte el orden habitual: primero la prueba, después el código.
graph LR
R["ROJO<br/>escribe una prueba<br/>que falla"] --> V["VERDE<br/>el código mínimo<br/>que la hace pasar"]
V --> RF["REFACTOR<br/>mejora el diseño<br/>sin tocar la prueba"]
RF --> R
style R fill:#f8d7da,stroke:#842029
style V fill:#d1e7dd,stroke:#0f5132
style RF fill:#cfe2ff,stroke:#084298
Un ciclo completo sobre una regla real de Escena Viva: ningún pedido puede superar las 6 entradas por sesión.
Rojo. Escribimos la prueba antes de que exista la comprobación:
// La regla todavía no está implementada: esta prueba DEBE fallar.
prueba('rechaza un pedido de mas de 6 entradas para la misma sesion', () => {
const sesion = crearSesion({ aforo: 400, vendidas: 0 });
let lanzo = false;
try {
sesion.vender(7);
} catch (error) {
lanzo = true;
}
comprobar(lanzo === true);
});Ejecutamos y falla. Este paso no es burocracia: verifica que la prueba sabe detectar el fallo. Si pasara ya en rojo, la prueba estaría mal escrita.
Verde. El código mínimo que la satisface:
// src/dominio/sesion.js (fragmento)
const MAXIMO_POR_PEDIDO = 6;
vender(cantidad) {
if (!Number.isInteger(cantidad) || cantidad < 1) {
throw new ErrorDeValidacion('La cantidad debe ser un entero positivo');
}
if (cantidad > MAXIMO_POR_PEDIDO) {
throw new ErrorDeValidacion(`Maximo ${MAXIMO_POR_PEDIDO} entradas por pedido`);
}
// ...resto de la lógica de aforo
}Refactor. Ahora sí mejoramos: extraemos MAXIMO_POR_PEDIDO a una constante exportada para que el esquema zod y el mensaje de error usen el mismo número, y añadimos el detalles del error con el máximo permitido. La prueba nos protege durante el cambio.
Y ahora la honestidad prometida:
| TDD ayuda mucho cuando... | TDD estorba cuando... |
|---|---|
| La regla de negocio está clara y es verificable | Estás explorando una API que no conoces |
| Arreglas un fallo (la prueba lo reproduce primero) | Maquetas una interfaz visual |
| Diseñas una función pura, como la política de permisos | El diseño va a cambiar tres veces esta tarde |
| Trabajas sobre código legado y quieres fijar el comportamiento actual | Escribes un script de un solo uso |
No es una religión. En este curso escribiremos algunas pruebas antes y muchas después, y en 09-06 usaremos TDD de forma estricta para una cosa concreta en la que es indiscutible: reproducir un fallo antes de arreglarlo.
El panorama de herramientas para Node
| Herramienta | Qué es | Puntos fuertes | Inconvenientes |
|---|---|---|---|
| Mocha | Ejecutor de pruebas | Maduro, flexible, no impone aserciones ni dobles, configuración transparente | Hay que montar la pila (Chai, Sinon) tú mismo |
| Chai | Librería de aserciones | expect muy legible, mensajes de fallo claros, extensible |
Dependencia extra |
| Sinon | Dobles de prueba | Espías, stubs, relojes falsos, el estándar de facto | Fácil de abusar |
| supertest | Cliente HTTP para pruebas | Prueba una app de Express sin listen manual |
Solo HTTP |
| c8 / nyc | Cobertura | c8 usa la cobertura nativa de V8, sin instrumentar | Métrica fácil de malinterpretar |
| Jest | Todo en uno | Ejecutor, aserciones, mocks y cobertura juntos; instantáneas | Opinado; su transformación complica el CommonJS/ESM puro |
| Vitest | Todo en uno moderno | Rapidísimo, API compatible con Jest, gran soporte ESM | Nació en el mundo Vite; menos común en APIs puras de Node |
node:test |
Ejecutor nativo | Cero dependencias, incluido en Node, con --test y cobertura integrada |
API más joven, ecosistema de complementos menor |
El ejecutor nativo merece un párrafo honesto. Desde Node 20 es estable y perfectamente utilizable:
// Cómo se vería con el ejecutor nativo (referencia, no lo usaremos)
const { test } = require('node:test');
const assert = require('node:assert/strict');
test('descuenta las localidades vendidas del aforo', () => {
const sesion = crearSesion({ aforo: 400, vendidas: 100 });
sesion.vender(3);
assert.equal(sesion.libres, 297);
});Si empezaras un proyecto nuevo hoy, node:test es una elección defendible y sin dependencias.
Por qué este curso usa Mocha + Chai + Sinon + supertest: porque es la pila más extendida en las APIs de Node que te vas a encontrar en producción, porque separa con claridad las tres responsabilidades (ejecutar, afirmar, simular) y eso enseña mejor los conceptos, porque su documentación de errores es explícita, y porque las ideas se trasladan a cualquier otra pila en una tarde. Elegida la pila, no cambiaremos a mitad del módulo: mezclar ejecutores es una fuente clásica de confusión.
El plan de pruebas de Escena Viva
Este es el recorrido del módulo:
| Lección | Qué se prueba | Herramientas |
|---|---|---|
| 09-02 | Dominio puro: Sesion, Evento, GestorDeVentas, y la matriz completa de politica.js |
Mocha, Chai |
| 09-03 | Unidades con dependencias: cambio-divisas.js, tokens que caducan, repositorios |
Sinon |
| 09-04 | La API real de punta a punta: compra, rechazos 401/403/404/409/422, concurrencia | supertest |
| 09-05 | Cobertura, umbrales, scripts de npm, pruebas intermitentes, preparación para CI | c8 |
| 09-06 | Depuración de lo que falle: inspector, VS Code, trazas, fugas de memoria | Node y DevTools |
La estructura de carpetas que crearemos, espejo de src/:
escena-viva/
├── src/
│ ├── dominio/
│ ├── autorizacion/
│ ├── repositorios/
│ └── ...
├── test/
│ ├── unidad/
│ │ ├── sesion.test.js
│ │ ├── evento.test.js
│ │ ├── politica.test.js
│ │ └── gestor-ventas.test.js
│ ├── integracion/
│ │ ├── eventos.test.js
│ │ └── pedidos.test.js
│ └── ayudas/
│ ├── fabricas.js
│ └── autenticacion.js
└── .mocharc.jsonTres convenciones que seguiremos sin excepción:
- Sufijo
.test.jsen todos los ficheros de prueba: hace trivial el patrón de búsqueda de Mocha y distingue las pruebas de las ayudas. - Espejo del código fuente:
src/dominio/sesion.jsse prueba entest/unidad/sesion.test.js. Encontrar la prueba de un fichero nunca debe requerir una búsqueda. test/ayudas/no contiene pruebas, solo utilidades compartidas: fábricas de datos y la ayuda de autenticación que resolverá la promesa del módulo 8.
Errores Comunes y Consejos
- Escribir pruebas para subir un número. La cobertura es un indicador, no un objetivo. Lo trataremos a fondo en 09-05, pero interiorízalo ya: una prueba que ejecuta código sin comprobar nada sube la cobertura y no protege de nada.
- Empezar por las pruebas de extremo a extremo porque "prueban de verdad". Acabarás con el cono de helado y una batería que nadie ejecuta.
- Probar métodos privados. Si sientes esa necesidad, normalmente esa lógica quiere ser una función pública en otro módulo.
#vendidasse prueba a través delibresyagotada. - Pruebas que dependen del orden. "Funciona si ejecutas todo el fichero pero falla sola" es el síntoma. Cada
itdebe poder ejecutarse en solitario. - Reutilizar objetos entre pruebas para "no repetir". Compartir un objeto mutable entre
ites la causa número uno de pruebas intermitentes. Usa fábricas que devuelvan objetos nuevos. - Consejo: empieza por la capa de mayor riesgo y menor coste. En Escena Viva eso es
src/autorizacion/politica.js: funciones puras, sin dependencias, protegiendo lo más sensible del sistema. Se prueba entera en cincuenta líneas. - Consejo: trata el código de las pruebas como código de producción. Se lee más veces de las que se escribe y hay que mantenerlo.
Ejercicios
Ejercicio 1: clasificar por nivel
Para cada comportamiento de Escena Viva, indica a qué nivel de la pirámide lo probarías y por qué:
- El total de un pedido de 2 entradas a 2500 céntimos es 5000.
POST /api/pedidossin cabeceraAuthorizationdevuelve 401.- Un organizador de
org-bovedano puede editarevt-001, que pertenece aorg-almendra. - El middleware
limiteComprase aplica antes que el controlador de pedidos. hashearContrasenausa coste 12.
Ejercicio 2: reescribir nombres
Reescribe estos nombres de prueba siguiendo las reglas de la lección:
test comprarEntradaspolitica funciona bienerror 409no peta con cantidad 0
Ejercicio 3: diseñar un ciclo TDD
Escribe (en pseudocódigo, sin ejecutar) el ciclo rojo-verde-refactor para esta regla nueva: una sesión que ya ha comenzado no admite ventas. Indica qué prueba escribirías primero, qué código mínimo la haría pasar y qué refactorizarías después.
Soluciones
Ejercicio 1
- Unitaria. Es un cálculo puro en el dominio; no necesita HTTP ni base de datos.
- Integración. El 401 nace de la combinación ruta + middleware
autenticar+manejadorDeErrores. Ninguna prueba unitaria del middleware garantiza que esté realmente montado en esa ruta. - Unitaria, con
puedeGestionarEvento, porque es una función pura y podemos recorrer la matriz entera barata y exhaustivamente. Además una prueba de integración de confirmación (403 real por HTTP), no las treinta. - Integración. El orden de los middlewares solo es observable ejecutando la aplicación real: es exactamente lo que las pruebas unitarias no pueden ver.
- Ninguna, o casi. Es una constante de configuración. Probar el coste exacto de bcrypt es probar la librería; sí tiene sentido una prueba de que
verificarContrasenaacepta el hash que producehashearContrasena(comportamiento, no detalle).
Ejercicio 2
crea un pedido con estado pendiente y descuenta el aforo de la sesionpermite al administrador gestionar cualquier eventodevuelve ConflictoDeEstado si las localidades libres son menores que las solicitadaslanza ErrorDeValidacion si la cantidad es cero
Ejercicio 3
Rojo: prueba rechaza la venta si la sesion ya ha comenzado, que crea una sesión con inicio en el pasado, llama a vender(1) y espera un ConflictoDeEstado. Falla porque vender no mira la fecha.
Verde: añadir al principio de vender una comprobación if (new Date(this.inicio) <= new Date()) { throw new ConflictoDeEstado('La sesion ya ha comenzado'); }.
Refactor: extraer un getter get haComenzado() que encapsule la comparación, reutilizable por el catálogo para no listar sesiones pasadas, e inyectar el reloj en lugar de llamar a new Date() directamente. Ese último punto es justo lo que hace posible la lección 09-03: el código que depende del reloj real no se puede probar de forma determinista.
Conclusión
Hemos puesto los cimientos. Sabemos por qué se prueba —para poder cambiar el código sin miedo, no por si acaso—, cómo se estructura una prueba con preparar, actuar y comprobar, qué niveles existen y por qué la pirámide tiene la forma que tiene, qué merece prueba según el riesgo y qué no, qué propiedades hacen buena a una prueba, cómo distinguir una prueba frágil de una robusta, cuándo TDD ayuda de verdad y qué herramientas hay en el ecosistema de Node.
También tenemos el plan: test/unidad/, test/integracion/, test/ayudas/, ficheros *.test.js, y la pila Mocha + Chai + Sinon + supertest.
Lo que no tenemos todavía es una sola línea ejecutable. En la lección siguiente, Pruebas Unitarias con Mocha y Chai, instalamos la pila, arreglamos de una vez el script test que lleva cuatro módulos fallando a propósito, y escribimos la batería unitaria completa del dominio de Escena Viva, incluida esa tabla de casos que recorre la matriz de permisos celda por celda que llevamos prometiendo desde el módulo 8.
Curso de Node.js: De Principiante a Avanzado
Módulo 1: Introducción a Node.js
- ¿Qué es Node.js?
- Instalación y Configuración del Entorno
- Tu Primer Programa en Node.js
- El REPL de Node.js
- JavaScript Moderno para Node.js
- El Proyecto del Curso: la Plataforma Escena Viva
Módulo 2: Conceptos Básicos
- Arquitectura de Node.js
- El Bucle de Eventos (Event Loop)
- Callbacks y Programación Asíncrona
- Promesas y async/await
- Eventos y EventEmitter
- Módulos CommonJS y require()
- Módulos ES e Interoperabilidad
Módulo 3: Sistema de Archivos y E/S
- Lectura y Escritura de Archivos
- El Módulo fs a Fondo
- Rutas Multiplataforma con el Módulo path
- Trabajando con Streams
- Streams de Transformación y pipeline
- Buffers y Datos Binarios
Módulo 4: HTTP y Servidores Web
- Creando un Servidor HTTP Simple
- Manejo de Solicitudes y Respuestas
- Enrutamiento Manual
- Sirviendo Archivos Estáticos
- Recibiendo Datos: Cuerpos de Petición y JSON
- Consumiendo APIs Externas desde Node.js
Módulo 5: NPM y Gestión de Paquetes
- Introducción a NPM y package.json
- Instalación y Uso de Paquetes
- Versionado Semántico y package-lock
- Scripts de npm y Automatización del Proyecto
- Creación y Publicación de Paquetes
- Seguridad y Mantenimiento de Dependencias
Módulo 6: Framework Express.js
- Introducción a Express.js
- Configuración de una Aplicación Express
- Enrutamiento en Express
- Middleware
- Middleware de Terceros Esenciales
- Validación de Datos de Entrada
- Manejo de Errores
Módulo 7: Bases de Datos y ORMs
- Introducción a las Bases de Datos
- Usando MongoDB con Mongoose
- Operaciones CRUD
- Relaciones, Poblado y Consultas Avanzadas
- Usando Bases de Datos SQL con Sequelize
- Migraciones, Transacciones y Datos de Prueba
Módulo 8: Autenticación y Autorización
- Introducción a la Autenticación
- Registro de Usuarios y Hash de Contraseñas
- Sesiones y Cookies con Passport.js
- Autenticación con JWT
- Control de Acceso Basado en Roles
- Buenas Prácticas de Seguridad en APIs
Módulo 9: Pruebas y Depuración
- Introducción a las Pruebas
- Pruebas Unitarias con Mocha y Chai
- Dobles de Prueba con Sinon
- Pruebas de Integración
- Cobertura y Automatización de las Pruebas
- Depuración de Aplicaciones Node.js
Módulo 10: Temas Avanzados
- El Módulo Cluster
- Hilos de Trabajo (Worker Threads)
- Caché y Colas de Trabajo con Redis
- Optimización del Rendimiento
- Construcción de APIs RESTful
- GraphQL con Node.js
Módulo 11: Despliegue y DevOps
- Configuración y Variables de Entorno
- Registro y Monitorización en Producción
- Usando PM2 para la Gestión de Procesos
- Empaquetado con Docker
- Desplegando en Heroku y Otras PaaS
- Integración y Despliegue Continuos
