Skip to main content

Casos de prueba — Contact

Catálogo de los tests del módulo contact. Specs fuente (relativas a src/app/modules/contact/):

  • controllers/contact.controller.permissions.spec.ts
  • controllers/contact.controller.spec.ts
  • services/contact.service.spec.ts
  • repositories/contact.repository.spec.ts

Resumen: 4 specs, 11 suites (describe) y 52 tests (it).

controllers/contact.controller.permissions.spec.ts​

Integración del guard real PermissionsGuard + Reflector a través del pipeline HTTP (supertest). AuthGuard se reemplaza por un FakeAuthGuard que inyecta tenantId/roleId.

ContactController — assignLabels (custom verb -> CONTACT_UPDATE) permission guard integration​

TestEscenarioResultado esperadoMocks
returns 403 Forbidden when CONTACT_UPDATE is missingEl rol solo tiene CONTACT_READ; se hace PATCH /v1/contacts/:id/assign-labelsResponde 403 y assignLabels no se invocaContactService, TranslateService, PermissionResolverService (resuelve el set de acrónimos), FakeAuthGuard
returns 200 OK when CONTACT_UPDATE is grantedEl rol tiene CONTACT_UPDATE; mismo PATCHResponde 200 y assignLabels es invocadoLos mismos

controllers/contact.controller.spec.ts​

Unitario del controlador con guards (AuthGuard, PermissionsGuard) anulados.

ContactController › create​

TestEscenarioResultado esperadoMocks
should pass user.tenantId and return created contactcreate con DTO válido y usuario autenticadoLlama service.create(dto, tenantId, lang) y devuelve { message: 'contact.created', data }ContactService, TranslateService
should propagate ConflictException when contact already existsEl servicio rechaza con ConflictExceptionEl controlador propaga ConflictExceptionContactService.create rechaza

ContactController › findAll​

TestEscenarioResultado esperadoMocks
should return all contacts without paginationSin query de paginaciónLlama findAll(tenantId, {}) y responde data.results con los contactosContactService.findAll
should return empty array when no contacts existEl servicio devuelve []data: { results: [] }ContactService.findAll
should return paginated contacts when page and limit are providedQuery con page: 1, limit: 10Usa findAllPaginated(tenantId, 1, 10, {}) y devuelve meta: { total, page, limit }ContactService.findAllPaginated
should pass filters to findAll when no paginationQuery con username e isActive sin paginaciónfindAll recibe el filtro tal cualContactService.findAll
should pass filters to findAllPaginated when pagination is providedQuery con page, limit e isBlockedfindAllPaginated recibe solo { isBlocked: false } como filtro (page/limit se separan)ContactService.findAllPaginated

ContactController › findOne​

TestEscenarioResultado esperadoMocks
should return contact scoped to user tenantContacto existenteLlama findOne(id, tenantId, lang) y responde { message: 'contact.findOne', data: { results: [contact] } }ContactService.findOne
should propagate NotFoundException when contact not found in this tenantEl servicio rechaza con NotFoundExceptionSe propaga NotFoundExceptionContactService.findOne rechaza

ContactController › update​

TestEscenarioResultado esperadoMocks
should update contact scoped to user tenantDTO con username nuevoLlama update(id, tenantId, dto, lang) y responde contact.updated con el contacto actualizadoContactService.update
should propagate NotFoundException when contact not found in this tenantContacto inexistente en el tenantSe propaga NotFoundExceptionContactService.update rechaza

ContactController › remove​

TestEscenarioResultado esperadoMocks
should remove contact scoped to user tenantContacto existenteLlama remove(id, tenantId, lang) y responde contact.deletedContactService.remove
should propagate NotFoundException when contact not found in this tenantContacto inexistenteSe propaga NotFoundExceptionContactService.remove rechaza

ContactController › assignLabels​

TestEscenarioResultado esperadoMocks
should assign labels to contact scoped to user tenantBody con labelIds: [labelId]Llama assignLabels(id, tenantId, [labelId], lang) y responde contact.updatedContactService.assignLabels
should use empty array when labelIds is undefinedBody vacío {}El servicio recibe [] como labelsContactService.assignLabels
should propagate NotFoundException when contact not foundContacto inexistenteSe propaga NotFoundExceptionContactService.assignLabels rechaza

services/contact.service.spec.ts​

Unitario del servicio con repositorio y LabelService simulados.

ContactService › create​

TestEscenarioResultado esperadoMocks
should throw ConflictException when contact already exists for that tenant+externalIdfindByExternalIdAndTenant devuelve un contactoLanza ConflictException y no llama repository.createContactRepository
should create and return contact when validfindByExternalIdAndTenant devuelve nullcreate recibe externalId, username y tenantId; devuelve el contactoContactRepository

ContactService › findAll​

TestEscenarioResultado esperadoMocks
should return contacts scoped to the tenantSin filtrorepository.findAll(tenantId, undefined) y devuelve la listaContactRepository.findAll
should forward filter to repositoryCon filtro username/isActiveEl filtro se reenvía al repositorioContactRepository.findAll
should return empty array when no contacts exist for the tenantEl repositorio devuelve []Devuelve []ContactRepository.findAll

ContactService › findAllPaginated​

