import { describe, expect, it, vi } from 'vitest' vi.mock('../config/index.js', () => ({ config: { monday: { boards: { leads: '111', oportunidades: '222', contactos: '333', unidades: '444', apartado: '555', }, }, }, })) import { GRUPOS_POR_ESTADO, grupoDestino, moverAGrupoSegunEstado } from './grupos-estado.service.js' interface ItemFake { id: string name: string groupId: string column_values: { id: string; text: string | null; value: string | null }[] } /** Monday mockeado: registra los movimientos de grupo solicitados */ function mondayMock(opts: { item?: ItemFake | null; columnaId?: string | null } = {}) { return { movimientos: [] as { itemId: string; groupId: string }[], async columnaIdPorTitulo(_boardId: string, _titulo: string) { return opts.columnaId !== undefined ? opts.columnaId : 'status_col' }, async getItemConGrupo(_itemId: string) { return opts.item ?? null }, async moverItemAGrupo(itemId: string, groupId: string) { this.movimientos.push({ itemId, groupId }) }, } } const itemCon = (groupId: string, estado: string): ItemFake => ({ id: '999', name: 'Item Prueba', groupId, column_values: [{ id: 'status_col', text: estado, value: null }], }) describe('grupoDestino', () => { it('mapea labels conocidos de cada tablero', () => { expect(grupoDestino('111', 'NUEVO')).toBe('topics') expect(grupoDestino('111', 'CONTACTADO')).toBe('group_mm6s1jct') expect(grupoDestino('111', 'DESCARTADO')).toBe('group_mm6s96mc') expect(grupoDestino('222', 'Ganado')).toBe('group_mm6scqz3') expect(grupoDestino('222', 'Afluencia')).toBe('topics') expect(grupoDestino('333', 'INACTIVO')).toBe('group_mm6sqqq2') expect(grupoDestino('444', 'Notaría')).toBe('group_mm6syf9c') expect(grupoDestino('555', 'LIBERADO')).toBe('group_mm6s2yyx') }) it('label desconocido → null', () => { expect(grupoDestino('111', 'INVENTADO')).toBeNull() }) it('board sin mapeo → null', () => { expect(grupoDestino('999', 'NUEVO')).toBeNull() }) it('etapa vacía en Unidades → null (no se mueve)', () => { expect(grupoDestino('444', '')).toBeNull() expect(grupoDestino('444', ' ')).toBeNull() }) it('los 5 tableros del CRM tienen mapeo', () => { expect(Object.keys(GRUPOS_POR_ESTADO).sort()).toEqual(['111', '222', '333', '444', '555']) }) }) describe('moverAGrupoSegunEstado', () => { it('mueve el item cuando el grupo actual difiere del destino', async () => { const monday = mondayMock({ item: itemCon('topics', 'DESCARTADO') }) const r = await moverAGrupoSegunEstado(monday, '111', '999') expect(r).toEqual({ movido: true, grupo: 'group_mm6s96mc' }) expect(monday.movimientos).toEqual([{ itemId: '999', groupId: 'group_mm6s96mc' }]) }) it('no mueve cuando el item ya está en el grupo destino', async () => { const monday = mondayMock({ item: itemCon('group_mm6s96mc', 'DESCARTADO') }) const r = await moverAGrupoSegunEstado(monday, '111', '999') expect(r).toEqual({ movido: false }) expect(monday.movimientos).toEqual([]) }) it('item inexistente (borrado tras el webhook) no truena ni mueve', async () => { const monday = mondayMock({ item: null }) const r = await moverAGrupoSegunEstado(monday, '111', '999') expect(r).toEqual({ movido: false }) expect(monday.movimientos).toEqual([]) }) it('board sin mapeo no consulta ni mueve nada', async () => { const monday = mondayMock({ item: itemCon('topics', 'NUEVO') }) const r = await moverAGrupoSegunEstado(monday, '999', '999') expect(r).toEqual({ movido: false }) expect(monday.movimientos).toEqual([]) }) it('label no mapeado no mueve', async () => { const monday = mondayMock({ item: itemCon('topics', 'INVENTADO') }) const r = await moverAGrupoSegunEstado(monday, '111', '999') expect(r).toEqual({ movido: false }) expect(monday.movimientos).toEqual([]) }) })