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
+52
View File
@@ -0,0 +1,52 @@
import { test, expect, type Page } from "@playwright/test";
async function createBoard(page: Page, title: string) {
await page.goto("/");
await page.getByTestId("board-title").fill(title);
await page.getByTestId("template").selectOption("mad-sad-glad");
await page.getByTestId("create").click();
await page.waitForURL(/\/b\/.+/);
return page.url();
}
async function joinAs(page: Page, boardUrl: string, name: string) {
await page.goto(boardUrl);
await page.getByTestId("name").fill(name);
await page.getByTestId("join").click();
await expect(page.getByTestId("column").first()).toBeVisible();
}
test("exportar a JSON e importar: estructura vs todo", async ({ page, request }) => {
const url = await createBoard(page, "Fuente");
const boardId = url.split("/b/")[1];
await joinAs(page, url, "Origen");
const col = page.getByTestId("column").first();
await col.getByTestId("note-input").fill("nota a exportar");
await col.getByTestId("note-input").press("Enter");
await col.getByTestId("publish").first().click(); // publicada para que viaje visible
await expect(col.getByTestId("note")).toHaveCount(1);
const snapshotJson = await (
await request.get(`http://localhost:3001/api/boards/${boardId}/export.json`)
).text();
const filePayload = { name: "fuente.retro.json", mimeType: "application/json", buffer: Buffer.from(snapshotJson) };
// --- import solo estructura: 3 columnas, 0 notas ---
await page.goto("/");
await page.getByTestId("import-toggle").click();
await page.getByText("Only structure", { exact: false }).click();
await page.getByTestId("import-file").setInputFiles(filePayload);
await page.waitForURL(/\/b\/.+/);
await joinAs(page, page.url(), "Importador");
await expect(page.getByTestId("column")).toHaveCount(3);
await expect(page.getByTestId("note")).toHaveCount(0);
// --- import completo: la nota viaja ---
await page.goto("/");
await page.getByTestId("import-toggle").click();
await page.getByTestId("import-file").setInputFiles(filePayload); // modo 'full' por defecto
await page.waitForURL(/\/b\/.+/);
await joinAs(page, page.url(), "Importador2");
await expect(page.getByTestId("note")).toHaveCount(1);
});