// Runnable assertions for src/lib/kyc-match.ts (no test runner is configured). // node scripts/kyc-match.check.ts // Lives outside src/ so it isn't part of the `tsc -b` app build. import assert from 'node:assert/strict'; import { crossCheck, dobVerdict, nameVerdict, normName } from '../src/lib/kyc-match.ts'; let n = 0; const ok = (label: string, cond: boolean) => { n++; if (!cond) { console.error('FAIL:', label); process.exitCode = 1; } }; // normName: order-insensitive, honorific/punct strip assert.equal(normName('Mr. Ravi Kumar'), 'kumar ravi'); assert.equal(normName('KUMAR, RAVI'), 'kumar ravi'); // name: exact / case / order → match ok('exact name', nameVerdict('Ravi Kumar', 'ravi kumar').status === 'match'); ok('reordered name', nameVerdict('Ravi Kumar', 'Kumar Ravi').status === 'match'); // initials → match ok('initial expands', nameVerdict('R Kumar', 'Ravi Kumar').status === 'match'); ok('middle initial', nameVerdict('Ravi K Sharma', 'Ravi Kumar Sharma').status === 'match'); // typo / wrong person → mismatch ok('typo name', nameVerdict('Rabi Kumar', 'Ravi Kumar').status === 'mismatch'); ok('wrong person', nameVerdict('Ravi Kumar', 'Suresh Patel').status === 'mismatch'); ok('extra surname missing', nameVerdict('Ravi', 'Ravi Kumar').status === 'mismatch'); // empty side → unknown ok('empty ocr', nameVerdict('Ravi Kumar', '').status === 'unknown'); ok('empty captured', nameVerdict('', 'Ravi Kumar').status === 'unknown'); // DOB: captured IST-midnight instant ("…T18:30Z" → 1990-05-15 IST) vs OCR YYYY-MM-DD // (literal compare, no tz shift). Normalization is pinned to Asia/Kolkata. ok('dob match', dobVerdict('1990-05-14T18:30:00.000Z', '1990-05-15') === 'match'); ok('dob mismatch day', dobVerdict('1990-05-14T18:30:00.000Z', '1990-05-16') === 'mismatch'); ok('dob mismatch year', dobVerdict('1990-05-14T18:30:00.000Z', '1991-05-15') === 'mismatch'); // DD/MM/YYYY as a card may print ok('dob dd/mm/yyyy', dobVerdict('1990-05-14T18:30:00.000Z', '15/05/1990') === 'match'); // null / unparseable → unknown ok('dob null', dobVerdict('1990-05-14T18:30:00.000Z', null) === 'unknown'); ok('dob garbage', dobVerdict('1990-05-14T18:30:00.000Z', 'unknown') === 'unknown'); // aggregate const clean = crossCheck( { name: 'Ravi Kumar', dob: '1990-05-14T18:30:00.000Z' }, { pan: { name: 'RAVI KUMAR', dob: '1990-05-15' }, aadhaar: { name: 'Ravi Kumar', dob: '1990-05-15' } }, ); ok('clean: 4 checked', clean.fields.length === 4); ok('clean: no mismatch', !clean.hasMismatch && clean.anyChecked); const bad = crossCheck( { name: 'Ravi Kumar', dob: '1990-05-14T18:30:00.000Z' }, { pan: { name: 'Ravi Kumar', dob: '1990-05-15' }, aadhaar: { name: 'Suresh Patel', dob: '1985-01-01' } }, ); ok('bad: hasMismatch', bad.hasMismatch); ok('bad: 2 aadhaar mismatches', bad.fields.filter((f) => f.status === 'mismatch').length === 2); // nothing OCR'd yet const empty = crossCheck({ name: 'Ravi Kumar', dob: '1990-05-14T18:30:00.000Z' }, {}); ok('empty: nothing checked', !empty.anyChecked && !empty.hasMismatch); if (!process.exitCode) console.log(`kyc-match: all checks passed (${n} cases)`);