import { describe, it, expect, vi } from 'vitest' import { mount } from '@vue/test-utils' import { h } from 'vue' import ConvocatoriasSection from '../../src/components/WebPageSections/ConvocatoriasSection.vue' // Mock Ant Design Vue components const mockAntComponents = { 'a-badge': { template: '', props: ['count'] }, 'a-card': { template: '
' }, 'a-tag': { template: '', props: ['color'] }, 'a-divider': { template: '
' }, 'a-button': { template: '', props: ['type', 'size', 'ghost'], emits: ['click'] }, 'a-image': { template: '', props: ['src', 'alt', 'preview'] }, 'a-empty': { template: '
', props: ['description'] } } // Mock icons const mockIcons = { FileTextOutlined: { template: '' }, DollarOutlined: { template: '' }, TeamOutlined: { template: '' }, CalendarOutlined: { template: '' }, FormOutlined: { template: '' } } const createWrapper = (props = {}) => { return mount(ConvocatoriasSection, { props, global: { stubs: { ...mockAntComponents, ...mockIcons } } }) } describe('ConvocatoriasSection', () => { describe('when no procesos are provided', () => { it('renders empty state message', () => { const wrapper = createWrapper({ procesos: [] }) expect(wrapper.find('.empty-state').exists()).toBe(true) expect(wrapper.text()).toContain('No hay convocatorias vigentes en este momento') }) it('does not render main or secondary cards', () => { const wrapper = createWrapper({ procesos: [] }) expect(wrapper.find('.main-convocatoria-card').exists()).toBe(false) expect(wrapper.find('.secondary-list').exists()).toBe(false) }) }) describe('when one proceso is provided', () => { const singleProceso = [ { id: 1, titulo: 'Admisión Ordinaria 2026', subtitulo: 'Proceso regular de admisión', descripcion: 'Descripción del proceso de admisión', estado: 'publicado', fecha_inicio_inscripcion: '2026-02-01', fecha_fin_inscripcion: '2026-02-28', link_preinscripcion: 'https://example.com/preinscripcion' } ] it('renders main convocatoria card with correct title', () => { const wrapper = createWrapper({ procesos: singleProceso }) expect(wrapper.find('.main-convocatoria-card').exists()).toBe(true) expect(wrapper.find('h3').text()).toBe('Admisión Ordinaria 2026') }) it('renders the "Principal" badge on main card', () => { const wrapper = createWrapper({ procesos: singleProceso }) expect(wrapper.find('.card-badge').exists()).toBe(true) expect(wrapper.find('.card-badge').text()).toBe('Principal') }) it('renders action buttons for requisitos, pagos, vacantes, and cronograma', () => { const wrapper = createWrapper({ procesos: singleProceso }) const actionButtons = wrapper.findAll('.action-btn') expect(actionButtons.length).toBe(4) const buttonTexts = actionButtons.map(btn => btn.text()) expect(buttonTexts).toContain('Requisitos') expect(buttonTexts).toContain('Pagos') expect(buttonTexts).toContain('Vacantes') expect(buttonTexts).toContain('Cronograma') }) it('does not render secondary cards list when only one proceso', () => { const wrapper = createWrapper({ procesos: singleProceso }) expect(wrapper.find('.secondary-list').exists()).toBe(false) }) it('displays the estado tag with correct label', () => { const wrapper = createWrapper({ procesos: singleProceso }) const statusTag = wrapper.find('.status-tag') expect(statusTag.exists()).toBe(true) expect(statusTag.text()).toBe('Abierto') // 'publicado' maps to 'Abierto' }) it('displays inscription dates when provided', () => { const wrapper = createWrapper({ procesos: singleProceso }) expect(wrapper.text()).toContain('Inscripciones:') }) }) describe('when multiple procesos are provided', () => { const multipleProcesos = [ { id: 1, titulo: 'Proceso Principal', descripcion: 'Descripción del proceso principal', estado: 'publicado' }, { id: 2, titulo: 'Proceso Secundario 1', descripcion: 'Descripción secundario 1', estado: 'en_proceso' }, { id: 3, titulo: 'Proceso Secundario 2', descripcion: 'Descripción secundario 2', estado: 'nuevo' } ] it('renders main card for first proceso', () => { const wrapper = createWrapper({ procesos: multipleProcesos }) expect(wrapper.find('.main-convocatoria-card').exists()).toBe(true) expect(wrapper.find('h3').text()).toBe('Proceso Principal') }) it('renders secondary cards for remaining procesos', () => { const wrapper = createWrapper({ procesos: multipleProcesos }) expect(wrapper.find('.secondary-list').exists()).toBe(true) const secondaryCards = wrapper.findAll('.secondary-convocatoria-card') expect(secondaryCards.length).toBe(2) }) it('renders correct titles in secondary cards', () => { const wrapper = createWrapper({ procesos: multipleProcesos }) const secondaryTitles = wrapper.findAll('.secondary-title') expect(secondaryTitles[0].text()).toBe('Proceso Secundario 1') expect(secondaryTitles[1].text()).toBe('Proceso Secundario 2') }) it('renders estado tags with correct colors for different estados', () => { const wrapper = createWrapper({ procesos: multipleProcesos }) const statusTags = wrapper.findAll('.status-tag') // First is main card (publicado), then secondary cards expect(statusTags[0].text()).toBe('Abierto') // publicado expect(statusTags[1].text()).toBe('En Proceso') // en_proceso expect(statusTags[2].text()).toBe('PRÓXIMAMENTE') // nuevo }) }) describe('emits events correctly', () => { const procesos = [ { id: 1, titulo: 'Proceso Test', estado: 'publicado' }, { id: 2, titulo: 'Proceso Secundario', estado: 'publicado' } ] it('emits show-modal event with correct payload when action button is clicked', async () => { const wrapper = createWrapper({ procesos }) const actionButtons = wrapper.findAll('.action-btn') await actionButtons[0].trigger('click') // Requisitos button expect(wrapper.emitted('show-modal')).toBeTruthy() expect(wrapper.emitted('show-modal')[0]).toEqual([ { procesoId: 1, tipo: 'requisitos' } ]) }) it('emits show-modal for pagos button', async () => { const wrapper = createWrapper({ procesos }) const actionButtons = wrapper.findAll('.action-btn') await actionButtons[1].trigger('click') // Pagos button expect(wrapper.emitted('show-modal')[0]).toEqual([ { procesoId: 1, tipo: 'pagos' } ]) }) it('emits show-modal for vacantes button', async () => { const wrapper = createWrapper({ procesos }) const actionButtons = wrapper.findAll('.action-btn') await actionButtons[2].trigger('click') // Vacantes button expect(wrapper.emitted('show-modal')[0]).toEqual([ { procesoId: 1, tipo: 'vacantes' } ]) }) it('emits show-modal for cronograma button', async () => { const wrapper = createWrapper({ procesos }) const actionButtons = wrapper.findAll('.action-btn') await actionButtons[3].trigger('click') // Cronograma button expect(wrapper.emitted('show-modal')[0]).toEqual([ { procesoId: 1, tipo: 'cronograma' } ]) }) }) describe('estado mapping', () => { const testEstadoCases = [ { estado: 'publicado', expectedLabel: 'Abierto' }, { estado: 'en_proceso', expectedLabel: 'En Proceso' }, { estado: 'nuevo', expectedLabel: 'PRÓXIMAMENTE' }, { estado: 'finalizado', expectedLabel: 'FINALIZADO' }, { estado: 'cancelado', expectedLabel: 'CANCELADO' } ] testEstadoCases.forEach(({ estado, expectedLabel }) => { it(`maps estado "${estado}" to label "${expectedLabel}"`, () => { const wrapper = createWrapper({ procesos: [{ id: 1, titulo: 'Test', estado }] }) expect(wrapper.find('.status-tag').text()).toBe(expectedLabel) }) }) }) describe('description display', () => { it('displays descripcion when provided', () => { const wrapper = createWrapper({ procesos: [{ id: 1, titulo: 'Test', descripcion: 'Esta es la descripción del proceso', estado: 'publicado' }] }) expect(wrapper.find('.convocatoria-desc').text()).toBe('Esta es la descripción del proceso') }) it('falls back to subtitulo when descripcion is not provided', () => { const wrapper = createWrapper({ procesos: [{ id: 1, titulo: 'Test', subtitulo: 'Este es el subtítulo', estado: 'publicado' }] }) expect(wrapper.find('.convocatoria-desc').text()).toBe('Este es el subtítulo') }) it('shows default text when neither descripcion nor subtitulo is provided', () => { const wrapper = createWrapper({ procesos: [{ id: 1, titulo: 'Test', estado: 'publicado' }] }) expect(wrapper.find('.convocatoria-desc').text()).toBe('Proceso de admisión') }) }) })