220 lines
9.3 KiB
JavaScript
220 lines
9.3 KiB
JavaScript
// Los 13 tipos: alta desde la paleta, edición en el formulario y reflejo en el chat.
|
|
import {
|
|
test, expect, estado, vaciar, anadirTipo, campo, filaChat, tarjetas, modoUrl, PNG_1PX, TIPOS,
|
|
} from "./fixtures.mjs";
|
|
|
|
const DATA_PNG = "data:image/png;base64," + PNG_1PX.toString("base64");
|
|
|
|
/**
|
|
* Por tipo: selector que debe existir en la burbuja recién creada, ediciones
|
|
* [ruta relativa, valor] y comprobaciones sobre la fila del chat tras editar.
|
|
*/
|
|
const CASOS = {
|
|
text: {
|
|
base: ".bubble .wa-texto",
|
|
editar: [["texto", "Pedido *listo* para _recoger_"]],
|
|
comprobar: async (fila) => {
|
|
await expect(fila.locator(".wa-texto strong")).toHaveText("listo");
|
|
await expect(fila.locator(".wa-texto em")).toHaveText("recoger");
|
|
},
|
|
},
|
|
image: {
|
|
base: "img.wa-media",
|
|
url: "src",
|
|
editar: [["src", DATA_PNG], ["caption", "Foto del local"]],
|
|
comprobar: async (fila) => {
|
|
await expect(fila.locator("img.wa-media")).toHaveAttribute("src", DATA_PNG);
|
|
await expect(fila.locator(".wa-caption")).toContainText("Foto del local");
|
|
},
|
|
},
|
|
video: {
|
|
base: ".wa-media-wrap .wa-play-badge",
|
|
editar: [["caption", "Tour virtual"]],
|
|
comprobar: async (fila) => {
|
|
await expect(fila.locator(".wa-caption")).toContainText("Tour virtual");
|
|
},
|
|
},
|
|
audio: {
|
|
base: ".wa-audio .audio-wave",
|
|
editar: [["duracion", "1:05"]],
|
|
comprobar: async (fila) => {
|
|
await expect(fila.locator(".audio-dur")).toHaveText("1:05");
|
|
await expect(fila.locator(".audio-mic")).toBeVisible();
|
|
},
|
|
},
|
|
document: {
|
|
base: ".wa-doc .doc-panel",
|
|
editar: [["filename", "informe-trimestral.xlsx"], ["caption", "Resultados"]],
|
|
comprobar: async (fila) => {
|
|
await expect(fila.locator(".doc-nombre")).toHaveText("informe-trimestral.xlsx");
|
|
await expect(fila.locator(".doc-sub")).toContainText(/xlsx/i);
|
|
await expect(fila.locator(".wa-caption")).toContainText("Resultados");
|
|
},
|
|
},
|
|
sticker: {
|
|
base: ".sticker-box .sticker-img",
|
|
url: "src",
|
|
editar: [["src", DATA_PNG]],
|
|
comprobar: async (fila) => {
|
|
await expect(fila.locator(".sticker-img")).toHaveAttribute("src", DATA_PNG);
|
|
},
|
|
},
|
|
location: {
|
|
base: ".wa-loc .loc-mapa",
|
|
editar: [["nombre", "Sucursal Norte"], ["direccion", "Av. Reforma 500"]],
|
|
comprobar: async (fila) => {
|
|
await expect(fila.locator(".loc-nombre")).toHaveText("Sucursal Norte");
|
|
await expect(fila.locator(".loc-dir")).toHaveText("Av. Reforma 500");
|
|
},
|
|
},
|
|
contact: {
|
|
base: ".wa-contact .contact-nombre",
|
|
editar: [["nombre", "Ana Torres"], ["telefono", "+52 55 1234 5678"]],
|
|
comprobar: async (fila) => {
|
|
await expect(fila.locator(".contact-nombre")).toHaveText("Ana Torres");
|
|
},
|
|
},
|
|
template: {
|
|
base: ".bubble.tpl .tpl-body",
|
|
editar: [["body", "Tu cita es mañana"], ["footer", "Clínica Demo"], ["botones.0.texto", "Confirmo"]],
|
|
comprobar: async (fila) => {
|
|
await expect(fila.locator(".tpl-body")).toHaveText("Tu cita es mañana");
|
|
await expect(fila.locator(".template-footer")).toHaveText("Clínica Demo");
|
|
await expect(fila.locator(".qr-btn .btn-label")).toHaveText(["Confirmo"]);
|
|
},
|
|
},
|
|
buttons: {
|
|
base: ".bubble.tpl button.qr-btn",
|
|
editar: [["body", "¿Te ayudo?"], ["botones.0.texto", "Sí, por favor"]],
|
|
comprobar: async (fila) => {
|
|
await expect(fila.locator(".tpl-body")).toHaveText("¿Te ayudo?");
|
|
await expect(fila.locator("button.qr-btn .btn-label")).toHaveText(["Sí, por favor"]);
|
|
},
|
|
},
|
|
list: {
|
|
base: ".bubble.tpl button.qr-btn[data-flujo]",
|
|
editar: [["header", "Catálogo"], ["body", "Elige tu plan"], ["boton", "Ver planes"]],
|
|
comprobar: async (fila) => {
|
|
await expect(fila.locator(".tpl-header-txt")).toHaveText("Catálogo");
|
|
await expect(fila.locator(".tpl-body")).toHaveText("Elige tu plan");
|
|
await expect(fila.locator("button.qr-btn")).toHaveText("Ver planes");
|
|
},
|
|
},
|
|
cta_url: {
|
|
base: ".bubble.tpl .qr-btn",
|
|
editar: [["textoBoton", "Ir a la web"], ["url", "https://example.org/promo"], ["body", "Promo de temporada"]],
|
|
comprobar: async (fila) => {
|
|
const a = fila.locator("a.qr-btn");
|
|
await expect(a).toHaveAttribute("href", "https://example.org/promo");
|
|
await expect(a).toHaveAttribute("target", "_blank");
|
|
await expect(a).toContainText("Ir a la web");
|
|
await expect(fila.locator(".tpl-body")).toHaveText("Promo de temporada");
|
|
},
|
|
},
|
|
carousel: {
|
|
base: ".carousel .card",
|
|
editar: [["body", "Novedades"], ["cards.0.texto", "Plan Básico"], ["cards.1.textoBoton", "Lo quiero"]],
|
|
comprobar: async (fila) => {
|
|
await expect(fila.locator(".card")).toHaveCount(2);
|
|
await expect(fila.locator(".wa-stack > .bubble .wa-texto")).toContainText("Novedades");
|
|
await expect(fila.locator(".card").nth(0).locator(".card-body")).toHaveText("Plan Básico");
|
|
await expect(fila.locator(".card").nth(1).locator(".btn-label")).toHaveText("Lo quiero");
|
|
},
|
|
},
|
|
};
|
|
|
|
test.describe("Los 13 tipos de mensaje", () => {
|
|
test("la paleta ofrece exactamente los 13 tipos", async ({ app }) => {
|
|
const tipos = await app.locator('#nuevo-tipo [data-acc="anadir-tipo"]').evaluateAll((els) => els.map((e) => e.dataset.tipo));
|
|
expect([...tipos].sort()).toEqual([...TIPOS].sort());
|
|
});
|
|
|
|
for (const tipo of TIPOS) {
|
|
test(`${tipo}: añadir, editar y ver el reflejo en el chat`, async ({ app }) => {
|
|
const caso = CASOS[tipo];
|
|
await vaciar(app);
|
|
const id = await anadirTipo(app, tipo);
|
|
|
|
// Tarjeta abierta y burbuja en el chat
|
|
const t = app.locator(`#lista-mensajes > .ed-tarjeta[data-id="${id}"]`);
|
|
await expect(tarjetas(app)).toHaveCount(1);
|
|
await expect(t).toHaveClass(/ed-abierta/);
|
|
const fila = filaChat(app, id);
|
|
await expect(fila).toBeVisible();
|
|
await expect(fila.locator(caso.base).first()).toBeVisible();
|
|
// Alta: el foco va a un campo de la tarjeta nueva
|
|
await expect.poll(() => app.evaluate((i) => {
|
|
const a = document.activeElement;
|
|
return !!(a && a.closest(`.ed-tarjeta[data-id="${i}"]`));
|
|
}, id)).toBe(true);
|
|
|
|
// Edición
|
|
for (const [rel, valor] of caso.editar) {
|
|
const ruta = `mensajes.0.${rel}`;
|
|
const inp = caso.url === rel ? await modoUrl(app, ruta) : campo(app, ruta);
|
|
await inp.fill(valor);
|
|
}
|
|
await caso.comprobar(fila);
|
|
|
|
// El estado vivo y el persistido reflejan la edición
|
|
const e = await estado(app);
|
|
for (const [rel, valor] of caso.editar) {
|
|
const v = rel.split(".").reduce((o, k) => (o == null ? o : o[k]), e.mensajes[0]);
|
|
expect(v, rel).toBe(valor);
|
|
}
|
|
const guardado = await app.evaluate(() => { WAM.guardarYa(); return JSON.parse(localStorage.getItem("wam-mockup-v1")); });
|
|
expect(guardado.mensajes[0].tipo).toBe(tipo);
|
|
});
|
|
}
|
|
|
|
test("cambiar la dirección a «Salida» pinta ticks y el selector de estado", async ({ app }) => {
|
|
await vaciar(app);
|
|
const id = await anadirTipo(app, "text");
|
|
const fila = filaChat(app, id);
|
|
await expect(fila).toHaveClass(/\bin\b/);
|
|
await app.locator('#lista-mensajes label.ed-seg-op:has(input[data-rol="dir"][value="out"])').click();
|
|
await expect(fila).toHaveClass(/\bout\b/);
|
|
await expect(fila.locator(".tick")).toHaveCount(1);
|
|
const sel = campo(app, "mensajes.0.estado");
|
|
await sel.selectOption("read");
|
|
await expect(filaChat(app, id).locator(".tick-read")).toBeVisible();
|
|
await sel.selectOption("delivered");
|
|
await expect(filaChat(app, id).locator(".tick")).toBeVisible();
|
|
await expect(filaChat(app, id).locator(".tick-read")).toHaveCount(0);
|
|
expect((await estado(app)).mensajes[0]).toMatchObject({ dir: "out", estado: "delivered" });
|
|
});
|
|
|
|
test("editar la hora se refleja en la burbuja", async ({ app }) => {
|
|
await vaciar(app);
|
|
const id = await anadirTipo(app, "text");
|
|
await campo(app, "mensajes.0.hora").fill("09:41");
|
|
await expect(filaChat(app, id).locator(".meta")).toContainText("09:41");
|
|
});
|
|
|
|
test("audio: desactivar «nota de voz» cambia a audio con auriculares", async ({ app }) => {
|
|
await vaciar(app);
|
|
const id = await anadirTipo(app, "audio");
|
|
await campo(app, "mensajes.0.voz").uncheck();
|
|
await expect(filaChat(app, id).locator(".audio-musica")).toBeVisible();
|
|
await expect(filaChat(app, id).locator(".audio-mic")).toHaveCount(0);
|
|
expect((await estado(app)).mensajes[0].voz).toBe(false);
|
|
});
|
|
|
|
test("plantilla: cabecera opcional de texto, imagen y documento", async ({ app }) => {
|
|
await vaciar(app);
|
|
const id = await anadirTipo(app, "template");
|
|
const fila = filaChat(app, id);
|
|
await app.locator("#lista-mensajes label.ed-switch", { hasText: "Mostrar cabecera" }).click();
|
|
await expect(app.locator('#lista-mensajes input[data-rol="header-toggle"]')).toBeChecked();
|
|
const tipoCab = (v) => app.locator(`#lista-mensajes [data-acc="header-tipo"][data-valor="${v}"]`);
|
|
await tipoCab("texto").click();
|
|
await campo(app, "mensajes.0.headerTexto").fill("Aviso importante");
|
|
await expect(fila.locator(".tpl-header-txt")).toHaveText("Aviso importante");
|
|
await tipoCab("imagen").click();
|
|
await expect(fila.locator("img.tpl-media")).toBeVisible();
|
|
await tipoCab("documento").click();
|
|
await expect(fila.locator(".tpl-header-doc .doc-nombre")).toBeVisible();
|
|
expect((await estado(app)).mensajes[0].headerTipo).toBe("documento");
|
|
});
|
|
});
|