diff --git a/prisma/test-phase4-ui.js b/prisma/test-phase4-ui.js index abda6cb..e2d535b 100644 --- a/prisma/test-phase4-ui.js +++ b/prisma/test-phase4-ui.js @@ -69,9 +69,10 @@ async function cleanupDb() { // Clean sales results created by test scripts await tx.salesResult.deleteMany({ where: { - idempotencyKey: { - startsWith: 'test-key-p4' - } + OR: [ + { idempotencyKey: { startsWith: 'test-key-p4' } }, + { idempotencyKey: { startsWith: 'key-' } } + ] } }); // Clean audit logs associated @@ -92,8 +93,10 @@ async function runTests() { // 2. Start Next.js production server on port 3012 console.log(`Starting Next.js production server on port ${PORT}...`); + const testEnv = { ...process.env, PORT: String(PORT), IS_E2E_TEST: 'true', N8N_WEBHOOK_SECRET: 'local_shared_signature_to_verify_n8n_callbacks' }; + delete testEnv.N8N_WEBHOOK_URL; // Force direct database save mode for E2E tests nextProcess = spawn('node', ['node_modules/next/dist/bin/next', 'start', '--port', String(PORT)], { - env: { ...process.env, PORT: String(PORT) } + env: testEnv }); nextProcess.stdout.on('data', (data) => { @@ -181,6 +184,7 @@ async function runTests() { await page.waitForSelector('#btn-create-plan'); // Navigate to import page + await page.waitForSelector('#nav-import-sales'); await page.click('#nav-import-sales'); await page.waitForSelector('#btn-download-template'); await page.screenshot({ path: path.join(SCREENSHOT_DIR, '02_admin_import_view.png') }); @@ -214,7 +218,7 @@ async function runTests() { assert(validationErrorCount === 4, "Atomic validation catches all 4 invalid rows in the sheet"); const errorTexts = await page.evaluate(() => { - return Array.from(document.querySelectorAll('.cellMsg')).map(el => el.textContent); + return Array.from(document.querySelectorAll('tbody tr td:last-child')).map(el => el.textContent); }); assert(errorTexts.some(t => t.includes("colaborador_inexistente")), "Rendered 'colaborador_inexistente' username validation error"); assert(errorTexts.some(t => t.includes("2026/06")), "Rendered invalid Period format validation error"); diff --git a/src/app/api/sales/import/route.ts b/src/app/api/sales/import/route.ts index 30aff13..9dd951a 100644 --- a/src/app/api/sales/import/route.ts +++ b/src/app/api/sales/import/route.ts @@ -228,7 +228,7 @@ export const POST = withAuth(async (req, { session, prisma }) => { } // 4. Dispatch to n8n or direct save - const useN8n = process.env.N8N_WEBHOOK_URL && !req.nextUrl.searchParams.has('direct'); + const useN8n = process.env.N8N_WEBHOOK_URL && process.env.NODE_ENV !== 'test' && process.env.IS_E2E_TEST !== 'true' && !req.nextUrl.searchParams.has('direct'); if (useN8n) { const response = await fetch(process.env.N8N_WEBHOOK_URL!, { diff --git a/src/app/sales/import/page.tsx b/src/app/sales/import/page.tsx index b5bd8b7..0c551e9 100644 --- a/src/app/sales/import/page.tsx +++ b/src/app/sales/import/page.tsx @@ -32,10 +32,14 @@ const TRANSLATIONS: Record = { IMPORT_ACCEPTED: "La importación ha sido aceptada y se está procesando mediante n8n en segundo plano." }; -const translate = (code: string, metadata: any = {}) => { +const translate = (code: string, metadata: any = {}, value?: any) => { let template = TRANSLATIONS[code] || code; - for (const key of Object.keys(metadata)) { - template = template.replace(`{${key}}`, String(metadata[key])); + const merged = { ...metadata }; + if (value !== undefined) { + merged.value = value; + } + for (const key of Object.keys(merged)) { + template = template.replace(`{${key}}`, String(merged[key])); } return template; }; @@ -314,7 +318,7 @@ export default function SalesImportPage() { Fila {err.row} {err.column} {String(err.value || '')} - {translate(err.code, err.metadata)} + {translate(err.code, err.metadata, err.value)} ))}