TestEscenarioResultado esperadoMocks
should return paginated contacts with totalPágina 1, límite 10, sin filtroDelega con (tenantId, 1, 10, undefined) y devuelve { results, total }ContactRepository.findAllPaginated
should forward filter when paginatingPágina 2, límite 5, filtro isBlocked: trueEl filtro se reenvía al repositorioContactRepository.findAllPaginated

ContactService › findOne​

TestEscenarioResultado esperadoMocks
should return contact when found within the tenantfindByIdAndTenant devuelve el contactoDevuelve el contactoContactRepository.findByIdAndTenant
should throw NotFoundException when contact does not exist in this tenantfindByIdAndTenant devuelve nullLanza NotFoundExceptionContactRepository.findByIdAndTenant

ContactService › update​

TestEscenarioResultado esperadoMocks
should return updated contact when found within tenantrepository.update devuelve el contacto actualizadoDevuelve el contacto y llama update(id, tenantId, dto)ContactRepository.update
should throw NotFoundException when contact does not belong to this tenantrepository.update devuelve nullLanza NotFoundExceptionContactRepository.update

ContactService › remove​

TestEscenarioResultado esperadoMocks
should return removed contact when found within tenantrepository.remove devuelve el contactoDevuelve el contacto y llama remove(id, tenantId)ContactRepository.remove
should throw NotFoundException when contact does not belong to this tenantrepository.remove devuelve nullLanza NotFoundExceptionContactRepository.remove

ContactService › findOrCreate​

TestEscenarioResultado esperadoMocks
should return existing contact when foundEl repositorio responde created: falseReenvía el payload y devuelve created === falseContactRepository.findOrCreate
should return new contact when not foundEl repositorio responde created: trueDevuelve created === trueContactRepository.findOrCreate

ContactService › findByMongoId​

TestEscenarioResultado esperadoMocks
should return contact when foundEl repositorio devuelve el contactoDevuelve el contactoContactRepository.findByMongoId
should return null when not foundEl repositorio devuelve nullDevuelve null (no lanza excepción)ContactRepository.findByMongoId

ContactService › assignLabels​

TestEscenarioResultado esperadoMocks
should assign labels and return updated contactContacto existente y labels válidos del tenantValida labels, llama repository.assignLabels con ObjectId y devuelve el contacto actualizadoContactRepository, LabelService.validateLabelsBelongToTenant
should throw NotFoundException when contact does not existfindByIdAndTenant devuelve nullLanza NotFoundException y no asigna labelsContactRepository
should assign empty labels array when labelIds is emptylabelIds vacíorepository.assignLabels recibe [] y el contacto queda con labels vacíoContactRepository, LabelService

ContactService › findOrCreateFromExternal​

TestEscenarioResultado esperadoMocks
should return created=true and the new contact when externalId does not existupsertFromExternal responde created: trueDevuelve created: true y el contactoContactRepository.upsertFromExternal
should return created=false and existing contact when externalId already existsupsertFromExternal responde created: falseDevuelve created: false y el contacto existenteContactRepository.upsertFromExternal
should forward tenantId and all mapped fields to repositoryDatos externos con externalId y metadataEl repositorio recibe el tenantId, externalId '31912' y metadata intactosContactRepository.upsertFromExternal

repositories/contact.repository.spec.ts​

Tests contra MongoDB real en memoria (mongodb-memory-server); no hay mocks de persistencia.

ContactRepository.findOrCreate — identity persistence (mongodb-memory-server)​

TestEscenarioResultado esperadoMocks
finds a contact by phone in any stored format, scoped to the tenantContactos con teléfono 593991234567, +573001234567, externalId WhatsApp y uno de otro tenant; se busca con distintos formatosCada búsqueda devuelve solo el contacto del tenant que corresponde; un teléfono inexistente da total 0Ninguno (MongoDB en memoria)
creates the contact with the identity fields from the host sessionfindOrCreate con email en mayúsculas, teléfono y nombrecreated: true, email en minúsculas (el schema lo normaliza), teléfono y nombres guardadosNinguno
updates identity fields on a returning contactContacto existente; se vuelve a llamar con email y nombre nuevoscreated: false y campos actualizadosNinguno
keeps stored identity when the session sends nothing (no erasure)Contacto con email y teléfono; segunda llamada sin identidadcreated: false y se conservan email y teléfonoNinguno
preserves a leading zero in the phoneTeléfono 0999999999Se guarda como string con el cero inicialNinguno
preserves the international prefixTeléfono +593984701187Se conserva el prefijo +Ninguno
still finds without duplicating when no identity is sent (legacy behavior)Dos llamadas sin identidadPrimera created: true, segunda false, mismo _id y solo 1 documentoNinguno

ContactRepository.setPresence / touchLastSeen (mongodb-memory-server)​

TestEscenarioResultado esperadoMocks
updates isOnline/lastSeen/lastDisconnectReason when tenant matches, without populating labelssetPresence con el tenant correctoActualiza los tres campos y no puebla labelsNinguno
does nothing (returns null) when the contact belongs to a different tenantsetPresence con otro tenantDevuelve null y el contacto no cambiaNinguno
bulk-updates lastSeen for every contact id given, ignoring tenanttouchLastSeen con ids de dos tenantsAmbos contactos reciben el mismo lastSeenNinguno
is a no-op on an empty array (no write attempted)touchLastSeen([])Resuelve sin lanzar errorNinguno