/** * AcroForm-tier test for parseBerthPdf. Builds a synthetic PDF with named * AcroForm fields via pdf-lib and asserts the parser pulls them out without * needing OCR. */ import { describe, expect, it } from 'vitest'; import { PDFDocument } from 'pdf-lib'; import { parseBerthPdf } from '@/lib/services/berth-pdf-parser'; async function buildAcroFormPdf(): Promise { const doc = await PDFDocument.create(); doc.addPage([400, 400]); const form = doc.getForm(); const fields: Array<[string, string]> = [ ['mooring_number', 'A1'], ['length_ft', '206.67'], ['length_m', '63'], ['width_ft', '46.58'], ['width_m', '14.2'], ['power_capacity', '330'], ['voltage', '480'], ['weekly_rate_high_usd', '11341'], ['weekly_rate_low_usd', '8100'], ['daily_rate_high_usd', '1890'], ['daily_rate_low_usd', '1350'], ['pricing_valid_until', '2025-09-15'], ['bow_facing', 'East'], ['mooring_type', 'Side Pier / Med Mooring'], ]; for (const [name, value] of fields) { const field = form.createTextField(name); field.setText(value); } const bytes = await doc.save(); return Buffer.from(bytes); } describe('parseBerthPdf — AcroForm tier', () => { it('extracts named fields and skips OCR', async () => { const buf = await buildAcroFormPdf(); const result = await parseBerthPdf(buf, { skipOcr: true }); expect(result.engine).toBe('acroform'); expect(result.fields.mooringNumber?.value).toBe('A1'); expect(result.fields.lengthFt?.value).toBeCloseTo(206.67, 1); expect(result.fields.lengthM?.value).toBe(63); expect(result.fields.weeklyRateHighUsd?.value).toBe(11341); expect(result.fields.pricingValidUntil?.value).toBe('2025-09-15'); expect(result.fields.bowFacing?.value).toBe('East'); expect(result.meanConfidence).toBe(1); }); it('rejects a non-PDF buffer via magic-byte check', async () => { await expect(parseBerthPdf(Buffer.from('not a pdf'))).rejects.toThrow(/magic-byte/); }); });