import { describe, expect, it, vi, beforeEach } from 'vitest' const prismaMock = vi.hoisted(() => ({ leadCaptura: { findMany: vi.fn(), }, })) vi.mock('../services/prisma.js', () => ({ prisma: prismaMock })) import { calcularScore, obtenerScores } from './lead-scoring.service.js' describe('calcularScore', () => { const ahora = new Date('2026-09-08T12:00:00Z') it('asigna score base según etapa (NUEVO = 20)', () => { const lead = { etapa: 'NUEVO', telefono: null, email: null, origen: null, createdAt: new Date('2026-09-07T12:00:00Z'), updatedAt: new Date('2026-09-07T12:00:00Z'), } // 20 (etapa) + 5 (recencia <7d) = 25 expect(calcularScore(lead, ahora)).toBe(25) }) it('asigna score CALIFICADO (90)', () => { const lead = { etapa: 'CALIFICADO', telefono: '4771234567', email: 'test@email.com', origen: 'Facebook', createdAt: new Date('2026-09-08T00:00:00Z'), updatedAt: new Date('2026-09-08T00:00:00Z'), } // 90 + 10 (<24h) + 5 tel + 5 email + 5 origen = 115 → clamp 100 expect(calcularScore(lead, ahora)).toBe(100) }) it('aplica penalización >30 días sin actividad', () => { const lead = { etapa: 'CONTACTADO', telefono: null, email: null, origen: null, createdAt: new Date('2026-07-01T00:00:00Z'), updatedAt: new Date('2026-07-01T00:00:00Z'), } // 40 (CONTACTADO) + (-20) (>30d) = 20 expect(calcularScore(lead, ahora)).toBe(20) }) it('score mínimo es 0', () => { const lead = { etapa: 'DESCARTADO', telefono: null, email: null, origen: null, createdAt: new Date('2026-01-01T00:00:00Z'), updatedAt: new Date('2026-01-01T00:00:00Z'), } // 10 (desconocida) + (-20) = -10 → clamp 0 expect(calcularScore(lead, ahora)).toBe(0) }) it('recencia <24h suma +10', () => { const lead = { etapa: 'NUEVO', telefono: '1234567890', email: 'a@b.com', origen: 'Web', createdAt: new Date('2026-09-08T10:00:00Z'), updatedAt: new Date('2026-09-08T10:00:00Z'), } // 20 + 10 + 5 + 5 + 5 = 45 expect(calcularScore(lead, ahora)).toBe(45) }) it('INTERESADO = 60 + recencia <7d = +5 = 65', () => { const lead = { etapa: 'INTERESADO', telefono: null, email: null, origen: null, createdAt: new Date('2026-09-05T12:00:00Z'), updatedAt: new Date('2026-09-05T12:00:00Z'), } expect(calcularScore(lead, ahora)).toBe(65) }) }) describe('obtenerScores', () => { beforeEach(() => { vi.clearAllMocks() }) it('devuelve scores ordenados de mayor a menor', async () => { prismaMock.leadCaptura.findMany.mockResolvedValue([ { leadId: 'l1', nombreLead: 'A', usuarioId: 'u1', etapa: 'NUEVO', telefono: null, email: null, origen: null, createdAt: new Date('2026-09-07'), updatedAt: new Date('2026-09-07'), }, { leadId: 'l2', nombreLead: 'B', usuarioId: 'u1', etapa: 'CALIFICADO', telefono: '1234567890', email: 'b@b.com', origen: 'Web', createdAt: new Date('2026-09-08'), updatedAt: new Date('2026-09-08'), }, ]) const scores = await obtenerScores() expect(scores).toHaveLength(2) expect(scores[0]!.leadId).toBe('l2') expect(scores[0]!.score).toBeGreaterThan(scores[1]!.score) }) it('filtra por usuarioId cuando se proporciona', async () => { prismaMock.leadCaptura.findMany.mockResolvedValue([]) await obtenerScores('u1') expect(prismaMock.leadCaptura.findMany).toHaveBeenCalledWith({ where: { board: { in: ['LEADS', 'OPORTUNIDADES'] }, usuarioId: 'u1', }, }) }) })