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.
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
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/);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user