Sternboard: free retro board, no signup (initial)
CI/CD Pipeline / test (push) Successful in 26s
CI/CD Pipeline / build-and-push (push) Successful in 44s

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:
Millaguie
2026-06-16 10:27:33 +02:00
commit f11ea58c2c
64 changed files with 12359 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
import { describe, it, expect, beforeAll, afterAll } from "vitest";
import { startTestServer, createBoard, join, type TestServer } from "./helpers.js";
let server: TestServer;
beforeAll(async () => {
server = await startTestServer();
});
afterAll(async () => {
await server.close();
});
describe("Notas privadas y publicar", () => {
it("note:publishMine publica todas mis notas de la columna", async () => {
const board = await createBoard(server.url);
const alice = await join(server.url, board.boardId, "alice", "Alice");
const bob = await join(server.url, board.boardId, "bob", "Bob");
const colId = alice.last!.columns[0].id;
alice.emit("note:add", { columnId: colId, text: "uno" });
alice.emit("note:add", { columnId: colId, text: "dos" });
await alice.waitFor((s) => s.notes.length === 2);
// Bob recibe las notas pero sin texto (privadas)
const bobBefore = await bob.waitFor((s) => s.notes.length === 2);
expect(bobBefore.notes.every((n) => n.text === "")).toBe(true);
alice.emit("note:publishMine", { columnId: colId });
// guard de longitud: every() es vacuamente true sobre [] -> exigimos las 2 notas
const bobAfter = await bob.waitFor((s) => s.notes.length === 2 && s.notes.every((n) => n.text !== ""));
expect(bobAfter.notes.map((n) => n.text).sort()).toEqual(["dos", "uno"]);
alice.close();
bob.close();
});
it("agrupar publica las notas implicadas", async () => {
const board = await createBoard(server.url);
const alice = await join(server.url, board.boardId, "alice", "Alice");
const bob = await join(server.url, board.boardId, "bob", "Bob");
const colId = alice.last!.columns[0].id;
alice.emit("note:add", { columnId: colId, text: "A" });
alice.emit("note:add", { columnId: colId, text: "B" });
const st = await alice.waitFor((s) => s.notes.length === 2);
const [a, b] = st.notes;
alice.emit("group:create", { noteId: b.id, targetNoteId: a.id });
// Bob ve ambas notas con texto (agrupar es público)
const bobAfter = await bob.waitFor(
(s) => s.groups.length === 1 && s.notes.length === 2 && s.notes.every((n) => n.text !== ""),
);
expect(bobAfter.notes.map((n) => n.text).sort()).toEqual(["A", "B"]);
alice.close();
bob.close();
});
});