Skip to main content

Conexiones (Meta)

Casos de prueba del feature src/app/features/connections. Hay 2 specs propios (25 tests) y 1 spec de servicio relacionado que se documenta en core-services.md. Ninguno usa xit, fdescribe ni fit, y no hay specs vacíos.

src/app/features/connections/components/connections-table/connections-table.component.spec.ts​

  • SUT: ConnectionsTableComponent.
  • Mocking: sin TestBed; se instancia con new ConnectionsTableComponent(...). ConnectionService es un jasmine.createSpyObj (findConnectionsPaginated devuelve of({ results: [], total: 0 }), removeConnection, logoutWhatsappSession). ChatSocketService es un objeto con whatsappSessionStatus$ respaldado por un Subject. NgbModal es un spy con open, ActivatedRoute un stub con queryParamMap vacío, Router y ToastrNotificationService son spies. afterEach llama ngOnDestroy().

ConnectionsTableComponent — whatsapp wiring​

it() títuloEscenarioResultado esperadoMocks/spies
openChannelSelector(): routes "whatsapp-qr" to openWhatsappModal()Dado que el modal selector se abre, cuando emite closed con 'whatsapp-qr', entonces se delega al flujo de WhatsApp.NgbModal.open recibe ConnectionChannelModalComponent y se llama openWhatsappModal.ngbModal.open devuelve { closed }; spyOn(component, 'openWhatsappModal')
openWhatsappModal(): opens the modal with the given connection and reloads on closeDada una conexión, cuando se abre el modal y este se cierra (closed emite undefined), entonces recarga la lista.Se abre ConnectionWhatsappModalComponent, componentInstance.connection es la misma conexión y se llama loadConnections.ngbModal.open devuelve { componentInstance, closed }; spyOn(component, 'loadConnections')
whatsappSessionStatus$ patches the matching card in place without a refetchDado ngOnInit y dos conexiones, cuando llega un evento de estado para conn-1, entonces solo esa tarjeta se actualiza (la otra, conn-2, queda intacta).conn-1 tiene sessionState connected y phoneJid; conn-2.whatsappConfig sigue undefined; findConnectionsPaginated se llamó una sola vez (sin refetch).Subject whatsappSessionStatusSubject, connectionService spy
whatsappSessionState() falls back to "init" when whatsappConfig is absentDada una conexión sin whatsappConfig, cuando se consulta el estado de sesión, entonces usa el valor por defecto.Devuelve 'init'.Ninguno (función pura sobre el input)
onWhatsappLogout(): calls the API and reloads only after the confirm dialog is acceptedDado el diálogo de confirmación, cuando se cierra con false no pasa nada; cuando se cierra con true se cierra la sesión y se recarga.Con false: logoutWhatsappSession no se llama. Con true: se llama con 'conn-1' y luego loadConnections.ngbModal.open devuelve { componentInstance, closed }; logoutWhatsappSession devuelve of(undefined); spyOn(component, 'loadConnections')

Tests en este archivo: 5.

src/app/features/connections/components/connection-whatsapp-modal/connection-whatsapp-modal.component.spec.ts​

  • SUT: ConnectionWhatsappModalComponent (emparejamiento por QR y formulario de configuración).
  • Mocking: TestBed con declarations: [ConnectionWhatsappModalComponent, SwitchComponent], imports TranslateModule.forRoot(), FormsModule, ReactiveFormsModule, NgSelectModule y NO_ERRORS_SCHEMA. Providers: NgbActiveModal (spy con close, dismiss), ConnectionService (spy con createConnection, startWhatsappSession, logoutWhatsappSession, getWhatsappSessionStatus, updateConnection, removeConnection), DepartmentService (getAll devuelve of([])) y ChatSocketService (whatsappQr$ y whatsappSessionStatus$ desde Subject). Por defecto removeConnection devuelve of(makeConnection()) y getWhatsappSessionStatus devuelve estado init. Helper makeConnection(); se usa fakeAsync/tick en los casos con temporizador.

