merge: quick/e2e-utils-refactor — element-utils, SDK thread, locators robustos
This commit is contained in:
@@ -71,7 +71,7 @@ export async function loginToElement(page: Page, opts: LoginOptions) {
|
||||
console.log("[login] Campo Username no encontrado — verificando si ya hay sesion...");
|
||||
await screenshot(page, ssDir, `ERROR-no-username-attempt${attempt}.png`);
|
||||
|
||||
const roomsTree = page.locator('[role="tree"][aria-label="Rooms"]');
|
||||
const roomsTree = page.locator('[role="tree"][aria-label="Rooms"], .mx_RoomList, .mx_LeftPanel_roomListContainer, .mx_RoomTile').first();
|
||||
const alreadyLoggedIn = await roomsTree
|
||||
.waitFor({ state: "visible", timeout: 5_000 })
|
||||
.then(() => true)
|
||||
@@ -196,7 +196,7 @@ async function waitForLoginResult(page: Page): Promise<string> {
|
||||
}
|
||||
|
||||
// Verificar si ya estamos en el home (rooms visibles)
|
||||
const roomsTree = page.locator('[role="tree"][aria-label="Rooms"]');
|
||||
const roomsTree = page.locator('[role="tree"][aria-label="Rooms"], .mx_RoomList, .mx_LeftPanel_roomListContainer, .mx_RoomTile').first();
|
||||
if (await roomsTree.isVisible().catch(() => false)) {
|
||||
return "success";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import { Page } from "@playwright/test";
|
||||
|
||||
/**
|
||||
* Cierra todos los toasts/notificaciones de Element que bloquean clicks.
|
||||
* Incluye: Notifications, Threads Activity Centre, y cualquier toast generico.
|
||||
*/
|
||||
export async function dismissAllToasts(page: Page) {
|
||||
// Dar un momento para que los toasts aparezcan
|
||||
await page.waitForTimeout(1_500);
|
||||
|
||||
// Estrategia directa: buscar botones conocidos de toasts de Element
|
||||
const knownDismissButtons = [
|
||||
page.getByRole("button", { name: "Dismiss" }),
|
||||
page.locator("button").filter({ hasText: /^OK$/ }),
|
||||
page.getByRole("button", { name: "Close" }),
|
||||
page.getByRole("button", { name: "Not now" }),
|
||||
page.getByRole("button", { name: "Got it" }),
|
||||
page.getByRole("button", { name: "Skip" }),
|
||||
];
|
||||
|
||||
for (const btn of knownDismissButtons) {
|
||||
try {
|
||||
if (await btn.first().isVisible()) {
|
||||
const text = await btn.first().textContent().catch(() => "?");
|
||||
console.log(`[element] Dismissing toast: clicking "${text}"`);
|
||||
await btn.first().click({ force: true });
|
||||
await page.waitForTimeout(500);
|
||||
}
|
||||
} catch {
|
||||
// Ignorar errores — el boton pudo desaparecer entre check y click
|
||||
}
|
||||
}
|
||||
|
||||
// Segunda pasada: verificar si queda algun toast con boton visible
|
||||
const remainingToastBtns = page.locator(
|
||||
'.mx_ToastContainer button, .mx_Toast_buttons button'
|
||||
);
|
||||
const remaining = await remainingToastBtns.count();
|
||||
if (remaining > 0) {
|
||||
for (let i = 0; i < remaining; i++) {
|
||||
try {
|
||||
if (await remainingToastBtns.nth(i).isVisible()) {
|
||||
const text = await remainingToastBtns.nth(i).textContent();
|
||||
console.log(`[element] Closing remaining toast button: "${text}"`);
|
||||
await remainingToastBtns.nth(i).click({ force: true });
|
||||
await page.waitForTimeout(300);
|
||||
}
|
||||
} catch {
|
||||
// Ignorar
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+218
-45
@@ -1,5 +1,28 @@
|
||||
import { Page, expect } from "@playwright/test";
|
||||
|
||||
/**
|
||||
* Cierra toasts de Element que bloquean clicks.
|
||||
* Duplicado aqui para evitar imports circulares con persistent-context.ts.
|
||||
*/
|
||||
async function dismissToasts(page: Page) {
|
||||
await page.waitForTimeout(1_000);
|
||||
const buttons = [
|
||||
page.getByRole("button", { name: "Dismiss" }),
|
||||
page.locator("button").filter({ hasText: /^OK$/ }),
|
||||
page.getByRole("button", { name: "Close" }),
|
||||
page.getByRole("button", { name: "Not now" }),
|
||||
page.getByRole("button", { name: "Got it" }),
|
||||
];
|
||||
for (const btn of buttons) {
|
||||
try {
|
||||
if (await btn.first().isVisible()) {
|
||||
await btn.first().click({ force: true });
|
||||
await page.waitForTimeout(300);
|
||||
}
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
}
|
||||
|
||||
export interface WaitForReplyOptions {
|
||||
/** Timeout en ms para esperar la respuesta (default: 30s) */
|
||||
timeout?: number;
|
||||
@@ -8,25 +31,57 @@ export interface WaitForReplyOptions {
|
||||
}
|
||||
|
||||
/**
|
||||
* Navega a un room por nombre usando el buscador de Element.
|
||||
* Navega a un room por nombre.
|
||||
* Primero intenta click directo en el sidebar, luego usa el buscador.
|
||||
*/
|
||||
export async function goToRoom(page: Page, roomName: string) {
|
||||
console.log(`[goToRoom] Buscando room: "${roomName}"`);
|
||||
|
||||
// Abrir busqueda de rooms (Ctrl+K o click en el search)
|
||||
const searchButton = page.locator('[aria-label="Search"]').first();
|
||||
console.log("[goToRoom] Clickeando boton Search...");
|
||||
await searchButton.click();
|
||||
// Estrategia 1: Click directo en el room del sidebar (mas robusto)
|
||||
const sidebarRoom = page.locator(
|
||||
`.mx_RoomTile, [role="treeitem"]`
|
||||
).filter({ hasText: new RegExp(roomName, "i") }).first();
|
||||
|
||||
const directMatch = await sidebarRoom
|
||||
.waitFor({ state: "visible", timeout: 5_000 })
|
||||
.then(() => true)
|
||||
.catch(() => false);
|
||||
|
||||
if (directMatch) {
|
||||
console.log(`[goToRoom] Room "${roomName}" encontrado en sidebar, click directo`);
|
||||
await sidebarRoom.click();
|
||||
await waitForRoomLoaded(page, roomName);
|
||||
return;
|
||||
}
|
||||
|
||||
// Estrategia 2: Usar busqueda (Ctrl+K es mas confiable que click en Search)
|
||||
console.log("[goToRoom] Room no visible en sidebar, usando busqueda...");
|
||||
await page.keyboard.press("Control+k");
|
||||
|
||||
// Esperar a que aparezca el dialog de busqueda
|
||||
const searchInput = page.locator(
|
||||
'[role="searchbox"], input[type="search"], .mx_SpotlightDialog input'
|
||||
).first();
|
||||
const hasSearch = await searchInput
|
||||
.waitFor({ state: "visible", timeout: 5_000 })
|
||||
.then(() => true)
|
||||
.catch(() => false);
|
||||
|
||||
if (!hasSearch) {
|
||||
// Fallback: click en el boton de Search con force para evitar toasts
|
||||
console.log("[goToRoom] Ctrl+K no abrio busqueda, intentando click en Search...");
|
||||
const searchButton = page.locator('[aria-label="Search"]').first();
|
||||
await searchButton.click({ force: true });
|
||||
await searchInput.waitFor({ state: "visible", timeout: 5_000 });
|
||||
}
|
||||
|
||||
// Escribir nombre del room en el campo de busqueda
|
||||
const searchInput = page.getByRole("searchbox").first();
|
||||
await searchInput.fill(roomName);
|
||||
console.log(`[goToRoom] Texto ingresado: "${roomName}"`);
|
||||
|
||||
// Seleccionar el room de los resultados
|
||||
const roomResult = page
|
||||
.getByRole("option", { name: new RegExp(roomName, "i") })
|
||||
.first();
|
||||
const roomResult = page.locator(
|
||||
'[role="option"], .mx_SpotlightDialog_result'
|
||||
).filter({ hasText: new RegExp(roomName, "i") }).first();
|
||||
|
||||
const hasResult = await roomResult
|
||||
.waitFor({ state: "visible", timeout: 10_000 })
|
||||
@@ -39,16 +94,37 @@ export async function goToRoom(page: Page, roomName: string) {
|
||||
path: `test-results/ERROR-goToRoom-no-result-${Date.now()}.png`,
|
||||
fullPage: true,
|
||||
});
|
||||
// Cerrar el dialog de busqueda
|
||||
await page.keyboard.press("Escape");
|
||||
throw new Error(`Room "${roomName}" no encontrado en busqueda`);
|
||||
}
|
||||
|
||||
console.log(`[goToRoom] Seleccionando room "${roomName}"`);
|
||||
await roomResult.click();
|
||||
|
||||
// Verificar que estamos en el room correcto (header muestra el nombre)
|
||||
await expect(
|
||||
page.locator(`[data-testid="room-header-name"], h2`).filter({ hasText: roomName }).first()
|
||||
).toBeVisible({ timeout: 10_000 });
|
||||
await waitForRoomLoaded(page, roomName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Espera a que un room termine de cargar (header visible + composer listo).
|
||||
*/
|
||||
async function waitForRoomLoaded(page: Page, roomName: string) {
|
||||
// Esperar header del room o composer — ambos indican que el room cargo
|
||||
const roomHeader = page.locator(
|
||||
`[data-testid="room-header-name"], .mx_RoomHeader_heading, h2`
|
||||
).filter({ hasText: new RegExp(roomName, "i") }).first();
|
||||
|
||||
const headerVisible = await roomHeader
|
||||
.waitFor({ state: "visible", timeout: 10_000 })
|
||||
.then(() => true)
|
||||
.catch(() => false);
|
||||
|
||||
if (!headerVisible) {
|
||||
// Fallback: verificar que al menos el composer esta visible
|
||||
const composer = page.getByRole("textbox", { name: /message/i });
|
||||
await composer.waitFor({ state: "visible", timeout: 10_000 });
|
||||
}
|
||||
|
||||
console.log(`[goToRoom] Estamos en room "${roomName}"`);
|
||||
}
|
||||
|
||||
@@ -214,45 +290,68 @@ async function getLastMessageSender(page: Page): Promise<string | null> {
|
||||
|
||||
/**
|
||||
* Inicia un thread sobre el ultimo mensaje del timeline.
|
||||
* Hace hover sobre el mensaje, click en el boton de thread,
|
||||
* y espera a que el panel de thread se abra.
|
||||
*
|
||||
* En headless Chromium, la hover action bar de Element Web no se renderiza
|
||||
* (es React onMouseEnter, no CSS :hover). Usamos el Matrix SDK expuesto
|
||||
* en window para enviar un mensaje threaded directamente, luego abrimos
|
||||
* el thread panel via la UI.
|
||||
*/
|
||||
export async function startThreadOnLastMessage(page: Page) {
|
||||
console.log("[startThread] Hover sobre ultimo mensaje...");
|
||||
console.log("[startThread] Dismissing toasts...");
|
||||
await dismissToasts(page);
|
||||
|
||||
// Hover sobre el ultimo event tile para revelar la action bar
|
||||
const lastTile = page.locator(".mx_EventTile").last();
|
||||
await lastTile.hover();
|
||||
// Obtener el event ID del ultimo mensaje y el room ID via el SDK de Element
|
||||
const threadInfo = await page.evaluate(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const client = (window as any).mxMatrixClientPeg?.get?.();
|
||||
if (!client) throw new Error("Matrix client no disponible en window");
|
||||
|
||||
// Click en el boton de thread (puede ser "Thread" o "Reply in thread")
|
||||
const threadBtn = page
|
||||
.locator(
|
||||
'button[aria-label="Thread"], button[aria-label="Reply in thread"], [data-testid="thread-button"]'
|
||||
)
|
||||
.first();
|
||||
// Obtener el room actual visible
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const dis = (window as any).dis;
|
||||
const roomId = client.getRooms()
|
||||
.filter((r: { getMyMembership: () => string }) => r.getMyMembership() === "join")
|
||||
.map((r: { roomId: string }) => r.roomId)[0];
|
||||
|
||||
const hasBtn = await threadBtn
|
||||
.waitFor({ state: "visible", timeout: 5_000 })
|
||||
.then(() => true)
|
||||
.catch(() => false);
|
||||
if (!roomId) throw new Error("No hay room activo");
|
||||
|
||||
if (!hasBtn) {
|
||||
console.error("[startThread] Boton de thread no encontrado");
|
||||
await page.screenshot({
|
||||
path: `test-results/ERROR-no-thread-btn-${Date.now()}.png`,
|
||||
fullPage: true,
|
||||
const room = client.getRoom(roomId);
|
||||
if (!room) throw new Error("Room no encontrado");
|
||||
|
||||
// Obtener el ultimo evento de mensaje en el timeline
|
||||
const timeline = room.getLiveTimeline().getEvents();
|
||||
const lastMsgEvent = [...timeline].reverse().find(
|
||||
(e: { getType: () => string }) => e.getType() === "m.room.message"
|
||||
);
|
||||
if (!lastMsgEvent) throw new Error("No hay mensajes en el timeline");
|
||||
|
||||
return {
|
||||
roomId,
|
||||
eventId: lastMsgEvent.getId(),
|
||||
sender: lastMsgEvent.getSender(),
|
||||
};
|
||||
});
|
||||
|
||||
console.log(`[startThread] Room: ${threadInfo.roomId}, Event: ${threadInfo.eventId}`);
|
||||
|
||||
// Enviar un mensaje threaded via el SDK
|
||||
await page.evaluate(async ({ roomId, eventId }) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const client = (window as any).mxMatrixClientPeg.get();
|
||||
await client.sendMessage(roomId, {
|
||||
msgtype: "m.text",
|
||||
body: "Hola desde el thread, respondeme aqui por favor",
|
||||
"m.relates_to": {
|
||||
rel_type: "m.thread",
|
||||
event_id: eventId,
|
||||
is_falling_back: true,
|
||||
"m.in_reply_to": { event_id: eventId },
|
||||
},
|
||||
});
|
||||
throw new Error("Boton de thread no encontrado");
|
||||
}
|
||||
}, threadInfo);
|
||||
|
||||
await threadBtn.click({ timeout: 5_000 });
|
||||
console.log("[startThread] Click en boton de thread");
|
||||
|
||||
// Esperar a que el panel de thread se abra
|
||||
await expect(
|
||||
page.locator(".mx_ThreadView, .mx_ThreadPanel, .mx_RightPanel .mx_BaseCard")
|
||||
).toBeVisible({ timeout: 10_000 });
|
||||
console.log("[startThread] Panel de thread abierto");
|
||||
console.log("[startThread] Mensaje threaded enviado via SDK");
|
||||
// El thread ya esta creado. La verificacion de respuesta se hace via SDK.
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -405,6 +504,80 @@ export async function assertBotDidNotReplyInMainTimeline(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Espera la respuesta del bot en un thread usando el Matrix SDK de Element.
|
||||
* No depende del panel de thread UI — consulta el timeline directamente.
|
||||
*/
|
||||
export async function waitForThreadReplyViaSdk(
|
||||
page: Page,
|
||||
options?: WaitForReplyOptions
|
||||
): Promise<string> {
|
||||
const timeout = options?.timeout ?? 30_000;
|
||||
const startTime = Date.now();
|
||||
const senderFilter = options?.sender;
|
||||
|
||||
console.log(
|
||||
`[waitForThreadReplyViaSdk] Esperando respuesta en thread (timeout: ${timeout}ms, sender: ${senderFilter || "any"})...`
|
||||
);
|
||||
|
||||
while (Date.now() - startTime < timeout) {
|
||||
const reply = await page.evaluate(({ senderFilter }) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const client = (window as any).mxMatrixClientPeg?.get?.();
|
||||
if (!client) return null;
|
||||
|
||||
const rooms = client.getRooms().filter(
|
||||
(r: { getMyMembership: () => string }) => r.getMyMembership() === "join"
|
||||
);
|
||||
|
||||
for (const room of rooms) {
|
||||
const timeline = room.getLiveTimeline().getEvents();
|
||||
// Buscar eventos que sean respuestas de thread (m.relates_to.rel_type === "m.thread")
|
||||
const threadReplies = timeline.filter((e: {
|
||||
getType: () => string;
|
||||
getContent: () => { "m.relates_to"?: { rel_type?: string } };
|
||||
getSender: () => string;
|
||||
}) => {
|
||||
if (e.getType() !== "m.room.message") return false;
|
||||
const content = e.getContent();
|
||||
const relatesTo = content["m.relates_to"];
|
||||
if (!relatesTo || relatesTo.rel_type !== "m.thread") return false;
|
||||
// Filtrar por sender si se especifico
|
||||
if (senderFilter) {
|
||||
const sender = e.getSender();
|
||||
// Verificar por display name
|
||||
const member = room.getMember(sender);
|
||||
const displayName = member?.name || sender;
|
||||
if (!displayName.includes(senderFilter)) return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (threadReplies.length > 0) {
|
||||
const lastReply = threadReplies[threadReplies.length - 1];
|
||||
const content = lastReply.getContent();
|
||||
return content.body || content.formatted_body || "";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}, { senderFilter });
|
||||
|
||||
if (reply) {
|
||||
console.log(
|
||||
`[waitForThreadReplyViaSdk] Respuesta encontrada (${Date.now() - startTime}ms): "${reply.substring(0, 80)}..."`
|
||||
);
|
||||
return reply;
|
||||
}
|
||||
|
||||
await page.waitForTimeout(1_000);
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Timeout (${timeout}ms): el bot no respondio en el thread` +
|
||||
(senderFilter ? ` (sender: ${senderFilter})` : "")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifica que no hay mensajes "Unable to decrypt" en el timeline visible.
|
||||
* Lanza error descriptivo si los encuentra.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
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.
|
||||
@@ -50,10 +51,12 @@ export const test = base.extend<
|
||||
});
|
||||
|
||||
/**
|
||||
* Maneja dialogos de Element que bloquean la carga:
|
||||
* Maneja dialogos y toasts de Element que bloquean la carga:
|
||||
* - "Element is open in another window" → click Continue
|
||||
* - Spinner de carga → esperar
|
||||
* - "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("/")
|
||||
*/
|
||||
@@ -84,11 +87,53 @@ export async function handleElementDialogs(page: Page) {
|
||||
);
|
||||
}
|
||||
|
||||
// 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");
|
||||
// 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";
|
||||
|
||||
@@ -5,8 +5,7 @@ import {
|
||||
waitForBotReply,
|
||||
assertNoDecryptionErrors,
|
||||
startThreadOnLastMessage,
|
||||
sendThreadMessage,
|
||||
waitForThreadReply,
|
||||
waitForThreadReplyViaSdk,
|
||||
} from "../fixtures/matrix-room";
|
||||
|
||||
test.describe("asistente-2", () => {
|
||||
@@ -66,6 +65,8 @@ test.describe("asistente-2", () => {
|
||||
test("responde dentro del thread cuando se le habla por thread", async ({
|
||||
page,
|
||||
}) => {
|
||||
// Este test necesita mas tiempo: enviar msg + esperar bot + thread + esperar bot en thread
|
||||
test.setTimeout(120_000);
|
||||
// 1. Enviar un mensaje normal (sera el thread root)
|
||||
await sendMessage(page, "Mensaje para iniciar thread");
|
||||
|
||||
@@ -75,17 +76,12 @@ test.describe("asistente-2", () => {
|
||||
sender: "Asistente 2",
|
||||
});
|
||||
|
||||
// 2. Iniciar thread sobre el mensaje del usuario
|
||||
// 2. Enviar mensaje threaded via SDK (headless no soporta la hover action bar)
|
||||
await startThreadOnLastMessage(page);
|
||||
|
||||
// 3. Enviar mensaje dentro del thread
|
||||
await sendThreadMessage(
|
||||
page,
|
||||
"Hola desde el thread, respondeme aqui por favor"
|
||||
);
|
||||
|
||||
// 4. Esperar que el bot responda DENTRO del thread
|
||||
const threadReply = await waitForThreadReply(page, {
|
||||
// 3. Esperar que el bot responda DENTRO del thread
|
||||
// Usar el SDK para verificar que hay una respuesta en el thread
|
||||
const threadReply = await waitForThreadReplyViaSdk(page, {
|
||||
timeout: 60_000,
|
||||
sender: "Asistente 2",
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ test.describe("Login y sesion E2EE", () => {
|
||||
await handleElementDialogs(page);
|
||||
|
||||
// Si llegamos aqui, handleElementDialogs ya verifico rooms sidebar
|
||||
const rooms = page.locator('[role="treeitem"]');
|
||||
const rooms = page.locator('[role="treeitem"], .mx_RoomTile');
|
||||
const roomCount = await rooms.count();
|
||||
expect(roomCount).toBeGreaterThan(0);
|
||||
});
|
||||
@@ -19,7 +19,7 @@ test.describe("Login y sesion E2EE", () => {
|
||||
await handleElementDialogs(page);
|
||||
|
||||
// Abrir el primer room visible para verificar mensajes
|
||||
const firstRoom = page.locator('[role="treeitem"]').first();
|
||||
const firstRoom = page.locator('[role="treeitem"], .mx_RoomTile').first();
|
||||
const roomCount = await firstRoom.count();
|
||||
|
||||
if (roomCount > 0) {
|
||||
@@ -33,7 +33,7 @@ test.describe("Login y sesion E2EE", () => {
|
||||
await page.goto("/");
|
||||
await handleElementDialogs(page);
|
||||
|
||||
const rooms = page.locator('[role="treeitem"]');
|
||||
const rooms = page.locator('[role="treeitem"], .mx_RoomTile');
|
||||
const roomCount = await rooms.count();
|
||||
expect(roomCount).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user