Files
FRASA-CAS/api-gateway/src/services/contactos-perfil.service.test.ts
Consult AS Technology db18685872 feat(ux): 17 mejoras de experiencia de usuario
Backend (10 endpoints nuevos):
- Recordatorios personales (CRUD + tabla RecordatorioVendedor)
- Lead scoring 0-100 (etapa+recencia+datos)
- Dashboard mora (pagos vencidos, monto, días atraso)
- Timeline de pagos (pagado/vence/futuro)
- Perfil completo contacto (pagos+cotizaciones+docs+score)
- Exportar contactos a CSV

Frontend Mi día:
- Resumen matutino (saludo+KPIs)
- Historial visual lead (timeline)
- Score badge 0-100 (verde/amarillo/rojo)
- Vista kanban (drag & drop)

Frontend Cobranza:
- Dashboard mora (tabla+WhatsApp)
- Timeline pagos visual (nodos coloreados)

Frontend Alta Clientes:
- Checklist documentos visual
- Foto cliente (cámara)

Frontend Landing:
- Perfil contacto completo
- Exportar contactos CSV

Frontend Mi día (extras):
- Comparativa mensual
- KPIs dashboard (leads hoy, ventas, conversión)

806 tests, 5 apps construidas.
2026-09-08 07:42:54 +00:00

132 lines
4.0 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest'
const prismaMock = vi.hoisted(() => ({
cliente: { findFirst: vi.fn() },
leadCaptura: { findUnique: vi.fn() },
planPago: { findMany: vi.fn() },
cotizacion: { findMany: vi.fn() },
documento: { findMany: vi.fn() },
actividadLocal: { findFirst: vi.fn() },
}))
vi.mock('../services/prisma.js', () => ({ prisma: prismaMock }))
// Mock lead-scoring to avoid circular dependency
vi.mock('../services/lead-scoring.service.js', () => ({
calcularScore: vi.fn(() => 75),
}))
import { perfilCompleto } from './contactos-detalle.service.js'
beforeEach(() => {
vi.clearAllMocks()
prismaMock.cliente.findFirst.mockResolvedValue(null)
prismaMock.leadCaptura.findUnique.mockResolvedValue(null)
prismaMock.planPago.findMany.mockResolvedValue([])
prismaMock.cotizacion.findMany.mockResolvedValue([])
prismaMock.documento.findMany.mockResolvedValue([])
prismaMock.actividadLocal.findFirst.mockResolvedValue(null)
})
describe('perfilCompleto', () => {
it('devuelve null si el contacto no existe', async () => {
const result = await perfilCompleto('no-existe')
expect(result).toBeNull()
})
it('arma perfil completo desde Cliente', async () => {
prismaMock.cliente.findFirst.mockResolvedValue({
id: 'c1',
nombreCompleto: 'Juan Pérez',
curp: 'CURP123',
rfc: 'RFC123',
email: 'juan@test.com',
celular: '4771234567',
proyecto: 'SENDA',
unidadCodigo: 'SENDA-101',
mondayContactoId: null,
createdAt: new Date('2026-09-01'),
})
prismaMock.planPago.findMany.mockResolvedValue([
{
id: 'plan1',
clienteNombre: 'Juan Pérez',
unidadCodigo: 'SENDA-101',
proyecto: 'SENDA',
pagos: [
{ numPago: 1, fechaVencimiento: new Date('2026-10-01'), monto: 5000, montoPagado: 0 },
],
},
])
prismaMock.documento.findMany.mockResolvedValue([
{ id: 'd1', tipo: 'INE', nombreArchivo: 'ine.pdf', createdAt: new Date('2026-09-02') },
])
const result = await perfilCompleto('c1')
expect(result).not.toBeNull()
expect(result?.contacto['nombre']).toBe('Juan Pérez')
expect(result?.contacto['CURP']).toBe('CURP123')
expect(result?.historialPagos).toHaveLength(1)
expect(result?.historialPagos[0]?.estado).toBe('pendiente')
expect(result?.documentos).toHaveLength(1)
expect(result?.documentos[0]?.tipo).toBe('INE')
})
it('arma perfil desde LeadCaptura cuando no hay Cliente', async () => {
prismaMock.leadCaptura.findUnique.mockResolvedValue({
leadId: 'loc_1',
nombreLead: 'Ana López',
telefono: '6649998877',
email: 'ana@test.com',
origen: 'Facebook',
etapa: 'INTERESADO',
createdAt: new Date('2026-09-05'),
updatedAt: new Date('2026-09-07'),
})
prismaMock.actividadLocal.findFirst.mockResolvedValue({
titulo: 'Llamar a Ana',
tipo: 'SEGUIMIENTO',
createdAt: new Date('2026-09-07'),
})
const result = await perfilCompleto('loc_1')
expect(result).not.toBeNull()
expect(result?.contacto['nombre']).toBe('Ana López')
expect(result?.contacto['Etapa']).toBe('INTERESADO')
expect(result?.leadScore).toBe(75)
expect(result?.ultimaActividad?.titulo).toBe('Llamar a Ana')
})
it('cotizaciones se incluyen cuando hay teléfono', async () => {
prismaMock.cliente.findFirst.mockResolvedValue({
id: 'c1',
nombreCompleto: 'Test',
curp: '',
rfc: '',
email: null,
celular: '4771234567',
proyecto: 'A',
unidadCodigo: null,
mondayContactoId: null,
createdAt: new Date(),
})
prismaMock.cotizacion.findMany.mockResolvedValue([
{
id: 'cot1',
unidadCodigo: 'U-101',
tipoPropuesta: 'BANCARIO',
precioFinal: 3000000,
createdAt: new Date('2026-09-01'),
},
])
const result = await perfilCompleto('c1')
expect(result?.cotizaciones).toHaveLength(1)
expect(result?.cotizaciones[0]?.tipoPropuesta).toBe('BANCARIO')
})
})