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>
92 lines
4.3 KiB
TypeScript
92 lines
4.3 KiB
TypeScript
/**
|
||
* Smoke test de producción — verifica el flujo completo en la URL live.
|
||
* Usa el proceso de ejemplo "Aprobación de crédito" (carga via fetch desde el CDN).
|
||
*
|
||
* Ejecutar: npx playwright test --config=playwright.prod.config.ts
|
||
*/
|
||
import { test, expect } from '@playwright/test'
|
||
import { readFileSync, mkdirSync } from 'fs'
|
||
import { resolve } from 'path'
|
||
import { fileURLToPath } from 'url'
|
||
|
||
const __dirname = fileURLToPath(new URL('.', import.meta.url))
|
||
const OUTPUT_DIR = resolve(__dirname, '__output__')
|
||
|
||
test.beforeAll(() => {
|
||
mkdirSync(OUTPUT_DIR, { recursive: true })
|
||
})
|
||
|
||
test('prod-smoke — import → simulate → export PDF', async ({ page }) => {
|
||
// ── 1. Landing page carga correctamente ──────────────────────────────────
|
||
await page.goto('/')
|
||
await expect(page).toHaveTitle(/Process Cost Platform/)
|
||
|
||
// Verificar heading principal
|
||
await expect(page.getByText('Cuantificá el costo operativo')).toBeVisible({ timeout: 10_000 })
|
||
|
||
// Verificar que los 3 procesos de ejemplo están presentes
|
||
await expect(page.getByText('Aprobación de crédito')).toBeVisible()
|
||
await expect(page.getByText('Proceso lineal simple')).toBeVisible()
|
||
await expect(page.getByText('Control de calidad con revisión')).toBeVisible()
|
||
|
||
// ── 2. Cargar proceso de ejemplo "Proceso lineal simple" ──────────────────
|
||
await page.getByText('Proceso lineal simple').click()
|
||
|
||
// Esperar navegación al workspace
|
||
await page.waitForURL(/\/workspace\//, { timeout: 30_000 })
|
||
|
||
// ── 3. Workspace: diagrama BPMN + botón Simular ───────────────────────────
|
||
await page.waitForSelector('button:has-text("Simular")', { timeout: 20_000 })
|
||
await page.waitForTimeout(1_500)
|
||
|
||
// Nombre del proceso visible en la topbar
|
||
await expect(page.getByText('simple-linear')).toBeVisible()
|
||
|
||
const simularBtn = page.getByRole('button', { name: 'Simular' })
|
||
await expect(simularBtn).not.toBeDisabled({ timeout: 5_000 })
|
||
await simularBtn.click()
|
||
|
||
// ── 4. Reporte carga ──────────────────────────────────────────────────────
|
||
await page.waitForURL(/\/report\//, { timeout: 30_000 })
|
||
await page.waitForSelector('button:has-text("Exportar PDF")', { timeout: 30_000 })
|
||
await page.waitForSelector('.bpmn-container .djs-group', { timeout: 30_000 })
|
||
|
||
// KPIs visibles
|
||
await expect(page.getByText('COSTO TOTAL ESPERADO')).toBeVisible()
|
||
|
||
// ── 5. Export PDF ─────────────────────────────────────────────────────────
|
||
const pdfPath = resolve(OUTPUT_DIR, 'prod-smoke.pdf')
|
||
|
||
const pdfDownload = page.waitForEvent('download', { timeout: 90_000 })
|
||
await page.getByRole('button', { name: 'Exportar PDF' }).click()
|
||
const dl = await pdfDownload
|
||
await dl.saveAs(pdfPath)
|
||
|
||
const pdfBuffer = readFileSync(pdfPath)
|
||
const pdfKB = (pdfBuffer.length / 1024).toFixed(1)
|
||
console.log(`\n📄 prod-smoke.pdf: ${pdfBuffer.length} bytes (${pdfKB} KB)`)
|
||
|
||
expect(pdfBuffer.length, 'PDF debe ser > 40 KB').toBeGreaterThan(40_000)
|
||
expect(pdfBuffer.length, 'PDF debe ser < 2 MB').toBeLessThan(2_000_000)
|
||
|
||
// JPEG heatmap embebido
|
||
const jpegMarker = Buffer.from([0xff, 0xd8, 0xff])
|
||
const hasJpeg = pdfBuffer.includes(jpegMarker)
|
||
console.log(` Heatmap JPEG embebido: ${hasJpeg}`)
|
||
expect(hasJpeg, 'PDF de prod debe tener heatmap embebido').toBe(true)
|
||
|
||
// ── 6. Export CSV ─────────────────────────────────────────────────────────
|
||
const csvPath = resolve(OUTPUT_DIR, 'prod-smoke.csv')
|
||
const csvDownload = page.waitForEvent('download')
|
||
await page.getByRole('button', { name: 'Exportar CSV' }).click()
|
||
const dlCsv = await csvDownload
|
||
await dlCsv.saveAs(csvPath)
|
||
|
||
const csvText = readFileSync(csvPath, 'utf-8')
|
||
expect(csvText, 'CSV debe tener BOM UTF-8').toMatch(/^/)
|
||
expect(csvText, 'CSV debe contener encabezado').toContain('Costo total')
|
||
|
||
console.log(`\n✅ Prod smoke PASSED — https://process-cost-platform.pages.dev`)
|
||
console.log(` PDF: ${pdfKB} KB | CSV: ${csvText.length} chars`)
|
||
})
|