Files
agents_and_robots/e2e/fixtures/persistent-context.ts
T
egutierrez c370c189d2 feat: extraer dismissAllToasts a element-utils.ts
Mueve la logica de cierre de toasts a un modulo compartido (element-utils.ts) para evitar duplicacion. persistent-context.ts importa dismissAllToasts desde ahi y la invoca despues de verificar el sidebar. Se mejora tambien la deteccion del sidebar usando multiples locators alternativos (mx_RoomList, mx_LeftPanel_roomListContainer, mx_RoomTile) para mayor compatibilidad con distintas versiones de Element Web.
2026-03-08 17:33:29 +00:00

140 lines
4.6 KiB
TypeScript

import { test as base, chromium, BrowserContext, Page } from "@playwright/test";
import * as path from "path";
import { dismissAllToasts } from "./element-utils";
/**
* Custom test fixture que usa un persistent browser context compartido.
*
* A diferencia de storageState (que solo guarda cookies + localStorage),
* un persistent context preserva IndexedDB — donde Element Web guarda
* las crypto keys de E2EE. Sin esto, cada test ve "Missing session data".
*
* El contexto es worker-scoped: se crea una vez y se reutiliza en todos
* los tests del worker. Esto evita el dialogo "Element is open in another
* window" que aparece cuando se abre/cierra el contexto repetidamente.
*/
const USER_DATA_DIR = path.resolve(__dirname, "..", ".auth", "chrome-profile");
export const test = base.extend<
{ page: Page },
{ persistentContext: BrowserContext }
>({
// Worker-scoped: un solo persistent context para todos los tests
persistentContext: [
async ({}, use) => {
const context = await chromium.launchPersistentContext(USER_DATA_DIR, {
headless: true,
baseURL: process.env.ELEMENT_URL || "http://localhost:8080",
viewport: { width: 1280, height: 720 },
});
await use(context);
await context.close();
},
{ scope: "worker" },
],
// Cada test obtiene una pagina del contexto compartido
page: async ({ persistentContext }, use) => {
// Cerrar paginas sobrantes de tests anteriores
for (const p of persistentContext.pages()) {
await p.close();
}
const page = await persistentContext.newPage();
await use(page);
// Cerrar la pagina al finalizar el test
await page.close();
},
});
/**
* Maneja dialogos y toasts de Element que bloquean la carga:
* - "Element is open in another window" → click Continue
* - "Missing session data" → error informativo
* - "Notifications" toast → click Dismiss
* - "Threads Activity Centre" toast → click OK
* - Cualquier otro toast → intentar cerrarlo
*
* Llamar despues de page.goto("/")
*/
export async function handleElementDialogs(page: Page) {
// 1. "Element is open in another window" — click Continue
const continueBtn = page.getByRole("button", { name: "Continue" });
const hasContinue = await continueBtn
.waitFor({ state: "visible", timeout: 5_000 })
.then(() => true)
.catch(() => false);
if (hasContinue) {
console.log("[element] 'Element is open in another window' — clicking Continue");
await continueBtn.click();
}
// 2. "Missing session data" — fatal
const missingData = page.locator('text="Missing session data"');
const hasMissing = await missingData
.waitFor({ state: "visible", timeout: 3_000 })
.then(() => true)
.catch(() => false);
if (hasMissing) {
throw new Error(
"Missing session data: crypto keys perdidas. " +
"Borrar .auth/ y re-ejecutar: rm -rf e2e/.auth && ./dev-scripts/e2e/run.sh"
);
}
// 3. Esperar a que la sidebar aparezca (sesion cargada)
// Usamos multiples locators porque Element Web cambia la estructura entre versiones
console.log("[element] Esperando sidebar con rooms...");
const sidebarLocators = [
page.locator('[role="tree"][aria-label="Rooms"]'),
page.locator(".mx_RoomList"),
page.locator(".mx_LeftPanel_roomListContainer"),
page.locator('[role="treeitem"]'),
// Rooms visibles como items en el sidebar
page.locator(".mx_RoomTile"),
];
let sidebarFound = false;
for (const locator of sidebarLocators) {
const visible = await locator.first()
.waitFor({ state: "visible", timeout: 30_000 })
.then(() => true)
.catch(() => false);
if (visible) {
console.log("[element] Sidebar visible");
sidebarFound = true;
break;
}
}
if (!sidebarFound) {
// Verificar si estamos en la pagina de login
const onLoginPage = await page.locator('text="Welcome to Element!"').isVisible().catch(() => false)
|| await page.getByRole("link", { name: "Sign in" }).isVisible().catch(() => false);
if (onLoginPage) {
throw new Error(
"Sesion no cargada: se muestra la pagina de login. " +
"Borrar .auth/ y re-ejecutar: rm -rf e2e/.auth && ./dev-scripts/e2e/run.sh"
);
}
await page.screenshot({
path: "test-results/ERROR-no-sidebar.png",
fullPage: true,
});
throw new Error("Sidebar de rooms no encontrado despues de 30s");
}
// 4. Cerrar TODOS los toasts que bloquean interacciones
await dismissAllToasts(page);
}
export { dismissAllToasts } from "./element-utils";
export { expect } from "@playwright/test";