import { EventEmitter } from 'node:events'; import { access, writeFile } from 'node:fs/promises'; import { beforeEach, describe, expect, it, vi } from 'vitest'; const spawn = vi.hoisted(() => vi.fn()); vi.mock('node:child_process', () => ({ spawn, })); const { renderPdf } = await import('../src/pdf/render.js'); function child() { const proc = new EventEmitter(); proc.stderr = new EventEmitter(); proc.kill = vi.fn(); return proc; } describe('renderPdf', () => { beforeEach(() => { spawn.mockReset(); }); it('returns the PDF and removes the temp files', async () => { spawn.mockImplementation((_bin, args) => { const proc = child(); queueMicrotask(async () => { await writeFile(args[1], Buffer.from('%PDF-1.4')); proc.emit('close', 0); }); return proc; }); const pdf = await renderPdf('Agreement'); expect(pdf.subarray(0, 5).toString()).toBe('%PDF-'); expect(spawn).toHaveBeenCalledWith( 'weasyprint', expect.any(Array), expect.objectContaining({ stdio: ['ignore', 'ignore', 'pipe'] }), ); const htmlPath = spawn.mock.calls[0][1][0]; await expect(access(htmlPath)).rejects.toThrow(); }); it('reports a missing WeasyPrint binary', async () => { spawn.mockImplementation(() => { const proc = child(); queueMicrotask(() => { const error = new Error('spawn weasyprint ENOENT'); error.code = 'ENOENT'; proc.emit('error', error); }); return proc; }); await expect(renderPdf('')).rejects.toThrow('WeasyPrint is not installed'); }); });