const request = require('supertest'); const { app } = require('../../backend/server'); const { cleanDb, getAuthHeader, seedSession } = require('../helpers/test-utils'); describe('GET /api/sessions — filter and limit', () => { beforeEach(() => { cleanDb(); }); test('default filter excludes archived sessions', async () => { seedSession({ is_active: 0, notes: null }); const archived = seedSession({ is_active: 0, notes: null }); require('../helpers/test-utils').db.prepare( 'UPDATE sessions SET archived = 1 WHERE id = ?' ).run(archived.id); const res = await request(app).get('/api/sessions'); expect(res.status).toBe(200); expect(res.body).toHaveLength(1); expect(res.body[0].archived).toBe(0); }); test('filter=archived returns only archived sessions', async () => { seedSession({ is_active: 0, notes: null }); const archived = seedSession({ is_active: 0, notes: null }); require('../helpers/test-utils').db.prepare( 'UPDATE sessions SET archived = 1 WHERE id = ?' ).run(archived.id); const res = await request(app).get('/api/sessions?filter=archived'); expect(res.status).toBe(200); expect(res.body).toHaveLength(1); expect(res.body[0].archived).toBe(1); }); test('filter=all returns all sessions', async () => { seedSession({ is_active: 0, notes: null }); const archived = seedSession({ is_active: 0, notes: null }); require('../helpers/test-utils').db.prepare( 'UPDATE sessions SET archived = 1 WHERE id = ?' ).run(archived.id); const res = await request(app).get('/api/sessions?filter=all'); expect(res.status).toBe(200); expect(res.body).toHaveLength(2); }); test('limit restricts number of sessions returned', async () => { for (let i = 0; i < 10; i++) { seedSession({ is_active: 0, notes: null }); } const res = await request(app).get('/api/sessions?filter=all&limit=3'); expect(res.status).toBe(200); expect(res.body).toHaveLength(3); }); test('limit=all returns all sessions', async () => { for (let i = 0; i < 10; i++) { seedSession({ is_active: 0, notes: null }); } const res = await request(app).get('/api/sessions?filter=all&limit=all'); expect(res.status).toBe(200); expect(res.body).toHaveLength(10); }); test('X-Total-Count header reflects total matching sessions before limit', async () => { for (let i = 0; i < 10; i++) { seedSession({ is_active: 0, notes: null }); } const res = await request(app).get('/api/sessions?filter=all&limit=3'); expect(res.headers['x-total-count']).toBe('10'); expect(res.body).toHaveLength(3); }); test('response includes archived field on each session', async () => { seedSession({ is_active: 0, notes: null }); const res = await request(app).get('/api/sessions?filter=all'); expect(res.status).toBe(200); expect(res.body[0]).toHaveProperty('archived', 0); }); test('default limit is all when no limit param provided', async () => { for (let i = 0; i < 8; i++) { seedSession({ is_active: 0, notes: null }); } const res = await request(app).get('/api/sessions?filter=all'); expect(res.status).toBe(200); expect(res.body).toHaveLength(8); }); }); describe('POST /api/sessions/:id/archive', () => { beforeEach(() => { cleanDb(); }); test('archives a closed session', async () => { const session = seedSession({ is_active: 0, notes: null }); const res = await request(app) .post(`/api/sessions/${session.id}/archive`) .set('Authorization', getAuthHeader()); expect(res.status).toBe(200); expect(res.body.success).toBe(true); const check = await request(app).get(`/api/sessions/${session.id}`); expect(check.body.archived).toBe(1); }); test('returns 400 for active session', async () => { const session = seedSession({ is_active: 1, notes: null }); const res = await request(app) .post(`/api/sessions/${session.id}/archive`) .set('Authorization', getAuthHeader()); expect(res.status).toBe(400); }); test('returns 404 for non-existent session', async () => { const res = await request(app) .post('/api/sessions/9999/archive') .set('Authorization', getAuthHeader()); expect(res.status).toBe(404); }); test('returns 401 without auth', async () => { const session = seedSession({ is_active: 0, notes: null }); const res = await request(app) .post(`/api/sessions/${session.id}/archive`); expect(res.status).toBe(401); }); }); describe('POST /api/sessions/:id/unarchive', () => { beforeEach(() => { cleanDb(); }); test('unarchives an archived session', async () => { const session = seedSession({ is_active: 0, notes: null }); require('../helpers/test-utils').db.prepare( 'UPDATE sessions SET archived = 1 WHERE id = ?' ).run(session.id); const res = await request(app) .post(`/api/sessions/${session.id}/unarchive`) .set('Authorization', getAuthHeader()); expect(res.status).toBe(200); expect(res.body.success).toBe(true); const check = await request(app).get(`/api/sessions/${session.id}`); expect(check.body.archived).toBe(0); }); test('returns 404 for non-existent session', async () => { const res = await request(app) .post('/api/sessions/9999/unarchive') .set('Authorization', getAuthHeader()); expect(res.status).toBe(404); }); }); describe('POST /api/sessions/bulk', () => { beforeEach(() => { cleanDb(); }); test('bulk archive multiple sessions', async () => { const s1 = seedSession({ is_active: 0, notes: null }); const s2 = seedSession({ is_active: 0, notes: null }); const res = await request(app) .post('/api/sessions/bulk') .set('Authorization', getAuthHeader()) .send({ action: 'archive', ids: [s1.id, s2.id] }); expect(res.status).toBe(200); expect(res.body.success).toBe(true); expect(res.body.affected).toBe(2); const list = await request(app).get('/api/sessions?filter=archived'); expect(list.body).toHaveLength(2); }); test('bulk unarchive multiple sessions', async () => { const s1 = seedSession({ is_active: 0, notes: null }); const s2 = seedSession({ is_active: 0, notes: null }); const db = require('../helpers/test-utils').db; db.prepare('UPDATE sessions SET archived = 1 WHERE id IN (?, ?)').run(s1.id, s2.id); const res = await request(app) .post('/api/sessions/bulk') .set('Authorization', getAuthHeader()) .send({ action: 'unarchive', ids: [s1.id, s2.id] }); expect(res.status).toBe(200); expect(res.body.affected).toBe(2); const list = await request(app).get('/api/sessions?filter=all'); expect(list.body.every(s => s.archived === 0)).toBe(true); }); test('bulk delete multiple sessions', async () => { const s1 = seedSession({ is_active: 0, notes: null }); const s2 = seedSession({ is_active: 0, notes: null }); const res = await request(app) .post('/api/sessions/bulk') .set('Authorization', getAuthHeader()) .send({ action: 'delete', ids: [s1.id, s2.id] }); expect(res.status).toBe(200); expect(res.body.affected).toBe(2); const list = await request(app).get('/api/sessions?filter=all'); expect(list.body).toHaveLength(0); }); test('rejects archive of active sessions', async () => { const active = seedSession({ is_active: 1, notes: null }); const closed = seedSession({ is_active: 0, notes: null }); const res = await request(app) .post('/api/sessions/bulk') .set('Authorization', getAuthHeader()) .send({ action: 'archive', ids: [active.id, closed.id] }); expect(res.status).toBe(400); expect(res.body.activeIds).toContain(active.id); const list = await request(app).get('/api/sessions?filter=all'); expect(list.body).toHaveLength(2); expect(list.body.every(s => s.archived === 0)).toBe(true); }); test('rejects delete of active sessions', async () => { const active = seedSession({ is_active: 1, notes: null }); const res = await request(app) .post('/api/sessions/bulk') .set('Authorization', getAuthHeader()) .send({ action: 'delete', ids: [active.id] }); expect(res.status).toBe(400); }); test('returns 400 for empty ids array', async () => { const res = await request(app) .post('/api/sessions/bulk') .set('Authorization', getAuthHeader()) .send({ action: 'archive', ids: [] }); expect(res.status).toBe(400); }); test('returns 400 for invalid action', async () => { const res = await request(app) .post('/api/sessions/bulk') .set('Authorization', getAuthHeader()) .send({ action: 'nuke', ids: [1] }); expect(res.status).toBe(400); }); test('returns 400 for non-array ids', async () => { const res = await request(app) .post('/api/sessions/bulk') .set('Authorization', getAuthHeader()) .send({ action: 'archive', ids: 'not-array' }); expect(res.status).toBe(400); }); test('returns 404 if any session ID does not exist', async () => { const s1 = seedSession({ is_active: 0, notes: null }); const res = await request(app) .post('/api/sessions/bulk') .set('Authorization', getAuthHeader()) .send({ action: 'archive', ids: [s1.id, 9999] }); expect(res.status).toBe(404); }); test('returns 401 without auth', async () => { const res = await request(app) .post('/api/sessions/bulk') .send({ action: 'archive', ids: [1] }); expect(res.status).toBe(401); }); });