Commit pendiente de Etapas 3+4. Son cambios validados (migraciones corriendo, build verde, 521 tests). Hay que commitearlos antes de empezar la siguiente etapa.
This commit is contained in:
@@ -1,220 +0,0 @@
|
||||
/**
|
||||
* Tests de migración Dexie v3 → v4 (Sprint 3).
|
||||
*
|
||||
* Verifican que:
|
||||
* 1. Proceso existente conserva todos sus campos y recibe groupId=null, tags=[].
|
||||
* 2. Activity existente conserva assignedResources y recibe automatedAssignedResources=[].
|
||||
* 3. Settings singleton creado con groupLabel='Cliente' durante el upgrade.
|
||||
* 4. El upgrade es idempotente: datos ya migrados no se corrompen.
|
||||
* 5. groupId puede ser un UUID válido y es queryable como índice.
|
||||
*
|
||||
* Usan fake-indexeddb (parcheado en tests/setup.ts).
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
||||
import { db } from '@/persistence/db'
|
||||
import type { Process, ProcessGroup } from '@/domain/types'
|
||||
|
||||
// ─── Helper ───────────────────────────────────────────────────────────────────
|
||||
|
||||
function makeProcess(id: string, overrides: Partial<Process> = {}): Process {
|
||||
return {
|
||||
id,
|
||||
name: `Proceso ${id}`,
|
||||
clientName: 'Cliente Test',
|
||||
bpmnXml: '<definitions/>',
|
||||
currency: 'USD',
|
||||
overheadPercentage: 0.2,
|
||||
annualFrequency: 1000,
|
||||
analysisHorizonYears: 3,
|
||||
automationInvestment: 0,
|
||||
createdAt: 1000,
|
||||
updatedAt: 2000,
|
||||
groupId: null,
|
||||
tags: [],
|
||||
...overrides,
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Test 1 — Process: lógica del upgrade (puro, sin base de datos) ───────────
|
||||
|
||||
describe('Migración Dexie v4 — Process: lógica de upgrade', () => {
|
||||
it('proceso v3 (sin groupId ni tags) recibe defaults correctos preservando campos originales', () => {
|
||||
const proc: Record<string, unknown> = {
|
||||
id: 'p1',
|
||||
name: 'Proceso Legado',
|
||||
clientName: 'Cliente A',
|
||||
bpmnXml: '<definitions/>',
|
||||
currency: 'PYG',
|
||||
overheadPercentage: 0.15,
|
||||
annualFrequency: 500,
|
||||
analysisHorizonYears: 5,
|
||||
automationInvestment: 50_000,
|
||||
createdAt: 1000,
|
||||
updatedAt: 2000,
|
||||
// Sin groupId ni tags — formato v3
|
||||
}
|
||||
|
||||
// Simular callback del upgrade
|
||||
if (proc.groupId === undefined) proc.groupId = null
|
||||
if (!Array.isArray(proc.tags)) proc.tags = []
|
||||
|
||||
// Campos originales intactos
|
||||
expect(proc.id).toBe('p1')
|
||||
expect(proc.name).toBe('Proceso Legado')
|
||||
expect(proc.clientName).toBe('Cliente A')
|
||||
expect(proc.currency).toBe('PYG')
|
||||
expect(proc.overheadPercentage).toBe(0.15)
|
||||
expect(proc.annualFrequency).toBe(500)
|
||||
expect(proc.analysisHorizonYears).toBe(5)
|
||||
expect(proc.automationInvestment).toBe(50_000)
|
||||
expect(proc.createdAt).toBe(1000)
|
||||
expect(proc.updatedAt).toBe(2000)
|
||||
// Nuevos campos con defaults correctos
|
||||
expect(proc.groupId).toBeNull()
|
||||
expect(proc.tags).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
// ─── Test 2 — Activity: lógica del upgrade (puro, sin base de datos) ─────────
|
||||
|
||||
describe('Migración Dexie v4 — Activity: lógica de upgrade', () => {
|
||||
it('activity v3 con assignedResources poblados recibe automatedAssignedResources=[]', () => {
|
||||
const act: Record<string, unknown> = {
|
||||
id: 'a1',
|
||||
processId: 'p1',
|
||||
bpmnElementId: 'task_a1',
|
||||
name: 'Tarea A',
|
||||
type: 'task',
|
||||
directCostFixed: 500,
|
||||
executionTimeMinutes: 60,
|
||||
assignedResources: [{ resourceId: 'r1', utilizationMinutes: 30, units: 1 }],
|
||||
automatable: true,
|
||||
automatedCostFixed: 200,
|
||||
automatedTimeMinutes: 15,
|
||||
// Sin automatedAssignedResources — formato v3
|
||||
}
|
||||
|
||||
// Simular callback del upgrade
|
||||
if (!Array.isArray(act.automatedAssignedResources)) {
|
||||
act.automatedAssignedResources = []
|
||||
}
|
||||
|
||||
// assignedResources no fue alterado
|
||||
expect(act.assignedResources).toEqual([{ resourceId: 'r1', utilizationMinutes: 30, units: 1 }])
|
||||
// campos de automatización intactos
|
||||
expect(act.automatable).toBe(true)
|
||||
expect(act.automatedCostFixed).toBe(200)
|
||||
expect(act.automatedTimeMinutes).toBe(15)
|
||||
// nuevo campo vacío
|
||||
expect(act.automatedAssignedResources).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
// ─── Test 3 — Settings singleton (integración) ───────────────────────────────
|
||||
|
||||
describe('Migración Dexie v4 — Settings singleton', () => {
|
||||
beforeEach(async () => {
|
||||
await db.open()
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await db.close()
|
||||
})
|
||||
|
||||
it('singleton creado con groupLabel=Cliente durante el upgrade', async () => {
|
||||
const settings = await db.settings.get('singleton')
|
||||
expect(settings).toBeDefined()
|
||||
expect(settings!.id).toBe('singleton')
|
||||
expect(settings!.groupLabel).toBe('Cliente')
|
||||
})
|
||||
})
|
||||
|
||||
// ─── Test 4 — Idempotencia (puro, sin base de datos) ─────────────────────────
|
||||
|
||||
describe('Migración Dexie v4 — Idempotencia', () => {
|
||||
it('upgrade no corrompe proceso ya migrado (groupId y tags con valores)', () => {
|
||||
const proc: Record<string, unknown> = {
|
||||
id: 'p2',
|
||||
groupId: null,
|
||||
tags: ['facturación', 'BPMN'],
|
||||
}
|
||||
|
||||
// Simular upgrade (idempotente)
|
||||
if (proc.groupId === undefined) proc.groupId = null
|
||||
if (!Array.isArray(proc.tags)) proc.tags = []
|
||||
|
||||
expect(proc.groupId).toBeNull()
|
||||
expect(proc.tags).toEqual(['facturación', 'BPMN'])
|
||||
})
|
||||
|
||||
it('upgrade no corrompe activity ya migrada (automatedAssignedResources poblado)', () => {
|
||||
const act: Record<string, unknown> = {
|
||||
id: 'a2',
|
||||
automatedAssignedResources: [{ resourceId: 'r2', utilizationMinutes: 10, units: 2 }],
|
||||
}
|
||||
|
||||
if (!Array.isArray(act.automatedAssignedResources)) {
|
||||
act.automatedAssignedResources = []
|
||||
}
|
||||
|
||||
expect(act.automatedAssignedResources).toEqual([
|
||||
{ resourceId: 'r2', utilizationMinutes: 10, units: 2 },
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
// ─── Test 5 — groupId como UUID válido (integración) ─────────────────────────
|
||||
|
||||
describe('Migración Dexie v4 — groupId como UUID válido', () => {
|
||||
beforeEach(async () => {
|
||||
await db.open()
|
||||
await db.transaction('rw', [db.processes, db.groups], async () => {
|
||||
await db.processes.clear()
|
||||
await db.groups.clear()
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await db.close()
|
||||
})
|
||||
|
||||
it('proceso con groupId persiste y es queryable por el índice groupId', async () => {
|
||||
const group: ProcessGroup = {
|
||||
id: 'group-abc-123',
|
||||
name: 'Grupo Test',
|
||||
createdAt: 1000,
|
||||
updatedAt: 2000,
|
||||
}
|
||||
await db.groups.put(group)
|
||||
|
||||
const proc: Process = makeProcess('p3', {
|
||||
groupId: 'group-abc-123',
|
||||
tags: ['test'],
|
||||
})
|
||||
await db.processes.put(proc)
|
||||
|
||||
// El campo persiste
|
||||
const retrieved = await db.processes.get('p3')
|
||||
expect(retrieved!.groupId).toBe('group-abc-123')
|
||||
expect(retrieved!.tags).toEqual(['test'])
|
||||
|
||||
// El índice funciona para query por grupo
|
||||
const byGroup = await db.processes.where('groupId').equals('group-abc-123').toArray()
|
||||
expect(byGroup).toHaveLength(1)
|
||||
expect(byGroup[0].id).toBe('p3')
|
||||
})
|
||||
|
||||
it('proceso con groupId=null persiste y es recuperable', async () => {
|
||||
const proc: Process = makeProcess('p4', { groupId: null, tags: [] })
|
||||
await db.processes.put(proc)
|
||||
|
||||
const retrieved = await db.processes.get('p4')
|
||||
expect(retrieved).toBeDefined()
|
||||
expect(retrieved!.groupId).toBeNull()
|
||||
|
||||
// Verificar con filter (Dexie no acepta null en .equals())
|
||||
const sinGrupo = await db.processes.filter((p) => p.groupId == null).toArray()
|
||||
expect(sinGrupo.some((p) => p.id === 'p4')).toBe(true)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user