ConnectionWhatsappModalComponent (nivel raíz)​

it() títuloEscenarioResultado esperadoMocks/spies
salta al formulario si la conexión ya estaba emparejadaDada una conexión existente cuya sesión ya responde connected con phoneJid, cuando se inicializa el componente, entonces omite el QR.step es 'form' y phoneNumber es '5511999999999'.startWhatsappSession devuelve connected
closeModal() dismisses the active modalDada una creación y arranque de sesión exitosos, cuando se llama closeModal(), entonces se descarta el modal.activeModal.dismiss fue llamado.createConnection, startWhatsappSession (init), activeModal

new connection (no @Input connection)​

it() títuloEscenarioResultado esperadoMocks/spies
creates a whatsapp-qr connection then starts the sessionDado que no hay conexión de entrada, cuando se inicializa, entonces crea la conexión y arranca la sesión que devuelve un QR.createConnection con { channelType: 'whatsapp-qr' }; startWhatsappSession('conn-1'); sessionState 'qr', qr con el data URL, isLoading false.createConnection y startWhatsappSession devuelven of(...)
sets an error key when creation fails, without ever calling startWhatsappSessionDado que la creación falla (error boom), cuando se inicializa, entonces se informa el error y no se arranca sesión.errorMessageKey es 'connections.whatsapp.createError' y startWhatsappSession no se llama.createConnection devuelve throwError

reconnect (existing @Input connection)​

it() títuloEscenarioResultado esperadoMocks/spies
starts the session directly for the existing connectionId, skipping createDada una conexión existente disconnected, cuando se inicializa, entonces reutiliza su id sin crear otra.createConnection no se llama; startWhatsappSession('conn-1'); sessionState 'connecting'.startWhatsappSession devuelve connecting

live socket updates​

beforeEach crea la conexión, arranca la sesión en init y ejecuta detectChanges().

it() títuloEscenarioResultado esperadoMocks/spies
ignores whatsappQr$ events for a different connectionIdCuando llega un QR de otro connectionId, entonces se ignora.qr sigue null.whatsappQrSubject
updates qr and sessionState on a matching whatsappQr$ eventCuando llega un QR para conn-1, entonces se refleja en el componente.qr con el data URL y sessionState 'qr'.whatsappQrSubject
updates sessionState/phoneJid on a matching whatsapp_session_status event and clears a stale QRDado un QR previo, cuando llega un estado connecting para conn-1, entonces se actualiza el estado y se limpia el QR obsoleto.sessionState 'connecting' y qr null.whatsappQrSubject, whatsappSessionStatusSubject
advances to the form shortly after reaching "connected"Cuando llega el estado connected, entonces el paso cambia al formulario tras 1200 ms (fakeAsync).Antes del tick step es 'qr'; tras tick(1200) es 'form' y activeModal.close no se llamó.whatsappSessionStatusSubject, fakeAsync/tick
ignores a status event for a different connectionIdCuando llega un estado connected de otro connectionId, entonces se ignora.sessionState no es 'connected'.whatsappSessionStatusSubject

paso 2: formulario​

El helper reachForm() asigna una conexión (Ventas, saludo Hola, tolerancia 30), arranca sesión en qr, hace detectChanges() y llama goToForm().

