// Regresiones: deshacer/rehacer con demos guardadas, avisos «Deshacer» // obsoletos, hoja «Todas las opciones» con URLs bloqueadas y foco en las hojas. import { test, expect, estado, filaChat, cargarEstado, rapido } from "./fixtures.mjs"; async function nombreCuenta(page, v) { await page.evaluate(() => { const d = document.getElementById("bloque-cuenta"); if (d) d.open = true; }); await page.locator("#cuenta-nombre").fill(v); await expect.poll(async () => (await estado(page)).cuenta.nombre).toBe(v); } const activaLS = (page) => page.evaluate(() => localStorage.getItem("wam-demo-activa")); async function guardarComo(page, nombre) { await page.locator("#btn-demos").click(); const dlg = page.locator("#dlg-demos"); await dlg.locator("#dlg-demo-nombre").fill(nombre); await dlg.getByRole("button", { name: /Guardar/ }).click(); await expect(dlg.locator(".wam-demo-nombre", { hasText: new RegExp("^" + nombre + "$") })).toBeVisible(); await dlg.locator(".wam-dlg-pie").getByRole("button", { name: "Cerrar" }).click(); } test.describe("Deshacer y demos guardadas", () => { test("deshacer / rehacer reponen la demo activa y «Actualizar» no pisa otra demo", async ({ app }) => { await guardarComo(app, "A"); const idA = await activaLS(app); // cargar un escenario y guardarlo como B await app.locator("#btn-demos").click(); await app.locator("#dlg-demos .wam-esc").first().click(); await nombreCuenta(app, "Cuenta B"); await guardarComo(app, "B"); const idB = await activaLS(app); expect(idB).not.toBe(idA); // abrir A await app.locator("#btn-demos").click(); await app.locator("#dlg-demos .wam-demo").filter({ has: app.locator(".wam-demo-nombre", { hasText: /^A$/ }) }) .getByRole("button", { name: "Abrir" }).click(); expect(await activaLS(app)).toBe(idA); // deshacer: vuelve el contenido de B y también la demo activa B await app.locator("#btn-deshacer").click(); expect((await estado(app)).cuenta.nombre).toBe("Cuenta B"); expect(await activaLS(app)).toBe(idB); await app.locator("#btn-demos").click(); await expect(app.locator("#dlg-demo-nombre")).toHaveValue("B"); await app.locator("#dlg-demos .wam-dlg-pie").getByRole("button", { name: "Cerrar" }).click(); // rehacer: vuelve A await app.locator("#btn-rehacer").click(); expect(await activaLS(app)).toBe(idA); // deshacer un escenario (que borra la clave activa) la repone await app.locator("#btn-demos").click(); await app.locator("#dlg-demos .wam-esc").first().click(); expect(await activaLS(app)).toBeNull(); await app.locator("#btn-deshacer").click(); expect(await activaLS(app)).toBe(idA); // el hueco de A sigue siendo A const slotA = await app.evaluate((id) => JSON.parse(localStorage.getItem("wam-demo-" + id) || "null"), idA); expect(slotA && slotA.cuenta.nombre).not.toBe("Cuenta B"); }); test("«Actualizar» pide un segundo clic si cambió la cuenta", async ({ app }) => { await guardarComo(app, "A"); const idA = await activaLS(app); const nombreOriginal = (await estado(app)).cuenta.nombre; await nombreCuenta(app, "Otra cuenta"); await app.locator("#btn-demos").click(); const bGuardar = app.locator("#dlg-demos .wam-dlg-primario"); await expect(bGuardar).toHaveText("Actualizar"); await bGuardar.click(); await expect(bGuardar).toHaveText(/Sobrescribir/); let slot = await app.evaluate((id) => JSON.parse(localStorage.getItem("wam-demo-" + id)), idA); expect(slot.cuenta.nombre).toBe(nombreOriginal); await bGuardar.click(); slot = await app.evaluate((id) => JSON.parse(localStorage.getItem("wam-demo-" + id)), idA); expect(slot.cuenta.nombre).toBe("Otra cuenta"); }); test("el «Deshacer» de un aviso desaparece cuando hay otro cambio", async ({ app }) => { const n = (await estado(app)).mensajes.length; await app.evaluate(() => WAM.borrarMensaje(0)); const accion = app.locator("#ed-toasts .ed-toast-accion"); await expect(accion).toHaveCount(1); await nombreCuenta(app, "Nombre nuevo"); // sin esperar: el aviso caduca solo a los 6 s y enmascararía el fallo expect(await accion.count()).toBe(0); expect((await estado(app)).mensajes.length).toBe(n - 1); }); }); const PLANTILLA = [ { id: "m1", dir: "in", tipo: "template", hora: "10:00", body: "Elige", botones: [ { texto: "Uno" }, { texto: "Dos" }, { texto: "Bloqueado", url: "javascript:alert(1)" }, { texto: "Relativa", url: "/menu" }, { texto: "Cinco" }, ], }, { id: "m2", dir: "in", tipo: "list", hora: "10:01", body: "Menú", boton: "Ver menú", secciones: [{ titulo: "S", filas: [{ id: "f1", titulo: "Fila 1" }, { id: "f2", titulo: "Fila 2" }] }], }, ]; test.describe("Hojas inferiores", () => { test.beforeEach(async ({ app }) => { await rapido(app); await cargarEstado(app, { mensajes: PLANTILLA }); await expect(filaChat(app, "m1")).toHaveCount(1); }); test("«Todas las opciones» pinta inertes los botones con URL bloqueada o no válida", async ({ app }) => { const fila = filaChat(app, "m1"); const inertesBurbuja = await fila.locator(".qr-btn-inactiva").allTextContents(); expect(inertesBurbuja.map((t) => t.trim())).toEqual(["Bloqueado", "Relativa"]); await fila.locator("[data-ver-todas]").click(); const hoja = app.locator("#sheet"); const inertesHoja = await hoja.locator('.sheet-fila.qr-btn-inactiva[aria-disabled="true"]').allTextContents(); expect(inertesHoja.map((t) => t.trim())).toEqual(inertesBurbuja.map((t) => t.trim())); await expect(hoja.locator("[data-opcion]")).toHaveCount(3); await expect(hoja.locator('[data-opcion="2"], [data-opcion="3"]')).toHaveCount(0); await expect(hoja.locator(".sheet-fila")).toHaveCount(5); }); test("foco: la hoja lo recibe, lo retiene con Tab y lo devuelve al cerrar", async ({ app }) => { const toggle = filaChat(app, "m1").locator("[data-ver-todas]"); await toggle.focus(); await app.keyboard.press("Enter"); await expect(app.locator("#sheet")).toHaveCount(1); const enHoja = () => app.evaluate(() => !!document.activeElement.closest("#sheet")); expect(await enHoja()).toBe(true); for (let k = 0; k < 6; k++) { await app.keyboard.press("Tab"); expect(await enHoja()).toBe(true); } await app.keyboard.press("Shift+Tab"); expect(await enHoja()).toBe(true); await app.keyboard.press("Escape"); await expect(app.locator("#sheet")).toHaveCount(0); expect(await app.evaluate(() => document.activeElement.hasAttribute("data-ver-todas"))).toBe(true); }); test("foco: la lista «Ver opciones» enfoca su primera fila", async ({ app }) => { const abridor = filaChat(app, "m2").locator("[data-flujo]:not([data-btn]):not([data-card])").first(); await abridor.focus(); await app.keyboard.press("Enter"); await expect(app.locator("#sheet")).toHaveCount(1); expect(await app.evaluate(() => document.activeElement.getAttribute("data-fila"))).toBe("0"); await app.locator("#sheet .sheet-cerrar").click(); await expect(app.locator("#sheet")).toHaveCount(0); expect(await app.evaluate(() => document.activeElement.closest('[data-id="m2"]') !== null)).toBe(true); }); });