feat(captura): módulo de captura por departamentos
Backend: tabla CapturaDepartamento, 5 departamentos, 7 desarrollos, service CRUD + importador Excel + 6 endpoints. Frontend: tabla editable inline, tabs por dept, resumen avance, paginación, filtro estatus, permisos por rol, dark mode. 746 API tests + 42 landing tests.
This commit is contained in:
209
apps/landing/src/components/TablaCaptura.test.tsx
Normal file
209
apps/landing/src/components/TablaCaptura.test.tsx
Normal file
@@ -0,0 +1,209 @@
|
||||
// @vitest-environment jsdom
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { cleanup, fireEvent, render, screen } from '@testing-library/react'
|
||||
import { TablaCaptura } from './TablaCaptura'
|
||||
import type { CampoDef, DatosCaptura } from '../services/captura'
|
||||
|
||||
const CAMPOS_OBRA: CampoDef[] = [
|
||||
{ campo: 'certificacion_gas', tipo: 'boolean', label: 'Certificación Gas' },
|
||||
{ campo: 'comentarios_obra', tipo: 'text', label: 'Comentarios' },
|
||||
]
|
||||
|
||||
const CAMPOS_VENTAS: CampoDef[] = [
|
||||
{ campo: 'estatus', tipo: 'select', label: 'Estatus', options: ['DISPONIBLE', 'APARTADO', 'VENDIDO'] },
|
||||
{ campo: 'precio_venta', tipo: 'number', label: 'Precio Venta' },
|
||||
]
|
||||
|
||||
const DATOS: DatosCaptura = {
|
||||
'409-1': { certificacion_gas: 'true', comentarios_obra: 'Listo' },
|
||||
'409-2': { certificacion_gas: null, comentarios_obra: null },
|
||||
}
|
||||
|
||||
const UNIDADES = ['409-1', '409-2']
|
||||
|
||||
afterEach(() => { cleanup() })
|
||||
|
||||
describe('TablaCaptura', () => {
|
||||
it('renderiza la tabla con unidades y campos', () => {
|
||||
const onGuardar = vi.fn()
|
||||
render(
|
||||
<TablaCaptura
|
||||
unidades={UNIDADES}
|
||||
campos={CAMPOS_OBRA}
|
||||
datos={DATOS}
|
||||
onGuardar={onGuardar}
|
||||
guardando={false}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(screen.getByText('409-1')).toBeTruthy()
|
||||
expect(screen.getByText('409-2')).toBeTruthy()
|
||||
expect(screen.getByText('Certificación Gas')).toBeTruthy()
|
||||
expect(screen.getByText('Comentarios')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('muestra checkboxes para campos boolean', () => {
|
||||
const onGuardar = vi.fn()
|
||||
render(
|
||||
<TablaCaptura
|
||||
unidades={UNIDADES}
|
||||
campos={CAMPOS_OBRA}
|
||||
datos={DATOS}
|
||||
onGuardar={onGuardar}
|
||||
guardando={false}
|
||||
/>,
|
||||
)
|
||||
|
||||
const checkboxes = screen.getAllByRole('checkbox')
|
||||
expect(checkboxes.length).toBe(2) // 2 unidades * 1 boolean campo
|
||||
// Primera unidad tiene certificacion_gas = 'true'
|
||||
expect((checkboxes[0] as HTMLInputElement).checked).toBe(true)
|
||||
// Segunda unidad tiene null
|
||||
expect((checkboxes[1] as HTMLInputElement).checked).toBe(false)
|
||||
})
|
||||
|
||||
it('muestra select para campos select', () => {
|
||||
const onGuardar = vi.fn()
|
||||
render(
|
||||
<TablaCaptura
|
||||
unidades={UNIDADES}
|
||||
campos={CAMPOS_VENTAS}
|
||||
datos={{}}
|
||||
onGuardar={onGuardar}
|
||||
guardando={false}
|
||||
/>,
|
||||
)
|
||||
|
||||
const selects = screen.getAllByRole('combobox')
|
||||
expect(selects.length).toBe(2) // 2 unidades * 1 select campo
|
||||
})
|
||||
|
||||
it('muestra "sin unidades" cuando la lista está vacía', () => {
|
||||
const onGuardar = vi.fn()
|
||||
render(
|
||||
<TablaCaptura
|
||||
unidades={[]}
|
||||
campos={CAMPOS_OBRA}
|
||||
datos={{}}
|
||||
onGuardar={onGuardar}
|
||||
guardando={false}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(screen.getByText(/No hay unidades/)).toBeTruthy()
|
||||
})
|
||||
|
||||
it('edita una celda y muestra el botón de guardar', () => {
|
||||
const onGuardar = vi.fn()
|
||||
render(
|
||||
<TablaCaptura
|
||||
unidades={UNIDADES}
|
||||
campos={CAMPOS_OBRA}
|
||||
datos={DATOS}
|
||||
onGuardar={onGuardar}
|
||||
guardando={false}
|
||||
/>,
|
||||
)
|
||||
|
||||
// Click en el checkbox de la segunda unidad (cambiar de unchecked a checked)
|
||||
const checkboxes = screen.getAllByRole('checkbox')
|
||||
fireEvent.click(checkboxes[1])
|
||||
|
||||
// Debería aparecer "Hay cambios sin guardar"
|
||||
expect(screen.getByText('Hay cambios sin guardar')).toBeTruthy()
|
||||
expect(screen.getByText('Guardar cambios')).toBeTruthy()
|
||||
expect(screen.getByText('Descartar')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('click en Guardar llama a onGuardar con los cambios dirty', () => {
|
||||
const onGuardar = vi.fn()
|
||||
render(
|
||||
<TablaCaptura
|
||||
unidades={UNIDADES}
|
||||
campos={CAMPOS_OBRA}
|
||||
datos={DATOS}
|
||||
onGuardar={onGuardar}
|
||||
guardando={false}
|
||||
/>,
|
||||
)
|
||||
|
||||
// Cambiar checkbox de la segunda unidad
|
||||
const checkboxes = screen.getAllByRole('checkbox')
|
||||
fireEvent.click(checkboxes[1])
|
||||
|
||||
// Click en Guardar
|
||||
fireEvent.click(screen.getByText('Guardar cambios'))
|
||||
|
||||
expect(onGuardar).toHaveBeenCalledTimes(1)
|
||||
const dirty = onGuardar.mock.calls[0][0]
|
||||
expect(dirty['409-2']).toEqual({ certificacion_gas: 'true' })
|
||||
})
|
||||
|
||||
it('click en Descartar elimina los cambios', () => {
|
||||
const onGuardar = vi.fn()
|
||||
render(
|
||||
<TablaCaptura
|
||||
unidades={UNIDADES}
|
||||
campos={CAMPOS_OBRA}
|
||||
datos={DATOS}
|
||||
onGuardar={onGuardar}
|
||||
guardando={false}
|
||||
/>,
|
||||
)
|
||||
|
||||
// Cambiar checkbox
|
||||
const checkboxes = screen.getAllByRole('checkbox')
|
||||
fireEvent.click(checkboxes[1])
|
||||
|
||||
// Descartar
|
||||
fireEvent.click(screen.getByText('Descartar'))
|
||||
|
||||
// Ya no debería mostrar "Hay cambios sin guardar"
|
||||
expect(screen.queryByText('Hay cambios sin guardar')).toBeNull()
|
||||
})
|
||||
|
||||
it('filtra por estatus', () => {
|
||||
const onGuardar = vi.fn()
|
||||
const datosConEstatus: DatosCaptura = {
|
||||
'409-1': { estatus: 'VENDIDO' },
|
||||
'409-2': { estatus: 'DISPONIBLE' },
|
||||
}
|
||||
|
||||
render(
|
||||
<TablaCaptura
|
||||
unidades={UNIDADES}
|
||||
campos={CAMPOS_VENTAS}
|
||||
datos={datosConEstatus}
|
||||
onGuardar={onGuardar}
|
||||
guardando={false}
|
||||
filtroEstatus="VENDIDO"
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(screen.getByText('409-1')).toBeTruthy()
|
||||
expect(screen.queryByText('409-2')).toBeNull()
|
||||
})
|
||||
|
||||
it('paginación: muestra paginación cuando hay >50 unidades', () => {
|
||||
const onGuardar = vi.fn()
|
||||
const unidadesGrandes = Array.from({ length: 60 }, (_, i) => `U-${String(i + 1).padStart(3, '0')}`)
|
||||
|
||||
render(
|
||||
<TablaCaptura
|
||||
unidades={unidadesGrandes}
|
||||
campos={CAMPOS_OBRA}
|
||||
datos={{}}
|
||||
onGuardar={onGuardar}
|
||||
guardando={false}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(screen.getByText(/Mostrando 1–50 de 60/)).toBeTruthy()
|
||||
expect(screen.getByText('Anterior')).toBeTruthy()
|
||||
expect(screen.getByText('Siguiente')).toBeTruthy()
|
||||
|
||||
// Navigate to page 2
|
||||
fireEvent.click(screen.getByText('Siguiente'))
|
||||
expect(screen.getByText(/Mostrando 51–60 de 60/)).toBeTruthy()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user