Testing
El backend se desarrolla con TDD. El frontend y el mobile, no.
En oxitesa-front y oxitec-mobile-app no hay specs y no hay que escribirlos: se validan con
tsc --noEmit, el build, y revisión visual del usuario.
Comandos (backend)
npm test # toda la suite
npm run test:watch
npm run test:coverage # → coverage/
npm run test:docker # la suite dentro de node:20-slim (requiere Docker Desktop)
npx jest tests/unit/GrantUtils.test.ts # un archivo
npx jest -t "devuelve true para una ruta" # por nombre del test
Lo importante: MySQL y Redis están mockeados
tests/setup/mockConnections.ts (registrado en setupFiles) mockea la conexión a base y a Redis en
todas las suites. Ningún test toca MySQL, MSSQL ni Redis reales.
Para stubear datos en un test, importá el singleton (ya mockeado) y usá las factories de
tests/mocks/typeorm.ts:
createMockRepository()
createMockQueryRunner()
createMockDataSource()
La plantilla mínima está en tests/unit/mocks.smoke.test.ts.
Estructura
tests/
├── unit/ unidades puras (SearchUtils, SpErrorUtils, GrantUtils, middlewares…)
├── integration/ app.e2e.test.ts — Supertest, hoy en describe.skip
├── modules/ el grueso de la suite, por dominio:
│ ├── deliveryNote/ entrega · visita · retiro · cancelacion · comentarios ·
│ │ list · reclasificacion
│ ├── dispatch/ hojas de ruta: creación, editar, fallar/reanudar/transferir
│ │ tarea, reordenar, optimizar ruta, reservas, stock de vehículo
│ ├── mercaderia/ ingreso, transferencia, unicidad de serial
│ ├── patient/ carga de suministros
│ └── reports/
├── mocks/ setup/ utils/
Los *.integration.test.ts de tests/modules/ siguen usando los mocks globales. Acá
"integration" quiere decir que ejercitan varias capas, no que peguen a una base.
Cada carpeta grande tiene su test.md con el inventario de casos cubiertos.
Dos suites que no son Jest
1. Tests SQL de los stored procedures
oxitesa-backend/migrations/finances/test/*.sql. Corren contra una base real (PRE) y son la
única forma de probar el pipeline de cierre de verdad.
Patrón: abrir transacción → crear entidades frescas → assertions → ROLLBACK. Aislamiento total
del entorno productivo.
- Naming:
T<sección>.<n>(T2.3,T_BUG_CART_1,T_DN13701_REPRO). - Las constantes se resuelven por CODE, nunca por id hardcodeado.
- El catálogo grande es
transaction_close_delivery_note_edge_cases.sql. - Bugs conocidos y sus fixes:
test/SP_BUGS_FOUND.md.
2. Entorno Docker reproducible
Dockerfile.test (node:20-slim, npm ci) + docker-compose.test.yml corren la suite Jest en un
contenedor, con instalación determinística desde el lockfile. No levanta MySQL ni Redis: todo está
mockeado.
npm run test:docker
Husky
| Hook | Qué corre |
|---|---|
| pre-commit | lint-staged: Prettier + ESLint + jest --findRelatedTests solo sobre lo staged |
| pre-push | audit:whitelist + la suite completa |
Para que --findRelatedTests pueda mapear src/ → tests, jest.config.js incluye src en roots
(y testMatch restringe los specs a tests/).
No uses --no-verify salvo emergencia real.
Gotchas
TESTS=true cambia el comportamiento de producciónjest.setup.ts carga el .env y fuerza TESTS=true. Con esa variable puesta:
unhandledExceptiondevuelve el mensaje crudo del error al cliente.logRequestpersiste enErrorLog(sin ella, no persiste nada).
No la dejes seteada fuera de tests.
- El e2e con Supertest está en
describe.skipporque arrastra el bootstrap completo (controllers + módulos), no porque necesite servicios externos. Se puede habilitar. - Los tests compilan con
tsconfig.test.jsony los alias de path se resuelven pormoduleNameMapperde Jest. Si agregás un alias nuevo, tenés que ponerlo en los dos lados.