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.
102 lines
3.3 KiB
TypeScript
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/);
|
|
});
|
|
});
|