4e90f6f7b2
- UsersView: tabla nativa con busqueda, paginacion (15/page), iniciales - UsersView: eliminada dependencia ag-grid (mantenida en bundle por otros modulos) - DashboardView: QA metrics con desglose auto/parcial/manual - DashboardView: seccion expandible con planes QA detallados - qa-analyzer: fix field name automatizable - ToDo: K-09 eliminada
89 lines
2.9 KiB
TypeScript
89 lines
2.9 KiB
TypeScript
import { callAI } from '@/services/ai'
|
|
import db from '@/services/db'
|
|
|
|
export interface QATestCase {
|
|
type: string
|
|
description: string
|
|
automatizable: string
|
|
tool: string
|
|
}
|
|
|
|
|
|
export interface HUQAPlan {
|
|
huTitle: string
|
|
huId: string
|
|
acceptanceCriteria: string[]
|
|
testCases: QATestCase[]
|
|
manualSteps: string[]
|
|
criticalTests: string[]
|
|
}
|
|
|
|
const QA_PROMPT = `Eres un ingeniero de QA experto. Generá un plan de pruebas detallado para una Historia de Usuario.
|
|
|
|
Formato de respuesta JSON:
|
|
{
|
|
"acceptanceCriteria": ["Criterio 1", "Criterio 2"],
|
|
"testCases": [
|
|
{
|
|
"type": "Tipo de prueba",
|
|
"description": "Descripción de lo que verifica",
|
|
"automatizable": "SÍ|PARCIAL|MANUAL",
|
|
"tool": "Playwright|API Testing|Manual"
|
|
}
|
|
],
|
|
"manualSteps": ["Paso manual 1"],
|
|
"criticalTests": ["Prueba crítica manual"]
|
|
}
|
|
|
|
Reglas:
|
|
- SÍ = completamente automatizable
|
|
- PARCIAL = requiere validación manual complementaria
|
|
- MANUAL = requiere intervención humana
|
|
- Incluí al menos 3-5 casos de prueba
|
|
- Marcá como crítica pruebas con datos reales, ERPs externos, o cálculos financieros`
|
|
|
|
export async function generateQAPlan(huTitle: string, huDescription: string, acceptanceCriteria: string): Promise<HUQAPlan> {
|
|
const userContent = `HU: ${huTitle}\nDescripción: ${huDescription}\nCriterios: ${acceptanceCriteria}`
|
|
const content = await callAI(
|
|
[{ role: 'system', content: QA_PROMPT }, { role: 'user', content: userContent }],
|
|
0.3, 4096,
|
|
)
|
|
try {
|
|
const jsonStr = extractJSON(content)
|
|
const result: Omit<HUQAPlan, 'huTitle' | 'huId'> = JSON.parse(jsonStr)
|
|
return { huTitle, huId: '', ...result }
|
|
} catch (e) {
|
|
console.error('[Alpha] Failed to parse QA plan. Raw:', content)
|
|
throw new Error(`Error generando plan QA para: ${huTitle}`)
|
|
}
|
|
}
|
|
|
|
export async function saveQAPlan(projectId: number, huId: string, huTitle: string, plan: HUQAPlan) {
|
|
await db.table('qa_plans').put({
|
|
id: `${projectId}-${huId}`, projectId, huId, huTitle,
|
|
plan: JSON.stringify(plan),
|
|
createdAt: new Date().toISOString(),
|
|
})
|
|
}
|
|
|
|
export async function getQAPlans(projectId: number) {
|
|
return db.table('qa_plans').where('projectId').equals(projectId).toArray()
|
|
}
|
|
|
|
export async function generateAndSavePlan(projectId: number, huId: string, huTitle: string, huDescription: string, acceptanceCriteria: string): Promise<HUQAPlan> {
|
|
const plan = await generateQAPlan(huTitle, huDescription, acceptanceCriteria)
|
|
plan.huId = huId
|
|
await saveQAPlan(projectId, huId, huTitle, plan)
|
|
return plan
|
|
}
|
|
|
|
function extractJSON(text: string): string {
|
|
try { JSON.parse(text); return text } catch {}
|
|
const block = text.match(/```(?:json)?\s*([\s\S]*?)```/)
|
|
if (block) { try { JSON.parse(block[1].trim()); return block[1].trim() } catch {} }
|
|
const first = text.indexOf('{')
|
|
const last = text.lastIndexOf('}')
|
|
if (first !== -1 && last > first) { const c = text.slice(first, last + 1); try { JSON.parse(c); return c } catch {} }
|
|
return text
|
|
}
|