import { computeRucDv } from '@impuestos/rules'; import { describe, expect, it } from 'vitest'; import { lookupNumber } from './index'; const NOW = new Date('2026-09-03T12:00:00Z'); describe('lookupNumber', () => { it('validates a RUC and derives the filing day from the base', () => { const dv = computeRucDv('4123456'); const result = lookupNumber(`4123456-${dv}`, NOW); expect(result.valid).toBe(true); expect(result.docType).toBe('ruc'); expect(result.base).toBe('4123456'); expect(result.dv).toBe(dv); // Base ends in 6, and RULES.md maps digit 6 to the 19th. expect(result.deadlineDigit).toBe(6); expect(result.deadlineDay).toBe(19); }); it('returns the next three monthly deadlines in order', () => { const dv = computeRucDv('4123456'); const result = lookupNumber(`4123456-${dv}`, NOW); expect(result.nextDeadlines).toHaveLength(3); // 2026-09-19 is a Saturday, so the first rolls to the Monday. expect(result.nextDeadlines).toEqual(['2026-09-21', '2026-10-19', '2026-11-19']); expect([...result.nextDeadlines].sort()).toEqual(result.nextDeadlines); }); it('reads a bare number as a CI, which individuals may type either way', () => { const result = lookupNumber('4123456', NOW); expect(result.valid).toBe(true); expect(result.docType).toBe('ci'); expect(result.dv).toBeNull(); expect(result.deadlineDay).toBe(19); }); it('reports a wrong check digit as invalid rather than as an error', () => { const dv = computeRucDv('4123456'); const result = lookupNumber(`4123456-${(dv + 1) % 10}`, NOW); expect(result.valid).toBe(false); expect(result.base).toBe('4123456'); }); it('tolerates the dots and spaces people actually type', () => { const dv = computeRucDv('4123456'); expect(lookupNumber(` 4.123.456-${dv} `, NOW).valid).toBe(true); }); it('rejects letters and over long numbers without throwing', () => { for (const value of ['abc', '', '123456789-1', '4123456-', '-1', '4123456-12']) { expect(lookupNumber(value, NOW).valid, value).toBe(false); } }); it('always returns a well formed shape, even when invalid', () => { const result = lookupNumber('nonsense', NOW); expect(result.nextDeadlines).toHaveLength(3); expect(result.deadlineDay).toBeGreaterThan(0); }); });