Files
Marcos Benítez bed161c92a feat: MVP Fase 0 — Process Cost Platform v0.1.0
Plataforma completa de análisis de costos operativos basada en BPMN 2.0.

Funcionalidades incluidas:
- Import de archivos BPMN 2.0 por drag & drop + 3 procesos de ejemplo
- Visualización read-only del diagrama (bpmn-js)
- Configuración de actividades (costo, tiempo, recursos asignados)
- CRUD de recursos (rol, persona, sistema, equipo, insumo)
- Configuración global (moneda, overhead %, nombre, cliente)
- Motor de simulación determinístico agregado con propagación de gateways XOR/AND
- Reporte visual con mapa de calor en dos modos (relativo/absoluto)
- Gráficos: KPIs, top actividades, composición, costo por recurso
- Export PDF (jsPDF + html2canvas) y CSV (papaparse)
- Persistencia en IndexedDB (Dexie)
- 268 tests unitarios/integración + 6 E2E con Playwright
- Deploy: https://process-cost-platform.pages.dev

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 01:58:40 -03:00

84 lines
2.7 KiB
TypeScript

import { describe, it, expect } from 'vitest'
import { slugify, buildFileName } from '@/lib/export/slug'
describe('slugify', () => {
it('"Proceso de Compras" → "proceso-de-compras"', () => {
expect(slugify('Proceso de Compras')).toBe('proceso-de-compras')
})
it('"Análisis Año 2025" → "analisis-ano-2025"', () => {
expect(slugify('Análisis Año 2025')).toBe('analisis-ano-2025')
})
it('elimina la ñ → n', () => {
expect(slugify('Gestión de Compañía')).toBe('gestion-de-compania')
})
it('elimina acentos (á é í ó ú ü)', () => {
expect(slugify('Ú ltimo Análisis Crítico')).toBe('u-ltimo-analisis-critico')
})
it('caracteres especiales → guiones', () => {
expect(slugify('Proceso #1 / Sub-proceso (test)')).toBe('proceso-1-sub-proceso-test')
})
it('múltiples espacios → un solo guión', () => {
expect(slugify('Proceso de ventas')).toBe('proceso-de-ventas')
})
it('string vacío → string vacío', () => {
expect(slugify('')).toBe('')
})
it('solo números → se mantienen', () => {
expect(slugify('2025')).toBe('2025')
})
it('ya en minúsculas sin acentos → sin cambios relevantes', () => {
expect(slugify('proceso-lineal')).toBe('proceso-lineal')
})
it('limita a 60 caracteres', () => {
const long = 'a'.repeat(100)
expect(slugify(long)).toHaveLength(60)
})
})
describe('buildFileName', () => {
// new Date(año, mes0, día) → fecha local sin ambigüedad de timezone
const date = new Date(2026, 4, 13) // 13 de mayo de 2026, local time
it('genera filename con proceso + cliente + fecha', () => {
const name = buildFileName('Proceso de Ventas', 'Banco ABC', date, 'pdf')
expect(name).toBe('proceso-de-ventas_banco-abc_20260513.pdf')
})
it('omite cliente si está vacío', () => {
const name = buildFileName('Proceso de Ventas', '', date, 'csv')
expect(name).toBe('proceso-de-ventas_20260513.csv')
})
it('omite cliente si es undefined', () => {
const name = buildFileName('Proceso', undefined, date, 'pdf')
expect(name).toBe('proceso_20260513.pdf')
})
it('extensión csv correcta', () => {
const name = buildFileName('test', 'cliente', date, 'csv')
expect(name).toMatch(/\.csv$/)
})
it('extensión pdf correcta', () => {
const name = buildFileName('test', 'cliente', date, 'pdf')
expect(name).toMatch(/\.pdf$/)
})
it('nombre con caracteres especiales queda limpio (sin #, paréntesis)', () => {
const name = buildFileName('Análisis #1', 'Empresa S.A.', date, 'csv')
// Verificar solo el slug (sin la extensión que tiene un punto legítimo)
const slug = name.replace(/\.\w+$/, '')
expect(slug).not.toMatch(/[#()]/)
expect(name).toMatch(/analisis/)
})
})