import { describe, it, expect } from 'vitest'; import { Anonymizer, presets } from '../src/index.js'; describe('generic preset', () => { const a = new Anonymizer({ patterns: presets.generic }); it('redacts a Luhn-valid credit card', async () => { const r = await a.anonymize('Carte 4111 1111 1111 1111 acceptée'); // valid test Visa expect(r.anon).not.toContain('4111'); expect(Object.values(r.mapping)).toContain('4111 1111 1111 1111'); expect(Object.keys(r.mapping)[0]).toMatch(/^\[CREDIT_CARD_1\]$/); }); it('leaves a Luhn-INVALID digit run intact (not tagged as a card)', async () => { // Unseparated run: no other generic pattern matches it either, so it stays verbatim. const r = await a.anonymize('Ref 1234567890123456 interne'); // fails Luhn expect(r.anon).toContain('1234567890123456'); expect(r.mapping).toEqual({}); }); it('redacts an IPv4 address without mangling it as a phone or card', async () => { const r = await a.anonymize('Serveur 192.168.1.42 indisponible'); expect(r.mapping).toEqual({ '[IPV4_1]': '192.168.1.42' }); expect(a.deanonymize(r.anon, r.mapping)).toContain('192.168.1.42'); }); it('tags a date as DATE (not TEL) and keeps a phone separate', async () => { const r = await a.anonymize('Le 12.03.2024, appelez le +41 22 345 67 89.'); const tags = Object.keys(r.mapping).map((p) => p.replace(/_\d+\]$/, ']')); expect(tags).toContain('[DATE]'); expect(tags).toContain('[TEL]'); expect(r.mapping['[DATE_1]']).toBe('12.03.2024'); // round-trip is lossless expect(a.deanonymize(r.anon, r.mapping)).toBe('Le 12.03.2024, appelez le +41 22 345 67 89.'); }); }); describe('nameHint stability', () => { it('a global-flagged custom nameHint yields the same result across repeated calls', async () => { // A naive `.test()` on a /g regex alternates true/false; the Anonymizer must strip the flag. const a = new Anonymizer({ nameHint: /\bDr\.\s\w+/g, patterns: presets.swiss }); const text = 'Rendez-vous avec Dr. Meyer'; // no structured PII, only the name hint const r1 = await a.anonymize(text); const r2 = await a.anonymize(text); const r3 = await a.anonymize(text); // No LLM → nothing is actually redacted, but behavior must be identical every time. expect(r1).toEqual(r2); expect(r2).toEqual(r3); }); });