Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Giofelix/Proyecto-automatizacion-Empresa/llms.txt
Use this file to discover all available pages before exploring further.
LoginPage encapsula el flujo completo de autenticación del sistema municipal de impuestos. El formulario Angular utiliza un diseño de dos pasos — primero se valida el nombre de usuario (campo #txtU → botón Siguiente) y, sólo si el usuario existe, aparece el campo de contraseña (#txtP → botón Iniciar Sesión). Para absorber inestabilidades de red o sesiones colgadas del pipeline anterior, login() reintenta el paso 1 hasta 3 veces y guarda capturas de pantalla de diagnóstico en playwright/.auth/ ante cualquier fallo.
Importación
LoginPage es consumida desde los archivos de setup/teardown que viven en el directorio playwright/. El import usa una ruta relativa hacia la raíz del proyecto:
La ruta
../pages/login/login.page (sin extensión .js) es la forma que usa el proyecto internamente. Si escribes un script personalizado en la raíz del proyecto, la ruta correcta sería ./pages/login/login.page.Constructor
El constructor recibe la instanciapage de Playwright y registra todos los locators utilizados por los métodos de la clase.
| Propiedad | Locator | Descripción |
|---|---|---|
usernameInput | page.locator('#txtU') | Campo de nombre de usuario (paso 1) |
nextButton | page.getByRole('button', { name: /siguiente|next/i }) | Botón que avanza al paso de contraseña |
passwordInput | page.locator('#txtP') | Campo de contraseña (paso 2, aparece tras Siguiente) |
loginButton | page.getByRole('button', { name: /iniciar sesión|sign in|log in/i }) | Botón que envía las credenciales al servidor |
logoutButton | page.getByRole('menuitem', { name: /cerrar sesión|sign out|log out/i }) | Ítem de menú para cerrar sesión |
userMenuButton | page.locator('button.mat-menu-trigger.btn-barra') | Botón de la barra superior que abre el menú de usuario |
Métodos
navegar()
Navega a la URL base de la aplicación y espera a que Angular haya terminado de inicializar los controles del formulario de login.
- Llama a
page.goto(process.env.BASE_URL, { waitUntil: 'domcontentloaded', timeout: 120000 }). - Espera con
page.waitForFunctiona que#txtUtenga la claseng-pristine, lo que indica que Angular ha completado su ciclo de detección de cambios y el formulario está listo para recibir input.
BASE_URL debe definirse en el archivo .env del proyecto o como variable de entorno del runner de CI. La página no se puede usar antes de que esta variable esté disponible.login(usuario, password)
Realiza el flujo completo de autenticación de dos pasos con lógica de reintentos automáticos.
Nombre de usuario de la aplicación (normalmente leído de
process.env.USER_GENERIC).Contraseña del usuario (normalmente leída de
process.env.PASSWORD_UNIVERSAL).Paso 1 — Validación de usuario (con reintentos)
El método intenta hasta 3 veces (
MAX_INTENTOS = 3) la siguiente secuencia:- Hace
click()sobre#txtU, llama afill('')para limpiar, y escribe el usuario conpage.keyboard.type(usuario, { delay: 80 }). El despacho a nivel depage.keyboarden lugar delocator.pressSequentiallyes necesario para que Angular dispare el eventobluren modo headless sobre Linux. - Presiona
Tabpara ejecutar el blur y el ciclo de detección de cambios de Angular que habilita el botón Siguiente. - Hace
click()sobrenextButton. - Espera que
passwordInputsea visible (timeout de 20 s por intento). - Si el intento falla: guarda un screenshot de diagnóstico, espera 3 s, recarga la página y vuelve a esperar
ng-pristineantes del siguiente intento. - Tras 3 fallos consecutivos lanza un error descriptivo mencionando la posible sesión colgada.
Paso 2 — Autenticación con contraseña
- Llama a
passwordInput.fill(password)y luegologinButton.click().
Paso 3 — Espera de redirección con manejo de diálogos intermedios
Entra en un loop que compite con cuatro eventos simultáneos (timeout global de 120 s):
ok—page.waitForURL('**/modulos**')→ login exitoso, rompe el loop.error—mat-dialog-containercon texto de error de credenciales (/código|no fue posible|credencial|contraseña incorrecta/i) → lanza error con el texto del diálogo.confirm— diálogo de sesión activa previa sin texto de error → acepta el botónAceptar/Continuar/OK/Síy reinicia la espera.swal— popup SweetAlert2 (.swal2-popup) → si contiene texto de error cambia aerror; si no, cierra con.swal2-confirmy reinicia.
logout()
Abre el menú de usuario, hace clic en el ítem de cerrar sesión y espera a que la aplicación regrese a la pantalla de login.
- Hace
click()sobreuserMenuButton(con timeout de 10 s) y espera 500 ms para la animación del menú. - Hace
click()sobrelogoutButton. - Espera que
usernameInput(#txtU) vuelva a ser visible, indicando el retorno a la página de login.
logout() está diseñado para tolerar fallos sin romper el pipeline. Si cualquier paso lanza una excepción, el método la captura, emite un console.warn y retorna normalmente. Esto evita que un timeout de red en el teardown marque toda la suite como fallida.Ejemplo de uso
LoginPage se utiliza exclusivamente en global-setup.js (para autenticarse antes de la suite) y en global-teardown.js (para liberar la sesión del servidor al finalizar).
No uses
LoginPage dentro de tests individuales. Los tests consumen el estado de autenticación guardado mediante la fixture paginaAutenticada, que restaura el storageState generado por global-setup.js. Esto evita un ciclo de login/logout completo por cada test, reduciendo drásticamente el tiempo de ejecución de la suite.Screenshots de diagnóstico
Cuandologin() necesita registrar un fallo, llama al método interno _guardarScreenshotDiagnostico(nombre).
Los archivos se guardan en:
| Nombre de archivo | Cuándo se genera |
|---|---|
login-intento-1-fallido.png | El intento 1 de validación de usuario agotó su timeout |
login-intento-2-fallido.png | El intento 2 de validación de usuario agotó su timeout |
login-intento-3-fallido.png | El intento 3 (último) agotó su timeout |
login-error-credenciales.png | El servidor rechazó las credenciales |
login-timeout-modulos.png | El redirect a /modulos no ocurrió en 120 s |