137 lines
5.1 KiB
TypeScript
137 lines
5.1 KiB
TypeScript
/**
|
|
* 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: '<def/>', 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(),
|
|
}),
|
|
}))
|
|
|
|
vi.mock('@/auth/AuthContext', () => ({
|
|
useAuth: () => ({ user: { id: 'test-user-id' } }),
|
|
}))
|
|
|
|
import { GlobalSettingsPanel } from '@/features/workspace/GlobalSettingsPanel'
|
|
|
|
// ─── Helper ───────────────────────────────────────────────────────────────────
|
|
|
|
function renderPanel() {
|
|
return render(
|
|
<TooltipProvider>
|
|
<GlobalSettingsPanel />
|
|
</TooltipProvider>
|
|
)
|
|
}
|
|
|
|
// ─── 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()
|
|
})
|
|
})
|