You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
taskbot/tests/web/api.tasks.complete-concurre...

92 lines
3.2 KiB
TypeScript

import { describe, it, beforeAll, afterAll, expect } from 'bun:test';
import { createTempDb } from './helpers/db';
import { startWebServer, type RunningServer } from './helpers/server';
describe('API Web - carreras en complete con auto-asignación', () => {
const U1 = '34600123456';
const U2 = '34600123457';
const GROUP = 'g-3@g.us';
let dbHandle: any;
let cleanupDb: () => void;
let serverA: RunningServer;
let serverB: RunningServer;
let baseA: string;
let baseB: string;
let taskId: number;
beforeAll(async () => {
const tmp = createTempDb();
dbHandle = tmp.db;
cleanupDb = tmp.cleanup;
// Semilla mínima
dbHandle.prepare(`INSERT INTO users (id) VALUES (?) ON CONFLICT(id) DO NOTHING`).run(U1);
dbHandle.prepare(`INSERT INTO users (id) VALUES (?) ON CONFLICT(id) DO NOTHING`).run(U2);
dbHandle
.prepare(`INSERT INTO groups (id, community_id, name, active) VALUES (?, 'comm-1', 'G3', 1)`)
.run(GROUP);
dbHandle.prepare(`INSERT INTO allowed_groups (group_id, status) VALUES (?, 'allowed')`).run(GROUP);
dbHandle
.prepare(`INSERT INTO group_members (group_id, user_id, is_admin, is_active) VALUES (?, ?, 0, 1)`)
.run(GROUP, U1);
dbHandle
.prepare(`INSERT INTO group_members (group_id, user_id, is_admin, is_active) VALUES (?, ?, 0, 1)`)
.run(GROUP, U2);
const ins = dbHandle
.prepare(`INSERT INTO tasks (description, group_id, created_by) VALUES ('Carrera complete', ?, ?)`)
.run(GROUP, U1);
taskId = Number(ins.lastInsertRowid);
// Iniciar dos servidores contra la misma DB
serverA = await startWebServer({
port: 19111,
env: { DB_PATH: tmp.path, DEV_DEFAULT_USER: U1, TZ: 'UTC' }
});
baseA = serverA.baseUrl;
serverB = await startWebServer({
port: 19112,
env: { DB_PATH: tmp.path, DEV_DEFAULT_USER: U2, TZ: 'UTC' }
});
baseB = serverB.baseUrl;
});
afterAll(async () => {
try {
await serverA.stop();
} catch {}
try {
await serverB.stop();
} catch {}
try {
cleanupDb?.();
} catch {}
});
it('solo una actualización de completed; la asignación incluye al menos al completador', async () => {
const [r1, r2] = await Promise.all([
fetch(`${baseA}/api/tasks/${taskId}/complete`, { method: 'POST' }),
fetch(`${baseB}/api/tasks/${taskId}/complete`, { method: 'POST' })
]);
expect([200, 200]).toContain(r1.status);
expect([200, 200]).toContain(r2.status);
const row = dbHandle
.prepare(`SELECT COALESCE(completed,0) as completed, completed_by FROM tasks WHERE id = ?`)
.get(taskId) as any;
expect(Number(row?.completed || 0)).toBe(1);
const completedBy = String(row?.completed_by || '');
const assigns = dbHandle
.prepare(`SELECT user_id FROM task_assignments WHERE task_id = ? ORDER BY assigned_at ASC`)
.all(taskId) as any[];
// Debe existir al menos una asignación y contener al que completó
expect(assigns.length >= 1 && assigns.length <= 2).toBe(true);
const assignedUsers = assigns.map((r) => String(r.user_id));
expect([U1, U2]).toContain(completedBy);
expect(assignedUsers).toContain(completedBy);
});
});