Files
Millaguie f11ea58c2c
CI/CD Pipeline / test (push) Successful in 26s
CI/CD Pipeline / build-and-push (push) Successful in 44s
Sternboard: free retro board, no signup (initial)
Servidor Fastify + Socket.IO + Drizzle/Postgres; front Vite+React (EN/ES, tema claro/oscuro).
Tableros por columnas con plantillas, notas privadas/públicas, agrupación, votos
configurables (multivoto), timer compartido con alarma, fases, action items,
export Markdown/JSON e import, autodestrucción, gestión de columnas.
Imagen única (front servido por el servidor) y CI que la construye y publica.
2026-06-16 10:27:33 +02:00

102 lines
3.3 KiB
TypeScript

import { describe, it, expect, beforeAll, afterAll } from "vitest";
import { startTestServer, type TestServer } from "./helpers.js";
let server: TestServer;
beforeAll(async () => {
server = await startTestServer();
});
afterAll(async () => {
await server.close();
});
const snapshot = {
version: 1,
board: { title: "Importado", votesPerUser: 4 },
columns: [
{ id: "c1", title: "Columna A", position: 0 },
{ id: "c2", title: "Columna B", position: 1 },
],
groups: [],
notes: [
{
id: "n1",
columnId: "c1",
groupId: null,
authorId: "x",
authorName: "X",
text: "nota importada",
revealed: true,
position: 1,
},
],
votes: [{ targetType: "note", targetId: "n1", participantId: "x" }],
actionItems: [{ text: "tarea importada", owner: "X" }],
};
async function importAndExport(mode: "full" | "structure") {
const res = await fetch(`${server.url}/api/boards/import`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ snapshot, mode }),
});
const { boardId } = await res.json();
const md = await (await fetch(`${server.url}/api/boards/${boardId}/export`)).text();
return { boardId, md };
}
describe("Import", () => {
it("modo 'full' importa columnas, notas y votos", async () => {
const { md } = await importAndExport("full");
expect(md).toContain("# Importado");
expect(md).toContain("## Columna A");
expect(md).toContain("nota importada — _X_ (1 👍)");
expect(md).toContain("tarea importada");
});
it("modo 'structure' importa solo columnas y config, sin notas", async () => {
const { md } = await importAndExport("structure");
expect(md).toContain("## Columna A");
expect(md).toContain("## Columna B");
expect(md).not.toContain("nota importada");
expect(md).not.toContain("tarea importada");
});
it("rechaza un snapshot sin columnas", async () => {
const res = await fetch(`${server.url}/api/boards/import`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ snapshot: { version: 1, columns: [] }, mode: "full" }),
});
expect(res.status).toBe(400);
});
});
describe("Export con opciones", () => {
async function importFull(): Promise<string> {
const res = await fetch(`${server.url}/api/boards/import`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ snapshot, mode: "full" }),
});
return (await res.json()).boardId;
}
const md = (id: string, qs: string) =>
fetch(`${server.url}/api/boards/${id}/export${qs}`).then((r) => r.text());
it("autores y votos se pueden desactivar por query", async () => {
const id = await importFull();
expect(await md(id, "")).toContain("nota importada — _X_ (1 👍)"); // defaults
const noAuthors = await md(id, "?authors=0");
expect(noAuthors).toContain("nota importada (1 👍)");
expect(noAuthors).not.toContain("_X_");
const noVotes = await md(id, "?votes=0");
expect(noVotes).not.toContain("👍");
});
it("la fecha de creación se añade al título con created=1", async () => {
const id = await importFull();
const withDate = await md(id, "?created=1");
expect(withDate).toMatch(/^# \d+\/\d+\/\d+ - Importado/);
});
});