d4e31ab315
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 <noreply@anthropic.com>
95 lines
3.1 KiB
TypeScript
95 lines
3.1 KiB
TypeScript
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";
|