/**
* Tests de la sección "Análisis de Impacto" del GlobalSettingsPanel.
*
* Los mocks usan vi.hoisted() para que currentProcess sea una referencia
* estable entre renders (evita el loop infinito del useEffect de sync).
*/
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { render, screen, fireEvent, act } from '@testing-library/react'
import { TooltipProvider } from '@/components/ui/tooltip'
// ─── Mocks con referencia estable ─────────────────────────────────────────────
const processStoreMock = vi.hoisted(() => ({
currentProcess: {
id: 'p1', name: 'Proceso test', clientName: 'Cliente A',
bpmnXml: '', currency: 'USD', overheadPercentage: 0.2,
annualFrequency: 1000, analysisHorizonYears: 3, automationInvestment: 0,
createdAt: 0, updatedAt: 0,
},
updateProcess: vi.fn(),
subscribe: vi.fn(),
}))
vi.mock('@/store/process-store', () => ({
useProcessStore: () => processStoreMock,
}))
vi.mock('@/store/simulation-store', () => ({
useSimulationStore: () => ({
resultActual: null,
resultAutomated: null,
invalidateResults: vi.fn(),
}),
}))
import { GlobalSettingsPanel } from '@/features/workspace/GlobalSettingsPanel'
// ─── Helper ───────────────────────────────────────────────────────────────────
function renderPanel() {
return render(
)
}
// ─── Tests ────────────────────────────────────────────────────────────────────
beforeEach(() => {
processStoreMock.updateProcess.mockReset()
processStoreMock.updateProcess.mockResolvedValue(undefined)
// Restaurar defaults del proceso
processStoreMock.currentProcess.annualFrequency = 1000
processStoreMock.currentProcess.analysisHorizonYears = 3
processStoreMock.currentProcess.automationInvestment = 0
})
describe('GlobalSettingsPanel — sección Análisis de Impacto', () => {
it('renderiza los 3 campos de impacto con sus labels correctos', () => {
renderPanel()
expect(screen.getByLabelText(/Frecuencia anual/i)).toBeInTheDocument()
expect(screen.getByText(/Horizonte de análisis/i)).toBeInTheDocument()
expect(screen.getByLabelText(/Inversión en automatización/i)).toBeInTheDocument()
})
it('frecuencia anual muestra el default 1000 del proceso', () => {
renderPanel()
const freqInput = screen.getByLabelText(/Frecuencia anual/i) as HTMLInputElement
expect(freqInput.value).toBe('1000')
})
it('editar frecuencia y guardar incluye el nuevo valor en updateProcess', async () => {
renderPanel()
const freqInput = screen.getByLabelText(/Frecuencia anual/i)
await act(async () => {
fireEvent.change(freqInput, { target: { value: '5000' } })
})
// Después de cambiar, el botón debería mostrar "Guardar configuración"
const guardarBtn = await screen.findByRole('button', { name: /Guardar/i })
await act(async () => { fireEvent.click(guardarBtn) })
expect(processStoreMock.updateProcess).toHaveBeenCalledOnce()
const calledWith = processStoreMock.updateProcess.mock.calls[0][0]
expect(calledWith.annualFrequency).toBe(5000)
})
it('horizonte de análisis se muestra en texto (default 3 años)', () => {
renderPanel()
expect(screen.getByText('3 años')).toBeInTheDocument()
})
it('guardar incluye horizonte actual en updateProcess', async () => {
renderPanel()
const freqInput = screen.getByLabelText(/Frecuencia anual/i)
await act(async () => {
fireEvent.change(freqInput, { target: { value: '1200' } })
})
const guardarBtn = await screen.findByRole('button', { name: /Guardar/i })
await act(async () => { fireEvent.click(guardarBtn) })
const calledWith = processStoreMock.updateProcess.mock.calls[0][0]
expect(calledWith.analysisHorizonYears).toBe(3)
expect(calledWith.analysisHorizonYears).toBeGreaterThanOrEqual(1)
expect(calledWith.analysisHorizonYears).toBeLessThanOrEqual(10)
})
it('editar inversión en automatización y guardar la incluye correctamente', async () => {
renderPanel()
const investInput = screen.getByLabelText(/Inversión en automatización/i)
await act(async () => {
fireEvent.change(investInput, { target: { value: '75000' } })
})
const guardarBtn = await screen.findByRole('button', { name: /Guardar/i })
await act(async () => { fireEvent.click(guardarBtn) })
const calledWith = processStoreMock.updateProcess.mock.calls[0][0]
expect(calledWith.automationInvestment).toBe(75000)
})
it('sección "ANÁLISIS DE IMPACTO" aparece con su label de sección', () => {
renderPanel()
expect(screen.getByText(/Análisis de Impacto/i)).toBeInTheDocument()
})
})