import { afterEach, describe, expect, it } from 'vitest'; import { createServer } from '../src/app.js'; import { db } from '../src/db/knex.js'; import { clearOutbox, outbox } from '../src/services/mail.js'; import { truncateTables } from './truncate.js'; const email = 'consent-doctor@example.com'; const answers = { voluntary_withdraw: true, mou_required: true, eligibility_six_months: true, confidential_research: true, web_questionnaire: true, no_intervention: true, aggregated_reporting: true, honorarium: true, agree_participate: true, }; /** * @param {import('@hapi/hapi').ServerInjectResponse} response */ function userCookie(response) { const raw = response.headers['set-cookie']; const headers = Array.isArray(raw) ? raw : raw ? [raw] : []; const match = headers.find((header) => header.startsWith('user_token=')); return match ? match.split(';')[0] : null; } describe('consent', () => { /** @type {import('@hapi/hapi').Server | undefined} */ let server; afterEach(async () => { clearOutbox(); await server?.stop(); await truncateTables(); }); async function start() { server = await createServer(); return server; } async function login(api) { await api.inject({ method: 'POST', url: '/api/auth/otp/request', payload: { email }, }); const verified = await api.inject({ method: 'POST', url: '/api/auth/otp/verify', payload: { email, otp: outbox[0].otp }, }); return userCookie(verified); } it('submits consent and advances nextStep to agreement', async () => { const api = await start(); const cookie = await login(api); const before = await api.inject({ method: 'GET', url: '/api/me', headers: { cookie }, }); expect(before.result.nextStep).toBe('consent'); const submitted = await api.inject({ method: 'POST', url: '/api/consent', headers: { cookie }, payload: { participant_name: 'Dr Consent Test', consent_date: '2026-10-16', answers, }, }); expect(submitted.statusCode).toBe(200); expect(submitted.result).toMatchObject({ participant_name: 'Dr Consent Test', consent_date: '2026-10-16', }); const me = await api.inject({ method: 'GET', url: '/api/me', headers: { cookie }, }); expect(me.result.steps.consent.done).toBe(true); expect(me.result.nextStep).toBe('agreement'); expect(me.result.user.name).toBe('Dr Consent Test'); const again = await api.inject({ method: 'POST', url: '/api/consent', headers: { cookie }, payload: { participant_name: 'Dr Consent Test', consent_date: '2026-10-16', answers, }, }); expect(again.statusCode).toBe(409); const row = await db('consents').where({ participant_name: 'Dr Consent Test' }).first(); expect(row).toBeTruthy(); }); it('rejects incomplete consent answers', async () => { const api = await start(); const cookie = await login(api); const response = await api.inject({ method: 'POST', url: '/api/consent', headers: { cookie }, payload: { participant_name: 'Dr Consent Test', consent_date: '2026-10-16', answers: { ...answers, eligibility_six_months: false }, }, }); expect(response.statusCode).toBe(400); }); });