From f7d74c052398dc80759010e78e094658d546d210 Mon Sep 17 00:00:00 2001 From: Chandler Copeland Date: Sat, 21 Mar 2026 16:59:11 -0600 Subject: [PATCH] test(13-01): add failing aiCoordsToPagePdfSpace unit tests - Add ai-coords.test.ts with 3 test cases covering US Letter (612x792 pts) - Tests import from lib/ai/field-placement which does not exist yet (RED phase) - Cases: text field near top, checkbox near bottom-right, client-sig at center --- .../src/lib/pdf/__tests__/ai-coords.test.ts | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 teressa-copeland-homes/src/lib/pdf/__tests__/ai-coords.test.ts diff --git a/teressa-copeland-homes/src/lib/pdf/__tests__/ai-coords.test.ts b/teressa-copeland-homes/src/lib/pdf/__tests__/ai-coords.test.ts new file mode 100644 index 0000000..0207406 --- /dev/null +++ b/teressa-copeland-homes/src/lib/pdf/__tests__/ai-coords.test.ts @@ -0,0 +1,91 @@ +/** + * Unit tests for aiCoordsToPagePdfSpace — AI top-left percentage coordinates to PDF bottom-left points. + * + * AI models return positions with top-left origin (0,0 = top-left corner of page). + * PDF user space uses bottom-left origin (0,0 = bottom-left corner of page). + * The conversion must flip the Y axis and multiply percentages by page dimensions. + * + * US Letter: 612 × 792 pts at 72 DPI. + */ + +import { aiCoordsToPagePdfSpace } from '../../../lib/ai/field-placement'; + +const US_LETTER_W = 612; // pts +const US_LETTER_H = 792; // pts + +describe('aiCoordsToPagePdfSpace — AI top-left percentage to PDF bottom-left points', () => { + test('text field near top of page', () => { + // xPct=10, yPct=5, widthPct=30, heightPct=5 + // x = 612 * 0.10 = 61.2 + // fieldH = 792 * 0.05 = 39.6 + // screenY = 792 * 0.05 = 39.6 + // y = 792 - 39.6 - 39.6 = 712.8 + const result = aiCoordsToPagePdfSpace( + { + page: 1, + fieldType: 'text', + xPct: 10, + yPct: 5, + widthPct: 30, + heightPct: 5, + prefillValue: '', + }, + US_LETTER_W, + US_LETTER_H, + ); + expect(result.x).toBeCloseTo(61.2, 1); + expect(result.y).toBeCloseTo(712.8, 1); + expect(result.width).toBeCloseTo(183.6, 1); + expect(result.height).toBeCloseTo(39.6, 1); + }); + + test('checkbox near bottom-right', () => { + // xPct=90, yPct=95, widthPct=3, heightPct=3 + // x = 612 * 0.90 = 550.8 + // fieldH = 792 * 0.03 = 23.76 + // screenY = 792 * 0.95 = 752.4 + // y = 792 - 752.4 - 23.76 = 15.84 + const result = aiCoordsToPagePdfSpace( + { + page: 1, + fieldType: 'checkbox', + xPct: 90, + yPct: 95, + widthPct: 3, + heightPct: 3, + prefillValue: '', + }, + US_LETTER_W, + US_LETTER_H, + ); + expect(result.x).toBeCloseTo(550.8, 1); + expect(result.y).toBeCloseTo(15.84, 1); + expect(result.width).toBeCloseTo(18.36, 1); + expect(result.height).toBeCloseTo(23.76, 1); + }); + + test('client-signature field at exact center', () => { + // xPct=50, yPct=50, widthPct=20, heightPct=5 + // x = 612 * 0.50 = 306 + // fieldH = 792 * 0.05 = 39.6 + // screenY = 792 * 0.50 = 396 + // y = 792 - 396 - 39.6 = 356.4 + const result = aiCoordsToPagePdfSpace( + { + page: 1, + fieldType: 'client-signature', + xPct: 50, + yPct: 50, + widthPct: 20, + heightPct: 5, + prefillValue: '', + }, + US_LETTER_W, + US_LETTER_H, + ); + expect(result.x).toBeCloseTo(306, 1); + expect(result.y).toBeCloseTo(356.4, 1); + expect(result.width).toBeCloseTo(122.4, 1); + expect(result.height).toBeCloseTo(39.6, 1); + }); +});