it() títuloEscenarioResultado esperadoMocks/spies
Saltar avanza al formulario sin esperar el escaneoDado el QR sin escanear, cuando se usa Saltar (goToForm), entonces avanza al formulario.step es 'form' y form está definido.startWhatsappSession
precarga el formulario con los datos de la conexiónCuando se llega al formulario, entonces se precargan los valores de la conexión.name 'Ventas', greetingMessage 'Hola', reopenToleranceMinutes 30.Ninguno adicional
guarda los seis campos y cierra el modalDado el formulario con valores nuevos, cuando se llama onSave(), entonces actualiza la conexión con los seis campos y cierra.updateConnection('conn-1', { name, greetingMessage, farewellMessage, departmentIds, reopenToleranceMinutes, returnToLastAgent }) y activeModal.close('saved').updateConnection devuelve of(...)
no guarda sin nombreDado name vacío, cuando se llama onSave(), entonces no se envía nada (validación).updateConnection no se llama.updateConnection
startOnForm entra directo al formulario sin arrancar la sesiónDado startOnForm = true, cuando se inicializa, entonces entra al formulario.step es 'form' y startWhatsappSession no se llama.startWhatsappSession
relee el estado real de la sesión al entrar al formularioDado startOnForm y un estado remoto connected con phoneJid, cuando se inicializa, entonces consulta el estado real.getWhatsappSessionStatus('conn-1') y phoneNumber '5511999999999'.getWhatsappSessionStatus devuelve connected
mantiene lo que traía la tarjeta si el estado no se puede releerDado startOnForm y que la relectura falla (offline), cuando se inicializa, entonces no se rompe el flujo.step sigue 'form'.getWhatsappSessionStatus devuelve throwError

orphaned connection cleanup on destroy​

it() títuloEscenarioResultado esperadoMocks/spies
removes the connection it created here when destroyed before reaching "connected"Dado que el modal creó new-conn y no llegó a connected, cuando se destruye el fixture, entonces limpia la conexión huérfana.removeConnection('new-conn').createConnection, startWhatsappSession (qr), removeConnection
does not remove an existing connection provided via @Input on destroyDada una conexión recibida por @Input, cuando se destruye, entonces no se elimina.removeConnection no se llama.startWhatsappSession (disconnected)
does not remove the created connection once it reached "connected"Dada una conexión creada que llegó a connected (con tick(1200)), cuando se destruye, entonces se conserva.removeConnection no se llama.whatsappSessionStatusSubject, fakeAsync/tick

Tests en este archivo: 20.

Referencia cruzada: src/app/core/services/api/connection.service.spec.ts​

Spec del servicio ConnectionService (fuera del feature; detalle completo en core-services.md). Usa HttpClientTestingModule y HttpTestingController, con ToastrNotificationService como spy. Casos, todos sobre describe('ConnectionService — whatsapp session endpoints'):

  • startWhatsappSession should POST /connections/whatsapp/:id/start and unwrap data
  • logoutWhatsappSession should DELETE /connections/whatsapp/:id/logout
  • getWhatsappSessionStatus should GET /connections/whatsapp/:id/status and unwrap data

Tests en este archivo: 3 (no se cuentan en el total de la página).

Qué NO está cubierto​

Verificado con rg sobre src: ningún spec referencia los siguientes elementos de la rama meta_connections. Solo existen en sus archivos de implementación, el módulo o las plantillas.

ElementoDónde existeEstado de pruebas
ConnectionInstagramModalComponentconnection-instagram-modal.component.ts, connections.module.ts, connections-table.component.tsSin spec
connection-web-modal (ConnectionWebModalComponent)connection-web-modal.component.ts, módulo y tablaSin spec
connections-filterconnections-filter.component.ts, connections-table.component.htmlSin spec
authorizeInstagramconnection.service.ts, connections-table.component.tsSin test en connection.service.spec.ts ni en el spec de la tabla
handleMetaOAuthReturnconnections-table.component.tsSin test
instagramExpiryconnections-table.component.ts y su .htmlSin test
connection-channel-modalconnection-channel-modal.component.tsSin spec propio. Solo se menciona como clase importada en el spec de la tabla, que verifica únicamente que NgbModal.open la recibe y el ruteo de 'whatsapp-qr'.

Tampoco hay specs para connections-page ni para otros métodos de ConnectionsTableComponent (por ejemplo, borrado o filtrado); el spec de la tabla se limita al cableado de WhatsApp. Los otros canales (Instagram, web) y los endpoints de ConnectionService distintos de los tres de sesión WhatsApp no tienen cobertura.

Total de la página​

25 tests documentados en 2 specs del feature: connections-table.component.spec.ts 5 y connection-whatsapp-modal.component.spec.ts 20. A ellos se suman 3 de connection.service.spec.ts solo como referencia cruzada.