WIP: mejoras de fidelidad, editor, lógica y suite e2e (checkpoint tras reinicio)

This commit is contained in:
urieljareth
2026-09-27 20:46:51 -06:00
parent dc6e31a9d7
commit 9a5f21badf
33 changed files with 7719 additions and 1129 deletions
+110
View File
@@ -0,0 +1,110 @@
// «Reproducir demo»: revelado paso a paso, detener, velocidad y autoPulsar.
import { test, expect, estado, filasChat, cargarEstado, rapido } from "./fixtures.mjs";
const btn = (page) => page.locator("#btn-reproducir");
const GUION_CORTO = {
version: 1, tema: "claro",
cuenta: { nombre: "Demo corta", verificado: false },
mensajes: [
{ id: "m1", dir: "in", tipo: "text", hora: "10:00", texto: "Hola" },
{ id: "m2", dir: "out", tipo: "text", hora: "10:01", texto: "Buenas", estado: "read" },
{
id: "m3", dir: "in", tipo: "buttons", hora: "10:02", body: "¿Qué quieres?", autoPulsar: 1,
botones: [
{ texto: "Precios", respuestas: [] },
{ texto: "Horario", respuestas: [{ id: "m4", dir: "in", tipo: "text", hora: "10:02", texto: "Abrimos a las 9" }] },
],
},
],
};
test.describe("Reproducir demo", () => {
test("vacía el chat, revela los mensajes uno a uno y termina sola", async ({ app }) => {
await cargarEstado(app, GUION_CORTO);
await rapido(app);
// al arrancar el chat se vacía al instante (solo quedan los avisos de sistema)
const filasTrasClic = await app.evaluate(() => {
document.getElementById("btn-reproducir").click();
return document.querySelectorAll("#chat-cuerpo > li.wa-row").length;
});
expect(filasTrasClic).toBe(0);
await expect(btn(app)).toHaveAttribute("aria-pressed", "true");
await expect(btn(app)).toContainText("Detener");
// «escribiendo…» antes del primer IN
await expect(app.locator("#chat-escribiendo")).toBeVisible();
await expect(filasChat(app)).toHaveCount(1, { timeout: 3000 });
await expect(filasChat(app).nth(0)).toContainText("Hola");
await expect(filasChat(app)).toHaveCount(3, { timeout: 5000 });
// autoPulsar: pulsa sola «Horario» y llega su respuesta
await expect(app.locator('#chat-cuerpo li.out[data-id^="s"]')).toContainText("Horario", { timeout: 5000 });
await expect(app.locator('#chat-cuerpo li.in[data-id^="s"]')).toContainText("Abrimos a las 9", { timeout: 6000 });
await expect.poll(() => app.evaluate(() => WAM.demoActiva()), { timeout: 10000 }).toBe(false);
await expect(btn(app)).toContainText("Reproducir demo");
await expect(btn(app)).toHaveAttribute("aria-pressed", "false");
});
test("pulsar de nuevo la detiene y vuelve al guion completo", async ({ app }) => {
const n = (await estado(app)).mensajes.length;
await btn(app).click();
await expect.poll(() => filasChat(app).count(), { timeout: 4000 }).toBeGreaterThan(0);
await app.waitForTimeout(400); // evita el antirrebote de doble clic
await btn(app).click();
await expect(btn(app)).toContainText("Reproducir demo");
await expect(filasChat(app)).toHaveCount(n);
expect(await app.evaluate(() => WAM.demoActiva())).toBe(false);
// nada sigue apareciendo después de detener
await app.waitForTimeout(1500);
await expect(filasChat(app)).toHaveCount(n);
});
test("un doble clic no arranca y detiene en el mismo gesto", async ({ app }) => {
await btn(app).dblclick();
expect(await app.evaluate(() => WAM.demoActiva())).toBe(true);
await app.waitForTimeout(400);
await btn(app).click();
});
test("la barra espaciadora (fuera de campos) alterna la demo", async ({ app }) => {
await app.locator("#iphone").click({ position: { x: 5, y: 400 } });
await app.keyboard.press("Space");
await expect.poll(() => app.evaluate(() => WAM.demoActiva())).toBe(true);
await app.waitForTimeout(400);
await app.keyboard.press("Space");
await expect.poll(() => app.evaluate(() => WAM.demoActiva())).toBe(false);
});
test("la velocidad se elige en el selector y persiste", async ({ app }) => {
await app.locator("#sel-velocidad").selectOption("2");
expect(await app.evaluate(() => WAM.getVelocidad())).toBe(2);
await app.reload();
await expect(app.locator("#sel-velocidad")).toHaveValue("2");
await app.locator("#sel-velocidad").selectOption("0.5");
expect(await app.evaluate(() => WAM.getVelocidad())).toBe(0.5);
});
test("a 2x la demo es más rápida que a 0,5x", async ({ app }) => {
await cargarEstado(app, { ...GUION_CORTO, mensajes: GUION_CORTO.mensajes.slice(0, 2) });
const medir = async (v) => {
await app.evaluate((x) => WAM.setVelocidad(x), v);
const t0 = Date.now();
await btn(app).click();
await expect.poll(() => app.evaluate(() => WAM.demoActiva()), { timeout: 15000, intervals: [50] }).toBe(false);
await app.waitForTimeout(400);
return Date.now() - t0;
};
const lenta = await medir(0.5);
const rapida = await medir(2);
expect(rapida).toBeLessThan(lenta);
});
test("editar el guion durante la demo la cancela sin errores", async ({ app }) => {
await btn(app).click();
await expect.poll(() => filasChat(app).count(), { timeout: 4000 }).toBeGreaterThan(0);
await app.locator('#nuevo-tipo [data-tipo="text"]').click();
await expect.poll(() => app.evaluate(() => WAM.demoActiva())).toBe(false);
const n = (await estado(app)).mensajes.length;
await expect(filasChat(app)).toHaveCount(n);
await expect(btn(app)).toContainText("Reproducir demo");
});
});