Files
FRASA-CAS/api-gateway/src/controllers/captura-departamento.controller.test.ts
Consult AS Technology c2a8f4e929 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.
2026-09-07 07:59:14 +00:00

224 lines
8.1 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest'
import type { Request, Response } from 'express'
// ---------- Prisma mockeado ----------
const prismaMock = vi.hoisted(() => ({
capturaDepartamento: {
findMany: vi.fn(),
findUnique: vi.fn(),
count: vi.fn(),
upsert: vi.fn(),
},
$transaction: vi.fn(),
}))
vi.mock('../services/prisma.js', () => ({ prisma: prismaMock }))
// Mock del service para no depender de Prisma real
vi.mock('../services/captura-departamento.service.js', () => ({
obtenerUnidades: vi.fn(),
obtenerCapturas: vi.fn(),
obtenerCapturaUnidad: vi.fn(),
guardarCampo: vi.fn(),
guardarBulk: vi.fn(),
resumenAvance: vi.fn(),
importarDesdeExcel: vi.fn(),
}))
import {
listarEndpoint,
unidadesEndpoint,
resumenEndpoint,
guardarEndpoint,
bulkEndpoint,
importarEndpoint,
requireAdminCaptura,
} from './captura-departamento.controller.js'
import * as capturaService from '../services/captura-departamento.service.js'
function reqFake(opts: { query?: Record<string, string>; body?: unknown; params?: Record<string, string>; token?: { sub: string; rol: string } }): Request {
return {
query: opts.query ?? {},
body: opts.body ?? {},
params: opts.params ?? {},
usuarioToken: opts.token,
} as unknown as Request
}
function resFake() {
const json = vi.fn()
const end = vi.fn()
const statusFn = vi.fn().mockReturnValue({ json, end })
return { res: { json, end, status: statusFn } as unknown as Response, status: statusFn, json, end }
}
beforeEach(() => {
vi.clearAllMocks()
})
// ── requireAdminCaptura ─────────────────────────────────────────────
describe('requireAdminCaptura', () => {
it('pasa si rol es admin', () => {
const next = vi.fn()
const req = reqFake({ token: { sub: 'u1', rol: 'admin' } })
requireAdminCaptura(req, {} as Response, next)
expect(next).toHaveBeenCalled()
})
it('lanza 403 si rol no es admin', () => {
const req = reqFake({ token: { sub: 'u1', rol: 'vendedor' } })
expect(() => requireAdminCaptura(req, {} as Response, vi.fn())).toThrow('Se requiere rol admin')
})
it('lanza 403 si no hay token', () => {
const req = reqFake({})
expect(() => requireAdminCaptura(req, {} as Response, vi.fn())).toThrow('Se requiere rol admin')
})
})
// ── listarEndpoint ──────────────────────────────────────────────────
describe('listarEndpoint (GET /api/captura)', () => {
it('retorna capturas agrupadas', async () => {
const fake = { U101: { estatus: 'VENDIDO' } }
vi.mocked(capturaService.obtenerCapturas).mockResolvedValue(fake)
const { res, json } = resFake()
await listarEndpoint(reqFake({ query: { desarrollo: 'SENDA' }, token: { sub: 'u1', rol: 'admin' } }), res)
expect(json).toHaveBeenCalledWith(fake)
expect(capturaService.obtenerCapturas).toHaveBeenCalledWith('SENDA', undefined)
})
it('pasa departamento cuando se provee', async () => {
vi.mocked(capturaService.obtenerCapturas).mockResolvedValue({})
const { res } = resFake()
await listarEndpoint(
reqFake({ query: { desarrollo: 'SENDA', departamento: 'OBRA' }, token: { sub: 'u1', rol: 'admin' } }),
res,
)
expect(capturaService.obtenerCapturas).toHaveBeenCalledWith('SENDA', 'OBRA')
})
it('rechaza sin desarrollo', async () => {
const { res } = resFake()
await expect(listarEndpoint(reqFake({ query: {}, token: { sub: 'u1', rol: 'admin' } }), res)).rejects.toThrow()
})
})
// ── unidadesEndpoint ────────────────────────────────────────────────
describe('unidadesEndpoint (GET /api/captura/unidades)', () => {
it('retorna lista de unidades', async () => {
vi.mocked(capturaService.obtenerUnidades).mockResolvedValue(['U-101', 'U-102'])
const { res, json } = resFake()
await unidadesEndpoint(reqFake({ query: { desarrollo: 'SENDA' }, token: { sub: 'u1', rol: 'admin' } }), res)
expect(json).toHaveBeenCalledWith(['U-101', 'U-102'])
})
})
// ── resumenEndpoint ─────────────────────────────────────────────────
describe('resumenEndpoint (GET /api/captura/resumen)', () => {
it('retorna resumen de avance', async () => {
const fake = [{ departamento: 'OBRA', camposTotales: 8, camposLlenos: 4, porcentaje: 50 }]
vi.mocked(capturaService.resumenAvance).mockResolvedValue(fake)
const { res, json } = resFake()
await resumenEndpoint(reqFake({ query: { desarrollo: 'SENDA' }, token: { sub: 'u1', rol: 'admin' } }), res)
expect(json).toHaveBeenCalledWith(fake)
})
})
// ── guardarEndpoint ─────────────────────────────────────────────────
describe('guardarEndpoint (POST /api/captura)', () => {
it('guarda campo y retorna 204', async () => {
vi.mocked(capturaService.guardarCampo).mockResolvedValue(undefined)
const { res, status } = resFake()
await guardarEndpoint(
reqFake({
body: { desarrollo: 'SENDA', unidadCodigo: 'U-101', departamento: 'VENTAS', campo: 'estatus', valor: 'VENDIDO' },
token: { sub: 'u1', rol: 'admin' },
}),
res,
)
expect(status).toHaveBeenCalledWith(204)
expect(capturaService.guardarCampo).toHaveBeenCalledWith('SENDA', 'U-101', 'VENTAS', 'estatus', 'VENDIDO', 'u1')
})
it('rechaza departamento inválido', async () => {
const { res } = resFake()
await expect(
guardarEndpoint(
reqFake({
body: { desarrollo: 'SENDA', unidadCodigo: 'U-101', departamento: 'INVALIDO', campo: 'x', valor: 'y' },
token: { sub: 'u1', rol: 'admin' },
}),
res,
),
).rejects.toThrow('Departamento inválido')
})
})
// ── bulkEndpoint ────────────────────────────────────────────────────
describe('bulkEndpoint (POST /api/captura/bulk)', () => {
it('guarda múltiple y retorna 204', async () => {
vi.mocked(capturaService.guardarBulk).mockResolvedValue(undefined)
const { res, status } = resFake()
await bulkEndpoint(
reqFake({
body: {
desarrollo: 'SENDA',
departamento: 'VENTAS',
registros: [
{ unidad: 'U-101', campo: 'estatus', valor: 'VENDIDO' },
{ unidad: 'U-102', campo: 'estatus', valor: 'DISPONIBLE' },
],
},
token: { sub: 'u1', rol: 'admin' },
}),
res,
)
expect(status).toHaveBeenCalledWith(204)
expect(capturaService.guardarBulk).toHaveBeenCalledWith('SENDA', 'VENTAS', [
{ unidad: 'U-101', campo: 'estatus', valor: 'VENDIDO' },
{ unidad: 'U-102', campo: 'estatus', valor: 'DISPONIBLE' },
], 'u1')
})
})
// ── importarEndpoint ────────────────────────────────────────────────
describe('importarEndpoint (POST /api/captura/importar)', () => {
it('importa datos y retorna resultado (admin)', async () => {
const fake = { registrosCreados: 10, registrosActualizados: 5 }
vi.mocked(capturaService.importarDesdeExcel).mockResolvedValue(fake)
const { res, json } = resFake()
await importarEndpoint(
reqFake({
body: { desarrollo: 'SENDA', datos: [['CLIENTE', 'ESTATUS'], ['U-101', 'VENDIDO']] },
token: { sub: 'u1', rol: 'admin' },
}),
res,
)
expect(json).toHaveBeenCalledWith(fake)
expect(capturaService.importarDesdeExcel).toHaveBeenCalledWith('SENDA', [['CLIENTE', 'ESTATUS'], ['U-101', 'VENDIDO']], 'u1')
})
it('lanza 403 si no es admin', async () => {
const req = reqFake({
body: { desarrollo: 'SENDA', datos: [] },
token: { sub: 'u1', rol: 'vendedor' },
})
expect(() => requireAdminCaptura(req, {} as Response, vi.fn())).toThrow('Se requiere rol admin')
})
})