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.
147 lines
5.5 KiB
TypeScript
147 lines
5.5 KiB
TypeScript
import { beforeEach, afterEach, describe, expect, it } from 'bun:test';
|
|
import { createTempDb } from './helpers/db';
|
|
|
|
// Reutilizamos el estilo de import dinámico del handler como en otros tests web.
|
|
|
|
describe('Web API - completar tarea (rutas de error y gating)', () => {
|
|
let cleanup: () => void;
|
|
let db: any;
|
|
let path: string;
|
|
|
|
const USER = '34600123456';
|
|
const GROUP_ID = '12345-67890@g.us';
|
|
|
|
beforeEach(() => {
|
|
const tmp = createTempDb();
|
|
cleanup = tmp.cleanup;
|
|
db = tmp.db;
|
|
path = tmp.path;
|
|
|
|
process.env.NODE_ENV = 'test';
|
|
process.env.DB_PATH = path;
|
|
process.env.REACTIONS_ENABLED = 'true';
|
|
process.env.REACTIONS_SCOPE = 'groups';
|
|
process.env.REACTIONS_TTL_DAYS = '14';
|
|
process.env.GROUP_GATING_MODE = 'enforce';
|
|
});
|
|
|
|
afterEach(async () => {
|
|
try {
|
|
const { closeDb } = await import('../../apps/web/src/lib/server/db.ts');
|
|
closeDb();
|
|
} catch {}
|
|
if (cleanup) cleanup();
|
|
delete process.env.DB_PATH;
|
|
delete process.env.REACTIONS_ENABLED;
|
|
delete process.env.REACTIONS_SCOPE;
|
|
delete process.env.REACTIONS_TTL_DAYS;
|
|
delete process.env.GROUP_GATING_MODE;
|
|
});
|
|
|
|
it('401 si no hay session (userId)', async () => {
|
|
const event: any = {
|
|
locals: { userId: null },
|
|
params: { id: '1' },
|
|
request: new Request('http://localhost', { method: 'POST' })
|
|
};
|
|
const { POST: completeHandler } = await import('../../apps/web/src/routes/api/tasks/[id]/complete/+server.ts');
|
|
const res = await completeHandler(event);
|
|
expect(res.status).toBe(401);
|
|
});
|
|
|
|
it('400 si id no es válido', async () => {
|
|
const event: any = {
|
|
locals: { userId: USER },
|
|
params: { id: 'abc' },
|
|
request: new Request('http://localhost', { method: 'POST' })
|
|
};
|
|
const { POST: completeHandler } = await import('../../apps/web/src/routes/api/tasks/[id]/complete/+server.ts');
|
|
const res = await completeHandler(event);
|
|
expect(res.status).toBe(400);
|
|
});
|
|
|
|
it('404 si la tarea no existe', async () => {
|
|
const event: any = {
|
|
locals: { userId: USER },
|
|
params: { id: '999999' },
|
|
request: new Request('http://localhost', { method: 'POST' })
|
|
};
|
|
// Sembrar usuario para evitar FKs indirectas (no imprescindible aquí)
|
|
db.prepare(`INSERT OR IGNORE INTO users (id) VALUES (?)`).run(USER);
|
|
|
|
const { POST: completeHandler } = await import('../../apps/web/src/routes/api/tasks/[id]/complete/+server.ts');
|
|
const res = await completeHandler(event);
|
|
expect(res.status).toBe(404);
|
|
});
|
|
|
|
it('403 si grupo no allowed', async () => {
|
|
db.prepare(`INSERT OR IGNORE INTO users (id) VALUES (?)`).run(USER);
|
|
// Asegurar fila del grupo para satisfacer FKs (sin marcarlo como allowed)
|
|
db.prepare(`INSERT OR IGNORE INTO groups (id, community_id, name, active) VALUES (?, 'comm', 'G', 1)`).run(GROUP_ID);
|
|
// Tarea con group_id; no insertamos en allowed_groups
|
|
const taskId = Number(
|
|
db.prepare(`
|
|
INSERT INTO tasks (description, due_date, group_id, created_by, completed, completed_at)
|
|
VALUES ('No allowed', NULL, ?, ?, 0, NULL)
|
|
`).run(GROUP_ID, USER).lastInsertRowid
|
|
);
|
|
|
|
// El usuario podría incluso ser miembro activo; sigue siendo 403 por falta de allowed
|
|
db.prepare(`INSERT OR REPLACE INTO group_members (group_id, user_id, is_admin, is_active) VALUES (?, ?, 0, 1)`).run(GROUP_ID, USER);
|
|
|
|
const event: any = {
|
|
locals: { userId: USER },
|
|
params: { id: String(taskId) },
|
|
request: new Request('http://localhost', { method: 'POST' })
|
|
};
|
|
const { POST: completeHandler } = await import('../../apps/web/src/routes/api/tasks/[id]/complete/+server.ts');
|
|
const res = await completeHandler(event);
|
|
expect(res.status).toBe(403);
|
|
});
|
|
|
|
it('403 si grupo allowed pero usuario no es miembro activo', async () => {
|
|
db.prepare(`INSERT OR IGNORE INTO users (id) VALUES (?)`).run(USER);
|
|
db.prepare(`INSERT OR IGNORE INTO groups (id, community_id, name, active) VALUES (?, 'comm', 'G', 1)`).run(GROUP_ID);
|
|
db.prepare(`INSERT OR REPLACE INTO allowed_groups (group_id, label, status) VALUES (?, 'G', 'allowed')`).run(GROUP_ID);
|
|
|
|
const taskId = Number(
|
|
db.prepare(`
|
|
INSERT INTO tasks (description, due_date, group_id, created_by, completed, completed_at)
|
|
VALUES ('No active member', NULL, ?, ?, 0, NULL)
|
|
`).run(GROUP_ID, USER).lastInsertRowid
|
|
);
|
|
|
|
// No sembramos group_members activo para USER
|
|
|
|
const event: any = {
|
|
locals: { userId: USER },
|
|
params: { id: String(taskId) },
|
|
request: new Request('http://localhost', { method: 'POST' })
|
|
};
|
|
const { POST: completeHandler } = await import('../../apps/web/src/routes/api/tasks/[id]/complete/+server.ts');
|
|
const res = await completeHandler(event);
|
|
expect(res.status).toBe(403);
|
|
});
|
|
|
|
it('403 en tarea personal si no está asignada al usuario', async () => {
|
|
db.prepare(`INSERT OR IGNORE INTO users (id) VALUES (?)`).run(USER);
|
|
const taskId = Number(
|
|
db.prepare(`
|
|
INSERT INTO tasks (description, due_date, group_id, created_by, completed, completed_at)
|
|
VALUES ('Personal sin asignación', NULL, NULL, ?, 0, NULL)
|
|
`).run(USER).lastInsertRowid
|
|
);
|
|
|
|
// No insertamos task_assignments
|
|
|
|
const event: any = {
|
|
locals: { userId: USER },
|
|
params: { id: String(taskId) },
|
|
request: new Request('http://localhost', { method: 'POST' })
|
|
};
|
|
const { POST: completeHandler } = await import('../../apps/web/src/routes/api/tasks/[id]/complete/+server.ts');
|
|
const res = await completeHandler(event);
|
|
expect(res.status).toBe(403);
|
|
});
|
|
});
|