Skip to main content

Casos de prueba: Conexiones

Casos de prueba del módulo de conexiones: servicio, repositorio (incluyendo whatsappConfig y metaConfig cifrado), DTO de configuración web y helper de teléfonos.

Specs fuente (bajo src/app/modules/connection):

  • services/connection.service.spec.ts
  • repositories/connection.repository.spec.ts
  • repositories/connection.repository.meta.integration.spec.ts
  • dtos/connection-web-config.dto.spec.ts
  • helpers/phone.helper.spec.ts

Resumen: 5 archivos spec, 18 bloques describe y 51 casos it() (cada it.each cuenta como un caso).


connection.service.spec.ts​

Tests unitarios con ConnectionRepository y TranslateService mockeados.

ConnectionService / create​

TestEscenarioResultado esperadoMocks
creates a web connection scoped to the tenantcreate con DTO webLlama a repository.create con tenant y DTO y devuelve lo creadorepository
defaults the name when the minimal create omits itDTO web sin nombreSe crea con el nombre Web Chat Connectionrepository
rejects channelType "%s" with 400 channel not available (it.each: whatsapp-cloud, facebook, instagram)Crear con un canal no disponible por esta víaBadRequestException, traducción de CHANNEL_NOT_AVAILABLE y no se llama a repository.createrepository, translate
creates a whatsapp-qr connection with status=pending and emits "created"Crear canal whatsapp-qrcreate con status: PENDING, devuelve lo creado y emite el evento createdrepository, listener
defaults the name to the WhatsApp-specific constant when a whatsapp-qr create omits itwhatsapp-qr sin nombreUsa DEFAULT_WHATSAPP_CONNECTION_NAMErepository
does NOT force a status override or emit "created" for the web channelCrear conexión webcreate recibe el DTO tal cual (sin forzar estado) y no se emite createdrepository, listener

findAll​

TestEscenarioResultado esperadoMocks
returns all connections when no pagination is givenSin página ni límiteDevuelve results y no usa findAllPaginatedrepository
delegates to findAllPaginated when page and limit are givenPágina 2, límite 10 y filtro por nombreLlama a findAllPaginated con tenant, página, límite y filtrorepository

findOne / update / remove​

TestEscenarioResultado esperadoMocks
findOne throws NotFoundException when missingfindById devuelve nullNotFoundExceptionrepository
update returns the updated documentupdate devuelve el documentoDevuelve el documento actualizadorepository
update throws NotFoundException when missingupdate devuelve nullNotFoundExceptionrepository
remove throws NotFoundException when missingdelete devuelve nullNotFoundExceptionrepository
regenerateToken returns the document with the fresh tokenRegenerar tokenLlama al repositorio con ObjectId y tenant y devuelve el documento con el token nuevorepository
regenerateToken throws NotFoundException when missingregenerateToken devuelve nullNotFoundExceptionrepository

connection.repository.spec.ts​

Test de integración con MongoDB en memoria (mongodb-memory-server) y modelo real.

ConnectionRepository — integration (mongodb-memory-server) / create​

TestEscenarioResultado esperadoMocks
stores the document with tenantId and returns itCrear conexión webDocumento con _id, tenant, nombre y dominios permitidosninguno (Mongo en memoria)
generates a unique UUID token and defaults status to connectedCrear dos conexionesTokens con formato UUID y distintos; estado por defecto CONNECTEDninguno
applies business defaults (messages, attention tab)Crear conexiónSaludo y despedida vacíos, sin departamentos, reopenToleranceMinutes 15 y returnToLastAgent trueninguno

updateWhatsappConfig​

TestEscenarioResultado esperadoMocks
creates whatsappConfig from null on the first writewhatsappConfig nace en null y se escribe sessionState y phoneJidSe crea el subobjeto sin error y se guardan ambos camposninguno
keeps previously stored fields on a partial writeEscritura parcial tras sessionState: qr con lastQrAtlastQrAt se conserva y sessionState pasa a connected (merge, no reemplazo)ninguno
mirrors the fine-grained state onto Connection.statusconnected y luego logged_outstatus pasa a CONNECTED y luego a DISCONNECTEDninguno
maps qr and connecting to pendingsessionState: qrstatus es PENDINGninguno

regenerateToken​

TestEscenarioResultado esperadoMocks
issues a fresh UUID and the old token stops resolvingRegenerar el tokenNuevo UUID distinto; findByToken con el viejo devuelve null y con el nuevo devuelve la conexiónninguno
never crosses tenantsRegenerar con otro tenantDevuelve nullninguno

