import { describe, it, expect, beforeEach } from 'vitest'; import { eq } from 'drizzle-orm'; import { createApp } from '../../src/app'; import { db } from '../../src/db/client'; import { workSessions } from '../../src/db/schema'; import { authToken, bearer, seedActivity, resetDb } from '../helpers'; const WIDE = `from=${new Date('2000-01-01').toISOString()}&to=${new Date('2100-01-01').toISOString()}`; describe('admin↔worker session lifecycle (worker starts → admin stops → report + export)', () => { beforeEach(resetDb); it('an admin-stopped worker session lands in the report and export with correct totals', async () => { const app = createApp(); const adminTok = await authToken(app, 'admin-ws-admin@example.com', 'admin'); const workerTok = await authToken(app, 'admin-ws-worker@example.com'); // worker const activityId = await seedActivity('Frezen', ['Kurk']); // Worker starts a session. const started = await ( await app.request('/api/sessions/start', { method: 'POST', headers: bearer(workerTok), body: JSON.stringify({ activity_id: activityId, insole_type: 'Kurk', pair_count: 3 }), }) ).json(); // Back-date the start so the admin stop yields a deterministic-ish worked span. await db .update(workSessions) .set({ startTime: new Date(Date.now() - 120000) }) .where(eq(workSessions.id, started.id)); // Admin stops it via the admin endpoint. const stopRes = await app.request(`/api/admin/sessions/${started.id}/stop`, { method: 'POST', headers: bearer(adminTok), }); expect(stopRes.status).toBe(200); const stopped = await stopRes.json(); expect(stopped.status).toBe('completed'); expect(stopped.duration_seconds).toBeGreaterThanOrEqual(120); // The session shows up in the admin report with totals matching the stored row. const report = await ( await app.request(`/api/admin/report?${WIDE}`, { headers: bearer(adminTok) }) ).json(); expect(report.totals.sessions).toBe(1); expect(report.totals.worked_seconds).toBe(stopped.duration_seconds); expect(report.totals.pairs).toBe(3); expect(report.by_worker).toHaveLength(1); expect(report.by_worker[0].user_name).toBe('admin-ws-worker'); expect(report.by_worker[0].worked_seconds).toBe(stopped.duration_seconds); expect(report.by_activity).toHaveLength(1); expect(report.by_activity[0].activity_name).toBe('Frezen'); expect(report.by_type).toHaveLength(1); expect(report.by_type[0].insole_type).toBe('Kurk'); // And in the all-users export CSV (header + the one row, with the Worker column). const csvRes = await app.request(`/api/admin/export?${WIDE}`, { headers: bearer(adminTok) }); expect(csvRes.status).toBe(200); const lines = (await csvRes.text()).trim().split('\n'); expect(lines).toHaveLength(2); expect(lines[0]).toContain('"Worker"'); expect(lines[1]).toContain('admin-ws-worker'); expect(lines[1]).toContain('Frezen'); }); });