Files
CRM_AGENTES_CARGA/frontend/e2e/FlujoCompleto.MD

9.0 KiB

Reporte de Pruebas E2E — Flujo de Factura

Proyecto: Anexo 76 — Sistema de Control de Operaciones Aduaneras
Herramienta: Playwright
Archivo: frontend/e2e/invoice-flow.spec.ts
Fecha: Abril 2026
Estado: 12/12 pruebas pasando
Tiempo de ejecución: ~4.4 minutos


Resumen

Categoría Pruebas Estado
Prerrequisitos (proveedor, cliente, agente, TC) 4
Pedimento 1
Factura TEM 3
Partidas 2
Actualización final 1
Total 11

Nota: el test de setup de autenticación (auth.setup.ts) suma 1 prueba adicional, totalizando 12 en el runner.


Flujo completo

1. Crear proveedor

Navega a /dashboard/clients_and_providers, abre el formulario de nuevo socio, llena RFC y nombre, selecciona tipo "Proveedor" y guarda. Verifica redirección a la lista y que el nombre aparece en la tabla.

2. Crear cliente

Mismo flujo que el proveedor pero con tipo "Cliente".

3. Crear agente aduanal

Navega a /dashboard/customs_brokers, abre el formulario, llena clave, patente y nombre. Verifica toast de éxito y redirección.

4. Crear tipo de cambio

Navega a /dashboard/general_catalogs/exchange-rate, abre el modal de nuevo tipo de cambio, llena fecha de hoy y valor 17.5, confirma. Verifica toast de éxito.

5. Crear pedimento

Navega a /dashboard/pedimentos/edit/new, llena año (26), selecciona Aduana, Patente, Clave, Tipo de Operación y Régimen via bits-ui Select. Llena número de pedimento. Guarda y verifica redirección a /dashboard/pedimentos.

6. Crear factura de importación TEM

Navega a /dashboard/invoices/edit/new?operation_type=imp&invoice_type=TEM. Llena número de factura con pressSequentially, fecha, y en la pestaña General selecciona proveedor, sold-to, shipped-to, agente aduanal, aduana y tipo de documento. Guarda y verifica toast de éxito. Al finalizar guarda el número de factura en .e2e-shared.json para los tests posteriores.

7. Factura aparece en la lista

Filtra por número de factura en la lista de importación y verifica que la fila es visible.

8. Agregar partida a la factura

Abre la factura desde la lista, navega a la pestaña Partidas, abre el sheet de nueva partida. Selecciona Clase, U.M. y País de Origen (cada uno abre un dialog con tabla). Llena cantidad (10), costo unitario (100), peso neto (5), peso bruto (6) y descripción en español. Hace click en el botón "Crear" del sheet. Guarda la factura completa.

9. Editar factura existente

Lee el número de factura desde .e2e-shared.json, la busca en la lista, la abre en modo edición. En la pestaña General vuelve a seleccionar agente aduanal, aduana y tipo de documento. Guarda y verifica toast de éxito.

10. Editar partida existente

Lee el número desde shared, abre la factura, va a pestaña Partidas. Hace click en el ícono Pencil de la primera fila para abrir el sheet de edición. Modifica cantidad (20) y costo unitario (200). Hace click en "Actualizar" del sheet. Guarda la factura.

11. Actualizar factura — verificación final

Lee el número desde shared, busca la factura en la lista, selecciona la fila, hace click en el botón "Actualizar" del footer (ícono RefreshCw, clase h-8). Verifica el resultado con toast de éxito.


Patrones técnicos establecidos

fillInput — inputs reactivos de Svelte 5

Los inputs de Svelte 5 no responden a page.fill() ni pressSequentially de forma confiable. La solución es usar el native setter del prototipo:

async function fillInput(page: Page, selector: string, value: string) {
    await page.locator(selector).click()
    await page.evaluate(({ sel, val }) => {
        const el = document.querySelector(sel) as HTMLInputElement
        const setter = Object.getOwnPropertyDescriptor(
            window.HTMLInputElement.prototype, 'value'
        )?.set
        setter?.call(el, val)
        el.dispatchEvent(new Event('input', { bubbles: true }))
        el.dispatchEvent(new Event('change', { bubbles: true }))
    }, { sel: selector, val: value })
    await page.waitForTimeout(2000)
}

La excepción es #invoice_number, que sí responde a pressSequentially con delay:

