83 lines
4.5 KiB
TypeScript
83 lines
4.5 KiB
TypeScript
/**
|
|
* Setup de autenticación para tests E2E de Playwright.
|
|
*
|
|
* El flujo de login de Anexo76 pasa por Workspace (workspace.aduanasoft.com):
|
|
* 1. Navegar a /login → 303 redirect al formulario de Workspace
|
|
* 2. Llenar el form de Workspace con el usuario de prueba (creado en globalSetup)
|
|
* 3. Workspace/Keycloak redirige de vuelta a /auth/callback → /dashboard
|
|
* 4. Guardar storageState para todos los tests dependientes
|
|
*
|
|
* El usuario de prueba es creado y eliminado por globalSetup / globalTeardown.
|
|
* Patrón idéntico al de aduanasoft-hub.
|
|
*/
|
|
import { test as setup, expect } from '@playwright/test'
|
|
import { mkdirSync } from 'node:fs'
|
|
import path from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
const authFile = path.join(__dirname, '.auth/user.json')
|
|
|
|
setup('autenticacion', async ({ page }) => {
|
|
const username = process.env.E2E_TEST_USER ?? ''
|
|
const password = process.env.E2E_TEST_PASSWORD ?? ''
|
|
|
|
if (!username) throw new Error('E2E_TEST_USER no está configurado')
|
|
if (!password) throw new Error('E2E_TEST_PASSWORD no está configurado')
|
|
|
|
// ── 1. Navegar a /login — Workspace intercepta y muestra su formulario ──
|
|
await page.goto('/login')
|
|
|
|
// ── 2. Llenar el formulario de Workspace (mismos selectores que hub/login.spec.ts) ──
|
|
await page.getByRole('textbox', { name: /usuario o email/i }).fill(username)
|
|
await page.getByLabel(/contraseña/i).fill(password)
|
|
await page.getByRole('button', { name: /continuar/i }).click()
|
|
|
|
// ── 3. Si Workspace muestra el app-launcher (usuario con múltiples apps),
|
|
// elegir anexo76-dev — la app del launcher cuya URL apunta al frontend bajo prueba.
|
|
// Cuando hay match directo de dominio, Workspace salta el launcher y este paso no ejecuta.
|
|
try {
|
|
await page.waitForURL(/\/(app-launcher|dashboard|auth\/callback)/, { timeout: 30_000 })
|
|
} catch (e) {
|
|
// Si seguimos en /login de Workspace, las credenciales fueron rechazadas o el form no aceptó.
|
|
// Imprimir diagnóstico antes de fallar: URL actual + posibles mensajes de error visibles.
|
|
const currentUrl = page.url()
|
|
const errorMessages = await page.locator('.text-destructive, [role="alert"], .error, .invalid-feedback')
|
|
.allTextContents()
|
|
.catch(() => [] as string[])
|
|
const visibleText = await page.locator('body').innerText().catch(() => '')
|
|
console.log(`[auth.setup][DIAG] URL: ${currentUrl}`)
|
|
console.log(`[auth.setup][DIAG] Mensajes de error: ${JSON.stringify(errorMessages)}`)
|
|
console.log(`[auth.setup][DIAG] Body (primeros 800 chars): ${visibleText.slice(0, 800)}`)
|
|
throw e
|
|
}
|
|
if (/\/app-launcher/.test(page.url())) {
|
|
await page.getByRole('button', { name: /^anexo76-dev/i }).click()
|
|
}
|
|
|
|
// ── 4. Esperar redirect SSO con active_system=fixed_asset ────────────────
|
|
await expect(page).toHaveURL(/active_system=fixed_asset/, { timeout: 30_000 })
|
|
|
|
// ── 5. ExchangeRateGuard abre un dialog modal en cada carga del dashboard
|
|
// si no existe un tipo de cambio para hoy. El guard espera a que
|
|
// companyStore.activeCompany?.id esté disponible (API async) antes de
|
|
// consultar la DB y abrir el dialog. Esperar networkidle para que ese
|
|
// flujo se complete antes de buscar el dialog.
|
|
await page.waitForLoadState('networkidle', { timeout: 30_000 }).catch(() => {})
|
|
const tcDialog = page.getByRole('dialog', { name: /Nuevo Tipo de Cambio/i })
|
|
if (await tcDialog.isVisible({ timeout: 10_000 }).catch(() => false)) {
|
|
const valueInput = tcDialog.getByRole('spinbutton', { name: /Tipo de Cambio/i })
|
|
await tcDialog.getByRole('button', { name: /Consultar DOF/i }).click()
|
|
// El backend consulta el DOF y llena el campo. Esperar a que tenga un valor.
|
|
await expect(valueInput).not.toHaveValue('', { timeout: 15_000 })
|
|
// "Ok" abre un AlertDialog de confirmación; el TC se crea hasta "Confirmar".
|
|
await tcDialog.getByRole('button', { name: /^Ok$/ }).click()
|
|
await page.getByRole('button', { name: /^Confirmar$/ }).click()
|
|
await tcDialog.waitFor({ state: 'hidden', timeout: 10_000 })
|
|
}
|
|
|
|
// ── 6. Guardar estado para los tests dependientes ─────────────────────────
|
|
mkdirSync(path.dirname(authFile), { recursive: true })
|
|
await page.context().storageState({ path: authFile })
|
|
})
|