Skip to main content

Casos de prueba — Bootstrap, Config, Seeds y E2E

Specs de src/bootstrap/**, src/config/**, src/database/** y test/app.e2e-spec.ts.

Resumen: 8 archivos spec, 59 bloques it() declarados. En env.validation.spec.ts un describe.each repite 6 casos para 2 claves, por lo que se ejecutan 13 tests en ese archivo.

Los specs de migraciones y de seeds usan mongodb-memory-server (MongoDB real en memoria), no mocks de driver.

src/bootstrap/cors.spec.ts​

setupCors​

TestEscenarioResultado esperadoMocks
should call enableCors with origin:true and credentials:trueNODE_ENV=developmentenableCors recibe origin: true y credentials: trueApp Nest falsa (enableCors jest.fn)
should include all HTTP methodsNODE_ENV=developmentconfig.methods es igual a CORS_METHODSApp falsa
should use wildcard allowedHeaders in non-productionNODE_ENV=developmentallowedHeaders es '*'App falsa
should use restricted allowedHeaders in productionNODE_ENV=productionallowedHeaders es CORS_ALLOWED_HEADERS_PRODApp falsa
should use wildcard allowedHeaders when NODE_ENV is undefinedNODE_ENV eliminadoallowedHeaders es '*'App falsa

cors constants​

TestEscenarioResultado esperadoMocks
CORS_METHODS should contain standard HTTP methodsSe lee la constanteContiene GET, POST, PUT, PATCH, DELETE y OPTIONSNinguno
CORS_ALLOWED_HEADERS_PROD should include Content-Type and AuthorizationSe lee la constanteIncluye Content-Type y AuthorizationNinguno
NODE_ENV.PRODUCTION should equal "production"Se lee la constanteEs 'production'Ninguno

src/bootstrap/load-env.spec.ts​

Cada test corre en un directorio temporal (cwd cambiado) y restaura process.env al finalizar.

loadEnv​

TestEscenarioResultado esperadoMocks
does nothing when .env does not existDirectorio sin .envNo lanza error y BASE_ONLY queda sin definirSistema de archivos temporal
loads values from the base .env file.env con BASE_ONLY=base-valueprocess.env.BASE_ONLY es base-valueArchivo .env temporal
never overwrites a value already present in process.env before .env loadsPRE_SET ya definido y distinto en .envSe conserva already-setArchivo .env temporal

src/bootstrap/migration-001-ensure-catalog-indexes.spec.ts​

Prueba el archivo real migrations/001-ensure-catalog-indexes.js cargado con loadMigrations: colapsa duplicados de módulos y permisos por acrónimo y crea índices únicos globales.

001-ensure-catalog-indexes​

TestEscenarioResultado esperadoMocks
is a safe no-op against an empty databaseBase vacíaup resuelve y modules/permissions siguen con 0 documentosmongodb-memory-server
is a safe no-op against an already-collapsed database (one doc per acronym)Un módulo, un permiso y un role-permission ya consistentesConteos intactos y permissions[] del role-permission sin cambiosmongodb-memory-server
collapses duplicate Module docs by acronym down to one deterministic survivorDos módulos USER, el más nuevo se inserta primeroQueda uno solo: el de createdAt más antiguomongodb-memory-server
rewires Permission.moduleId from a deleted duplicate Module onto its survivorUn permiso apunta al módulo duplicado que se eliminamoduleId pasa al módulo sobrevivientemongodb-memory-server
collapses duplicate Permission docs by acronym down to one deterministic survivorDos permisos USER_CREATE, el más nuevo se inserta primeroQueda solo el más antiguomongodb-memory-server
rewires and de-duplicates RolePermission.permissions[] when it referenced both tenant-duplicate ids for the same acronymUn role-permission referencia ambos ids duplicados más un permiso distintopermissions[] queda con el sobreviviente y el otro permiso, sin duplicadomongodb-memory-server
drops a RolePermission reference to a permission that no longer exists at all (truly orphaned)Referencia a un permiso inexistenteLa referencia huérfana se eliminamongodb-memory-server
every surviving Permission still points at a Module that exists after collapsing bothMódulos y permisos duplicados a la vezUn solo permiso, cuyo moduleId existe en modulesmongodb-memory-server
creates a unique acronym-only index on modules (not the old tenantId compound one)Se ejecuta upExiste índice único solo por acronym y no existe tenantId_1_acronym_1mongodb-memory-server
creates a unique acronym-only index on permissions (not the old tenantId compound one)Se ejecuta upIgual que el anterior, sobre permissionsmongodb-memory-server
actually enforces global uniqueness on modules once createdSe inserta dos veces el mismo acronymLa segunda inserción es rechazadamongodb-memory-server
actually enforces global uniqueness on permissions once createdSe inserta dos veces el mismo acronymLa segunda inserción es rechazadamongodb-memory-server
is idempotent — running it twice does not throwSe ejecuta up dos vecesNo lanza y queda un solo módulomongodb-memory-server

src/bootstrap/migration-002-ensure-role-grant-indexes.spec.ts​

Prueba migrations/002-ensure-role-grant-indexes.js cargada con loadMigrations.

002-ensure-role-grant-indexes​

TestEscenarioResultado esperadoMocks
creates a unique (tenantId, acronym) index on rolesSe ejecuta upExiste índice único compuesto tenantId + acronym en rolesmongodb-memory-server
creates a unique (tenantId, roleId, acronym) index on role-permissionsSe ejecuta upExiste índice único tenantId + roleId + acronym en role-permissionsmongodb-memory-server
is idempotent — running it twice does not throwSe ejecuta up dos vecesLa segunda ejecución resuelve sin errormongodb-memory-server
actually enforces uniqueness on roles once createdSe inserta dos veces el mismo tenantId + acronymLa segunda inserción es rechazadamongodb-memory-server
actually enforces uniqueness on role-permissions once createdSe inserta dos veces el mismo tenantId + roleId + acronymLa segunda inserción es rechazadamongodb-memory-server

src/bootstrap/run-migrations.spec.ts​

loadMigrations​

TestEscenarioResultado esperadoMocks
returns an empty array when the migrations directory does not existRuta inexistenteDevuelve []Directorio temporal
loads .js files sorted by filename regardless of write orderArchivos 010, 001, 002 y un README.mdSolo los .js, ordenados: first, second, thirdArchivos temporales
throws a clear error when a file does not export { name, up }Archivo que exporta { run }Lanza error Invalid migration fileArchivo temporal

applyMigrations / runMigrations — applyMigrations​

TestEscenarioResultado esperadoMocks
runs pending migrations in the given order and records themDos migraciones pendientesSe ejecutan en orden, resultado { applied: ['mig-a','mig-b'], skipped: [] } y quedan registradas en migrationsmongodb-memory-server
does not re-run a migration already recorded in the tracking collectionSe aplica dos veces la misma migración1.ª ejecución la aplica, 2.ª la omite; up se llama una vezjest.fn para up
does not run up() again for a name concurrently claimed by another callerYa existe el registro de seguimiento (carrera TOCTOU)Resultado skipped y up no se llamajest.fn para up
rolls back the claim when up() throws, so the migration remains retryableup falla la primera vez y funciona la segundaLanza boom, no queda registro y el reintento la aplica (up llamado 2 veces)jest.fn (rechaza una vez)

applyMigrations / runMigrations — runMigrations​

TestEscenarioResultado esperadoMocks
connects, applies pending migrations from disk, and is idempotent on a second runUna migración en disco, dos ejecuciones1.ª applied: ['create-marker'], 2.ª skipped: ['create-marker']Archivo temporal, mongodb-memory-server
returns empty results without connecting when there are no migration filesDirectorio sin migraciones{ applied: [], skipped: [] }Directorio temporal

runMigrationsIfEnabled​

TestEscenarioResultado esperadoMocks
skips entirely when MIGRATION_DB is unsetEntorno {}{ ranMigrations: false, applied: [], skipped: [] }Entorno inyectado
skips entirely when MIGRATION_DB is 'false'MIGRATION_DB='false'Mismo resultado: no correEntorno inyectado
requires an exact lowercase match — "TRUE" is treated as disabledMIGRATION_DB='TRUE'No corre (solo true en minúscula habilita)Entorno inyectado
never attempts a database connection when disabled, even with a garbage MONGODB_URIDeshabilitado y MONGODB_URI inválidaResultado de omitido, sin intentar conectarEntorno inyectado

src/config/env.validation.spec.ts​

Valida el esquema Joi envValidationSchema con un entorno base válido. El describe.each se ejecuta para WHATSAPP_SESSION_ENCRYPTION_KEY y META_TOKEN_ENCRYPTION_KEY.

envValidationSchema — %s (describe.each, 2 variantes)​

TestEscenarioResultado esperadoMocks
passes validation with a valid base64-encoded 32-byte keyClave base64 de 32 bytesSin error y el valor se conservaNinguno
fails validation when the key is missing entirelyVariable ausenteError <VAR> is requiredNinguno
fails validation when the key is an empty stringVariable ''Error <VAR> is requiredNinguno
fails validation when the decoded key is shorter than 32 bytesClave de 16 bytesError <VAR> must be a base64-encoded 32-byte keyNinguno
fails validation when the decoded key is longer than 32 bytesClave de 48 bytesError <VAR> must be a base64-encoded 32-byte keyNinguno
does NOT silently fall back to a default — an invalid key never passesClave not-even-close-to-32-bytesHay error (no se usa valor por defecto)Ninguno

En la tabla, <VAR> representa el nombre de la variable de la variante en curso.

envValidationSchema — key isolation​

TestEscenarioResultado esperadoMocks
rejects a Meta key equal to the WhatsApp keyMETA_TOKEN_ENCRYPTION_KEY igual a la clave de WhatsAppError META_TOKEN_ENCRYPTION_KEY must be a base64-encoded 32-byte key different from WHATSAPP_SESSION_ENCRYPTION_KEYNinguno

src/database/seeds/seed.service.spec.ts​

SeedService contra MongoDB en memoria con los modelos reales; TenantService, repositorio y PermissionCatalogSeedService reales. Restaura variables de entorno (APP_ENV, RUN_SEEDS, FORCE_SEED_CLEANUP, MIGRATION_DB_DATA) tras cada test.

SeedService (mongodb-memory-server) — onApplicationBootstrap​

TestEscenarioResultado esperadoMocks
does nothing when APP_ENV is not "development", regardless of RUN_SEEDSAPP_ENV=production, RUN_SEEDS=falserun no se invocaSpy de service.run
logs an error (does not throw) when APP_ENV is not development but RUN_SEEDS==="true"APP_ENV=staging, RUN_SEEDS=trueNo lanza, run no se invoca y se registra un errorSpy de run y del logger
does nothing when APP_ENV==="development" but RUN_SEEDS is not "true"Development sin RUN_SEEDSrun no se invocaSpy de run
calls run() when APP_ENV==="development" and RUN_SEEDS==="true"Development, RUN_SEEDS=true, FORCE_SEED_CLEANUP=truerun se llama con { force: true }Spy de run

SeedService (mongodb-memory-server) — run — defense in depth​

TestEscenarioResultado esperadoMocks
throws when called directly with APP_ENV not developmentAPP_ENV=production y run({ count: 1 })Rechaza con APP_ENV is not "development"Ninguno

SeedService (mongodb-memory-server) — run — force cleanup​

TestEscenarioResultado esperadoMocks
wipes only the 8 in-scope collections, leaving an unrelated collection (Role) untouchedDatos previos en tenants, labels, roles, departments, users y department-users; run({ force: true, count: 0 })Las 8 colecciones en alcance quedan en 0 y el Role previo sobreviveMongoDB en memoria

SeedService (mongodb-memory-server) — run — non-destructive default (force=false)​

TestEscenarioResultado esperadoMocks
skips seeding entirely when the tenants collection already has dataYa existe un tenant y run({ force: false, count: 5 })Sigue habiendo 1 tenant y 0 usuarios y contactosMongoDB en memoria

SeedService (mongodb-memory-server) — run — roleId lookup failure​

TestEscenarioResultado esperadoMocks
throws a clear, actionable error when a created tenant has no ADMIN/AGENT rolesMIGRATION_DB_DATA sin definir, por lo que no se siembran rolesRechaza con un error que menciona MIGRATION_DB_DATA=true y no se crea ningún usuarioMongoDB en memoria

SeedService (mongodb-memory-server) — run — happy path​

TestEscenarioResultado esperadoMocks
seeds one full tenant with users (real roleIds), contacts, labels, tickets and messagesAPP_ENV=development, MIGRATION_DB_DATA=true, run({ count: 1 })Un tenant con 2 roles; usuarios con roleId real; labels, departamentos, asignaciones que cubren todos los departamentos, contactos, tickets con departamento válido y mensajes con timestamps variados (timeout 30 s)MongoDB en memoria

test/app.e2e-spec.ts​

AppController (e2e)​

TestEscenarioResultado esperadoMocks
/ (GET)Se levanta AppModule completo y se hace GET / con supertestStatus 200 y cuerpo Hello World!Ninguno (aplicación real)

Casos it() documentados en esta página: 59 (8 + 3 + 13 + 5 + 13 + 7 + 9 + 1 en el orden de las secciones: cors, load-env, migration 001, migration 002, run-migrations, env.validation, seeds, e2e).