await page.locator('#invoice_number').click()
await page.keyboard.press('Control+A')
await page.locator('#invoice_number').pressSequentially(INVOICE_NUMBER, { delay: 1000 })

bits-ui Select — selects con IDs dinámicos

Los selects de bits-ui generan IDs como bits-s65 que cambian en cada render. La estrategia es seleccionarlos por el atributo data-select-trigger y posición:

const triggers = page.locator('[data-select-trigger]')
await triggers.nth(0).click()  // Aduana
await page.getByRole('option').first().click()

Para selects con IDs estables (facturas) se usa directamente:

await page.locator('#provider_id').click()
await page.getByRole('option').first().click()

Dialogs anidados — clase, U.M., país de origen

Los campos Clase, U.M. y País de Origen abren un dialog de búsqueda encima del sheet. Para evitar que el sheet intercepte los clicks, se scopea al último dialog abierto:

await page.locator('#clase').click()
await page.waitForTimeout(3000)
const claseDialog = page.locator('[data-dialog-content]').last()
await claseDialog.locator('tbody tr').first().click()

Botones dentro del sheet

El botón de guardar partida está dentro del sheet y puede ser interceptado. Se scopea explícitamente:

const sheet = page.locator('[data-slot="sheet-content"]')
await sheet.getByRole('button', { name: /Crear/ }).click()   // nueva partida
await sheet.getByRole('button', { name: /Actualizar/ }).click() // editar partida

Distinguir botones ambiguos por clase CSS

Cuando hay múltiples botones con el mismo texto o ícono, se distinguen por clases CSS únicas:

// Botón Actualizar del footer (tiene h-8, border, RefreshCw)
await page.locator('button.h-8:has([class*="lucide-refresh"])').click()

Compartir estado entre tests

Playwright corre cada test en un worker separado, por lo que Date.now() se reevalúa. Para compartir el número de factura entre tests se usa un archivo JSON:

// Al final del test 6
saveShared({ INVOICE_NUMBER })

// En tests 7-11
const shared = loadShared()
const invoiceNumber = shared.INVOICE_NUMBER || INVOICE_NUMBER

El archivo se guarda en frontend/e2e/.e2e-shared.json.


Selectores de referencia

Campo Selector Tipo
RFC #rfc input normal
Nombre #name input normal
Tipo de socio #type bits-ui Select
Año pedimento #year input normal
Número pedimento #pedimento_number input normal
Aduana pedimento [data-select-trigger] nth(0) bits-ui Select
Patente pedimento [data-select-trigger] nth(1) bits-ui Select
Clave pedimento [data-select-trigger] nth(2) bits-ui Select
Número factura #invoice_number input (pressSequentially)
Fecha factura #invoice_date date input
Proveedor #provider_id bits-ui Select
Sold-to #sold_to_id bits-ui Select
Shipped-to #shipped_to_id bits-ui Select
Agente aduanal #customs_broker_id bits-ui Select
Aduana factura #aduana bits-ui Select
Tipo documento #document_type bits-ui Select
Clase partida #clase input readonly → dialog
U.M. #um input readonly → dialog
País origen #pais_origen input readonly → dialog
Cantidad #cantidad input number
Costo unitario #costo_unitario input number
Peso neto #peso_neto input number
Peso bruto #peso_bruto input number
Descripción ES #desc_espanol textarea
Filtro número #filter-invoice-number input normal

Comandos

# Flujo completo
pnpm test:e2e --grep "Flujo completo"

# Test individual
pnpm test:e2e --grep "5. crear pedimento"
pnpm test:e2e --grep "8. agregar partida"

# Modo visual para debug
pnpm test:e2e --grep "Flujo completo" --headed --timeout 120000

Estructura de archivos

frontend/e2e/
├── .auth/
│   └── user.json                        sesion de autenticacion
├── .e2e-shared.json                     estado compartido entre tests (generado)
├── auth.setup.ts                        1 test  — login y guardado de sesion
├── invoice-flow.spec.ts                11 tests — flujo completo de factura
├── full-flow.spec.ts                    4 tests
├── login.spec.ts                        3 tests
├── navigation.spec.ts                  10 tests
└── modules.spec.ts                     10 tests

Conteo total actualizado

Suite Pruebas
auth.setup.ts 1
invoice-flow.spec.ts 11
full-flow.spec.ts 4
login.spec.ts 3
navigation.spec.ts 10
modules.spec.ts 10
Total Playwright 39

Anexo 76 — Reporte de Pruebas E2E v4.0 — invoice-flow — Abril 2026