'use strict'; /** * Integration tests: DELETE /api/admin/sessions/:id * Covers: session removal + cascade, audit entry, 404 for missing, 403 for non-admin. */ const { describe, it, before, after } = require('node:test'); const assert = require('node:assert/strict'); const { db, inject, getToken, cleanup } = require('./setup'); after(() => cleanup()); describe('Admin Session Delete', () => { let adminToken, studentUser, subjectId, sessionId; before(async () => { const a = await getToken('admin'); adminToken = a.token; const s = await getToken('student'); studentUser = s; // Ensure subject exists let subj = db.prepare("SELECT id FROM subjects WHERE slug = 'admin-sess-test'").get(); if (!subj) { db.prepare("INSERT INTO subjects (slug, name, icon) VALUES ('admin-sess-test', 'Admin Sess Test', 'test')").run(); subj = db.prepare("SELECT id FROM subjects WHERE slug = 'admin-sess-test'").get(); } subjectId = subj.id; // Create a question with options const qId = db.prepare( 'INSERT INTO questions (subject_id, text, difficulty) VALUES (?, ?, 1)' ).run(subjectId, 'Admin session delete test question').lastInsertRowid; db.prepare('INSERT INTO options (question_id, text, is_correct) VALUES (?, ?, 0)').run(qId, 'Wrong'); db.prepare('INSERT INTO options (question_id, text, is_correct) VALUES (?, ?, 1)').run(qId, 'Correct'); // Start a session via API const sessRes = await inject('POST', '/api/sessions', { subject_slug: 'admin-sess-test', count: 1, mode: 'exam', }, studentUser.token); assert.equal(sessRes.status, 201, `session create failed: ${JSON.stringify(sessRes.body)}`); sessionId = sessRes.body.session_id; // Answer to create user_answers row const q = sessRes.body.questions[0]; await inject('POST', `/api/sessions/${sessionId}/answer`, { question_id: q.id, option_id: q.options[0].id, }, studentUser.token); }); // ── 1. Non-admin gets 403 ──────────────────────────────────────────────── it('student gets 403 when trying to delete a session', async () => { const res = await inject('DELETE', `/api/admin/sessions/${sessionId}`, null, studentUser.token); assert.equal(res.status, 403, `expected 403, got ${res.status}`); }); // ── 2. 404 for non-existent session ───────────────────────────────────── it('returns 404 for non-existent session id', async () => { const res = await inject('DELETE', '/api/admin/sessions/999999', null, adminToken); assert.equal(res.status, 404, `expected 404, got ${res.status}: ${JSON.stringify(res.body)}`); }); // ── 3. Session delete cascades user_answers and session_questions ───────── it('deletes session and cascades related rows', async () => { // Verify rows exist before delete const answersBefore = db.prepare('SELECT COUNT(*) AS n FROM user_answers WHERE session_id = ?') .get(sessionId).n; const sqBefore = db.prepare('SELECT COUNT(*) AS n FROM session_questions WHERE session_id = ?') .get(sessionId).n; // The session must still exist const sessBefore = db.prepare('SELECT id FROM test_sessions WHERE id = ?').get(sessionId); assert.ok(sessBefore, 'session should exist before delete'); const res = await inject('DELETE', `/api/admin/sessions/${sessionId}`, null, adminToken); assert.equal(res.status, 200, `expected 200, got ${res.status}: ${JSON.stringify(res.body)}`); assert.equal(res.body.ok, true); // Session gone const sessAfter = db.prepare('SELECT id FROM test_sessions WHERE id = ?').get(sessionId); assert.equal(sessAfter, undefined, 'session should be deleted'); // user_answers gone const answersAfter = db.prepare('SELECT COUNT(*) AS n FROM user_answers WHERE session_id = ?') .get(sessionId).n; assert.equal(answersAfter, 0, 'user_answers should be cleared after session delete'); // session_questions gone const sqAfter = db.prepare('SELECT COUNT(*) AS n FROM session_questions WHERE session_id = ?') .get(sessionId).n; assert.equal(sqAfter, 0, 'session_questions should be cleared after session delete'); }); // ── 4. Audit entry created on delete ───────────────────────────────────── it('creates audit log entry on session delete', async () => { // Create and immediately delete another session const sessRes = await inject('POST', '/api/sessions', { subject_slug: 'admin-sess-test', count: 1, mode: 'practice', }, studentUser.token); assert.equal(sessRes.status, 201); const newSessId = sessRes.body.session_id; const countBefore = db.prepare( "SELECT COUNT(*) AS n FROM admin_audit_log WHERE action = 'session.delete'" ).get().n; await inject('DELETE', `/api/admin/sessions/${newSessId}`, null, adminToken); const countAfter = db.prepare( "SELECT COUNT(*) AS n FROM admin_audit_log WHERE action = 'session.delete'" ).get().n; assert.ok(countAfter > countBefore, 'Expected session.delete audit entry to be created'); }); });