findByToken​

TestEscenarioResultado esperadoMocks
resolves a connection by its public token regardless of tenantBuscar por token públicoDevuelve la conexiónninguno
returns null for an unknown tokenToken nopeDevuelve nullninguno

tenant scoping​

TestEscenarioResultado esperadoMocks
findAll / findById / update / delete never cross tenantsConexiones de dos tenants y operaciones con el tenant equivocadofindAll solo devuelve las propias; findById, update y delete con otro tenant devuelven null; el update del dueño sí funcionaninguno

findAllPaginated​

TestEscenarioResultado esperadoMocks
paginates and filters by name and channelTypeTres conexiones; filtro por nombre sitio (página 1, límite 2) y por canal webtotal 2 con 2 resultados por nombre y total 3 por canalninguno

connection.repository.meta.integration.spec.ts​

Test de integración con MongoDB en memoria y clave de cifrado de tokens Meta definida en el entorno.

ConnectionRepository — metaConfig (integration) / unique index on channelType + metaConfig.accountId​

TestEscenarioResultado esperadoMocks
still allows several web connections in the same tenantDos conexiones web y una whatsapp-qr en el mismo tenantLas 3 se crean (el índice único no afecta a canales sin cuenta Meta)ninguno
rejects the same Instagram account connected twice, even across tenantsMisma cuenta Instagram en dos tenantsLa segunda falla con error de clave duplicada (código 11000)ninguno
allows the same account id on instagram and facebookMismo accountId en Instagram y FacebookAmbas conexiones se creanninguno

setMetaConfig​

TestEscenarioResultado esperadoMocks
persists the token as an encrypted envelope, never as plaintextGuardar metaConfig y leer el documento crudoEl token es un objeto con iv, tag y ciphertext; el texto plano no aparece en el documentoninguno
clears a previous authErrorAt on re-authorizationConexión con authErrorAt y nueva autorizaciónauthErrorAt queda en nullninguno
is scoped by tenantsetMetaConfig con otro tenantDevuelve null y la conexión conserva metaConfig en nullninguno

the access token never leaves through regular reads​

TestEscenarioResultado esperadoMocks
findByIdLectura normalEl JSON no contiene accessToken ni ciphertextninguno
findAllListadoEl JSON no contiene accessToken ni ciphertextninguno
findAllPaginatedListado paginadoEl JSON no contiene accessToken ni ciphertextninguno
setMetaConfig own return valueValor de retorno de setMetaConfigEl JSON no contiene accessToken ni ciphertextninguno
update and regenerateTokenRetorno de update y de regenerateTokenNinguno expone el tokenninguno

findByMetaAccount + readMetaAccessToken​

TestEscenarioResultado esperadoMocks
loads the token and decrypts it to the original valueBuscar por canal y cuenta MetaDevuelve la conexión del tenant y readMetaAccessToken descifra al valor originalninguno
does not match another channel typeBuscar la cuenta de Instagram como FacebookDevuelve nullninguno
fails loudly when the token was not selectedreadMetaAccessToken sobre una lectura sin el tokenLanza error con Meta access token not loadedninguno

connection-web-config.dto.spec.ts​

Validación con class-transformer y class-validator.

ConnectionWebConfigDto — requiresAuth​

TestEscenarioResultado esperadoMocks
accepts requiresAuth %s (it.each: true, false)Payload con un dominio permitido y requiresAuth booleanoSin errores de validaciónninguno
accepts the payload without requiresAuthPayload sin requiresAuth (se usa el default del modelo, true)Sin errores de validaciónninguno
rejects a non-boolean requiresAuthrequiresAuth: 'yes'Error en la propiedad requiresAuthninguno
still enforces at least one allowed domainallowedDomains vacíoError en la propiedad allowedDomainsninguno

phone.helper.spec.ts​

jidToPhoneDigits​

TestEscenarioResultado esperadoMocks
extracts the number from a phone JID5511999999999@s.whatsapp.net5511999999999ninguno
strips the device suffix5511999999999:12@s.whatsapp.net5511999999999ninguno
rejects a linked-id JIDJID @lid (identificador opaco, no un teléfono)undefinedninguno
rejects a group JIDJID de grupo @g.usundefinedninguno
rejects the status broadcast JIDstatus@broadcastundefinedninguno
handles absent inputundefined, null y cadena vacíaundefined en los tres casosninguno