import { randomUUID } from 'node:crypto'; import argon2 from 'argon2'; import ExcelJS from 'exceljs'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { createServer } from '../src/app.js'; import { db } from '../src/db/knex.js'; import { seedSurveyDefinition } from '../src/survey/seed.js'; import { truncateTables } from './truncate.js'; const email = 'export-admin@example.com'; const password = 'correct-password'; /** * @param {import('@hapi/hapi').ServerInjectResponse} response */ function sessionCookie(response) { const raw = response.headers['set-cookie']; const header = Array.isArray(raw) ? raw[0] : raw; return header.split(';')[0]; } describe('survey export', () => { /** @type {import('@hapi/hapi').Server | undefined} */ let server; beforeEach(async () => { await seedSurveyDefinition(); }); afterEach(async () => { await server?.stop(); await truncateTables(); }); it('writes response headers, question ids, and choice counts', async () => { server = await createServer(); await db('admin_users').insert({ name: 'Administrator', email, password_hash: await argon2.hash(password, { type: argon2.argon2id }), is_active: true, }); const login = await server.inject({ method: 'POST', url: '/api/admin/auth/login', payload: { email, password }, }); const definitionId = await seedSurveyDefinition(); const [applicationId] = await db('applications').insert({ public_id: randomUUID(), email: 'physician@example.com', status: 'APPROVED', full_name: 'Asha Rao', registration_no: 'MMC-100', version: 1, }); await db('survey_responses').insert({ application_id: applicationId, survey_definition_id: definitionId, answers: JSON.stringify({ adherence_comparison: { choice: 'much_better' }, pack_split: { regular_pmdi: { asthma: 25, copd: 25 }, regular_rotacap: { asthma: 25, copd: 25 }, extended_pmdi: { asthma: 25, copd: 25 }, extended_rotacap: { asthma: 25, copd: 25 }, }, }), status: 'COMPLETED', started_at: new Date(), completed_at: new Date(), }); const response = await server.inject({ method: 'GET', url: '/api/admin/survey/export?status=COMPLETED', headers: { cookie: sessionCookie(login) }, }); expect(response.statusCode).toBe(200); expect(response.headers['content-disposition']).toContain('survey-responses.xlsx'); const workbook = new ExcelJS.Workbook(); await workbook.xlsx.load(response.rawPayload); const responses = workbook.getWorksheet('Responses'); const headers = responses.getRow(1).values.slice(1); expect(headers).toContain('Prescribing % - Extended-Dose Rotacap - COPD'); const column = headers.indexOf('Prescribing % - Extended-Dose Rotacap - COPD') + 1; expect(responses.getRow(2).getCell(column).value).toBe(25); const questions = workbook.getWorksheet('Questions'); const questionIds = questions.getColumn(1).values; expect(questionIds).toContain('pack_split'); const summary = workbook.getWorksheet('Summary'); const summaryText = summary.getSheetValues().flat().join(' '); expect(summaryText).toContain('Much better'); expect(summaryText).toContain('1'); expect(await db('audit_log').where({ action: 'SURVEY_EXPORTED' }).first()).toBeTruthy(); }); });