feat(mejoras): 14 mejoras al CRM Frasa
Fase 1 - UI: dark mode, skeletons, toasts Fase 2 - Filtros: avanzados Mi día, búsqueda global Ctrl+K Fase 3 - Datos: export Excel, notas apartados, auditoría Fase 4 - Dashboard: gráficas vendedor + métricas uso Fase 5 - Responsive: tablets optimizadas Fase 6 - PWA: IndexedDB offline, push notifications Backend: 3 tablas nuevas, 6 services, 6 endpoints nuevos 721 API tests + fronts verdes.
This commit is contained in:
116
apps/mi-dia/src/services/exportar.test.ts
Normal file
116
apps/mi-dia/src/services/exportar.test.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
// @vitest-environment jsdom
|
||||
import { describe, expect, it, vi, beforeEach } from 'vitest'
|
||||
import type { LeadMiDia, OportunidadMiDia, ApartadoMiDia } from '../lib/mi-dia'
|
||||
|
||||
// Mock xlsx before importing the module under test
|
||||
vi.mock('xlsx', () => {
|
||||
const ws = {
|
||||
'!cols': [],
|
||||
}
|
||||
const wb = {
|
||||
SheetNames: [] as string[],
|
||||
Sheets: {} as Record<string, unknown>,
|
||||
}
|
||||
return {
|
||||
utils: {
|
||||
book_new: () => ({ ...wb, SheetNames: [], Sheets: {} }),
|
||||
json_to_sheet: (_data: unknown[]) => ({ ...ws }),
|
||||
book_append_sheet: (workbook: typeof wb, worksheet: typeof ws, name: string) => {
|
||||
workbook.SheetNames.push(name)
|
||||
workbook.Sheets[name] = worksheet
|
||||
},
|
||||
},
|
||||
write: (_workbook: unknown, _opts: unknown) => new ArrayBuffer(8),
|
||||
}
|
||||
})
|
||||
|
||||
import { exportarLeads, exportarOportunidades, exportarApartados } from './exportar'
|
||||
|
||||
const leadFake: LeadMiDia = {
|
||||
id: '1',
|
||||
nombre: 'Juan Pérez',
|
||||
telefono: '6641234567',
|
||||
email: 'juan@test.com',
|
||||
estado: 'CONTACTADO',
|
||||
origen: 'PASE',
|
||||
updatedAt: '2026-09-01T10:00:00Z',
|
||||
fuente: 'lead',
|
||||
ultimoCambio: { fechaISO: '2026-09-01T10:00:00Z', usuario: 'Admin', detalle: 'Lead creado' },
|
||||
}
|
||||
|
||||
const opFake: OportunidadMiDia = {
|
||||
id: '2',
|
||||
nombre: 'María López',
|
||||
telefono: '6649876543',
|
||||
email: 'maria@test.com',
|
||||
etapa: 'Agendo Cita',
|
||||
desarrollo: 'DIAGONAL',
|
||||
modeloInteres: 'Modelo A',
|
||||
unidadCodigo: 'D-101',
|
||||
updatedAt: '2026-09-02T12:00:00Z',
|
||||
ultimoCambio: { fechaISO: '2026-09-02T12:00:00Z', usuario: 'Admin', detalle: 'Etapa cambiada' },
|
||||
}
|
||||
|
||||
const apartadoFake: ApartadoMiDia = {
|
||||
id: '3',
|
||||
nombre: 'Carlos Ruiz',
|
||||
unidadCodigo: 'E-202',
|
||||
estado: 'En proceso',
|
||||
fechaLimite: '2026-09-15',
|
||||
ultimoCambio: null,
|
||||
}
|
||||
|
||||
let clickSpy: ReturnType<typeof vi.fn>
|
||||
|
||||
beforeEach(() => {
|
||||
clickSpy = vi.fn()
|
||||
// Mock document.createElement('a').click
|
||||
const originalCreateElement = document.createElement.bind(document)
|
||||
vi.spyOn(document, 'createElement').mockImplementation((tag: string) => {
|
||||
const el = originalCreateElement(tag)
|
||||
if (tag === 'a') {
|
||||
el.click = clickSpy
|
||||
}
|
||||
return el
|
||||
})
|
||||
// Stub URL.createObjectURL / revokeObjectURL (jsdom may not have them)
|
||||
if (typeof URL.createObjectURL !== 'function') {
|
||||
Object.defineProperty(URL, 'createObjectURL', { value: () => 'blob:mock', configurable: true })
|
||||
} else {
|
||||
vi.spyOn(URL, 'createObjectURL').mockReturnValue('blob:mock')
|
||||
}
|
||||
if (typeof URL.revokeObjectURL !== 'function') {
|
||||
Object.defineProperty(URL, 'revokeObjectURL', { value: () => {}, configurable: true })
|
||||
} else {
|
||||
vi.spyOn(URL, 'revokeObjectURL').mockImplementation(() => {})
|
||||
}
|
||||
})
|
||||
|
||||
describe('exportarLeads', () => {
|
||||
it('genera buffer xlsx válido y dispara descarga', () => {
|
||||
const leads = [leadFake]
|
||||
exportarLeads(leads, 'test_leads.xlsx')
|
||||
|
||||
expect(clickSpy).toHaveBeenCalledOnce()
|
||||
expect(document.createElement).toHaveBeenCalledWith('a')
|
||||
})
|
||||
|
||||
it('usa nombre de archivo por defecto cuando no se proporciona', () => {
|
||||
exportarLeads([leadFake])
|
||||
expect(clickSpy).toHaveBeenCalledOnce()
|
||||
})
|
||||
})
|
||||
|
||||
describe('exportarOportunidades', () => {
|
||||
it('genera buffer xlsx válido y dispara descarga', () => {
|
||||
exportarOportunidades([opFake], 'test_ops.xlsx')
|
||||
expect(clickSpy).toHaveBeenCalledOnce()
|
||||
})
|
||||
})
|
||||
|
||||
describe('exportarApartados', () => {
|
||||
it('genera buffer xlsx válido y dispara descarga', () => {
|
||||
exportarApartados([apartadoFake], 'test_aparts.xlsx')
|
||||
expect(clickSpy).toHaveBeenCalledOnce()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user