import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest'; import { PrismaClient } from '@prisma/client'; import { resetDb } from '../test-utils/reset-db'; import { TemplateRepository } from './template.repository'; import { TemplateService } from './template.service'; import { TemplateNotFoundError } from './template.repository'; import type { PrismaService } from '../prisma/prisma.service'; const url = process.env.DATABASE_URL ?? 'postgresql://iios:iios@localhost:5434/iios?schema=public'; const prisma = new PrismaClient({ datasources: { db: { url } } }); const svc = new TemplateService(new TemplateRepository(prisma as unknown as PrismaService)); beforeAll(async () => { await prisma.$connect(); }); afterAll(async () => { await prisma.$disconnect(); }); beforeEach(async () => { await resetDb(prisma); }); describe('TemplateService.render', () => { it('resolves a stored template and renders it, with provenance', async () => { await prisma.iiosMessageTemplate.create({ data: { key: 'welcome', channel: 'EMAIL', locale: 'en', version: 2, subject: 'Hi {{firstName}}', bodyHtml: '

{{firstName}}

', variables: ['firstName'] }, }); const { content, provenance } = await svc.render({ key: 'welcome' }, { firstName: 'Dana' }, { channel: 'EMAIL' }); expect(content.subject).toBe('Hi Dana'); expect(content.html).toBe('

Dana

'); expect(provenance).toMatchObject({ templateKey: 'welcome', templateVersion: 2, templateLocale: 'en' }); expect(provenance.renderedHash).toMatch(/^[a-f0-9]{64}$/); }); it('renders an inline source without a DB row (key/version null)', async () => { const { content, provenance } = await svc.render( { inline: { subject: 'Ad-hoc {{x}}', html: '{{x}}', variables: ['x'] } }, { x: 'Y' }, { channel: 'EMAIL' }, ); expect(content.subject).toBe('Ad-hoc Y'); expect(content.html).toBe('Y'); expect(provenance.templateKey).toBeNull(); expect(provenance.templateVersion).toBeNull(); expect(provenance.renderedHash).toMatch(/^[a-f0-9]{64}$/); }); it('pins to an explicit version when asked', async () => { await prisma.iiosMessageTemplate.create({ data: { key: 'k', channel: 'EMAIL', locale: 'en', version: 1, bodyText: 'v1' } }); await prisma.iiosMessageTemplate.create({ data: { key: 'k', channel: 'EMAIL', locale: 'en', version: 2, bodyText: 'v2' } }); const latest = await svc.render({ key: 'k' }, {}, { channel: 'EMAIL' }); const pinned = await svc.render({ key: 'k', version: 1 }, {}, { channel: 'EMAIL' }); expect(latest.content.text).toBe('v2'); expect(pinned.content.text).toBe('v1'); expect(pinned.provenance.templateVersion).toBe(1); }); it('throws for an unknown stored key', async () => { await expect(svc.render({ key: 'missing' }, {}, { channel: 'EMAIL' })).rejects.toBeInstanceOf(TemplateNotFoundError); }); });