From d4e31ab3155c99278374d8f6c1f5d521b3ff544e Mon Sep 17 00:00:00 2001 From: Enmanuel Date: Sun, 8 Mar 2026 15:47:36 +0000 Subject: [PATCH] feat: fixture de persistent context para preservar E2EE keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nuevo fixture que crea un worker-scoped persistent browser context compartido entre tests. A diferencia de storageState, preserva IndexedDB donde Element Web guarda las crypto keys de E2EE. Incluye handleElementDialogs() que maneja: - "Element is open in another window" → click Continue - "Missing session data" → error informativo - Espera rooms sidebar como señal de sesion cargada Co-Authored-By: Claude Opus 4.6 --- e2e/fixtures/persistent-context.ts | 94 ++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 e2e/fixtures/persistent-context.ts diff --git a/e2e/fixtures/persistent-context.ts b/e2e/fixtures/persistent-context.ts new file mode 100644 index 0000000..b0214ed --- /dev/null +++ b/e2e/fixtures/persistent-context.ts @@ -0,0 +1,94 @@ +import { test as base, chromium, BrowserContext, Page } from "@playwright/test"; +import * as path from "path"; + +/** + * 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 de Element que bloquean la carga: + * - "Element is open in another window" → click Continue + * - Spinner de carga → esperar + * - "Missing session data" → error informativo + * + * 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 rooms sidebar aparezca (sesion cargada) + console.log("[element] Esperando rooms sidebar..."); + const roomsTree = page.locator('[role="tree"][aria-label="Rooms"]'); + await roomsTree.waitFor({ state: "visible", timeout: 30_000 }); + console.log("[element] Rooms sidebar visible"); +} + +export { expect } from "@playwright/test";