|
2 | 2 | * Unit tests for the PII guardrail functionality. |
3 | 3 | */ |
4 | 4 |
|
5 | | -import { describe, it, expect } from 'vitest'; |
6 | | -import { pii, PIIConfig, PIIEntity } from '../../../checks/pii'; |
| 5 | +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; |
| 6 | +import { pii, PIIConfig, PIIEntity, _clearDeprecationWarnings } from '../../../checks/pii'; |
7 | 7 |
|
8 | 8 | describe('pii guardrail', () => { |
9 | 9 | it('masks detected PII when block=false', async () => { |
@@ -286,4 +286,141 @@ describe('pii guardrail', () => { |
286 | 286 | ); |
287 | 287 | expect(result.info?.checked_text).toBe('Ship to <LOCATION> for delivery.'); |
288 | 288 | }); |
| 289 | + |
| 290 | + describe('NRP and PERSON deprecation (Issue #47)', () => { |
| 291 | + beforeEach(() => { |
| 292 | + // Clear deprecation warnings before each test to ensure clean state |
| 293 | + _clearDeprecationWarnings(); |
| 294 | + }); |
| 295 | + |
| 296 | + afterEach(() => { |
| 297 | + // Restore all mocks to prevent leaking between tests |
| 298 | + vi.restoreAllMocks(); |
| 299 | + }); |
| 300 | + |
| 301 | + it('excludes NRP and PERSON from default entities', () => { |
| 302 | + const config = PIIConfig.parse({}); |
| 303 | + |
| 304 | + expect(config.entities).not.toContain(PIIEntity.NRP); |
| 305 | + expect(config.entities).not.toContain(PIIEntity.PERSON); |
| 306 | + }); |
| 307 | + |
| 308 | + it('does not mask common two-word phrases when using defaults', async () => { |
| 309 | + const config = PIIConfig.parse({ |
| 310 | + block: false, |
| 311 | + }); |
| 312 | + const text = 'crea un nuevo cliente con email [email protected]'; |
| 313 | + |
| 314 | + const result = await pii({}, text, config); |
| 315 | + |
| 316 | + // Should only mask the email, not "crea un" or "nuevo cliente" |
| 317 | + expect(result.info?.checked_text).toBe('crea un nuevo cliente con email <EMAIL_ADDRESS>'); |
| 318 | + expect((result.info?.detected_entities as Record<string, string[]>)?.NRP).toBeUndefined(); |
| 319 | + }); |
| 320 | + |
| 321 | + it('does not mask capitalized phrases when using defaults', async () => { |
| 322 | + const config = PIIConfig.parse({ |
| 323 | + block: false, |
| 324 | + }); |
| 325 | + const text = 'Welcome to New York, The User can access the system.'; |
| 326 | + |
| 327 | + const result = await pii({}, text, config); |
| 328 | + |
| 329 | + // Should not mask "New York" or "The User" |
| 330 | + expect(result.info?.checked_text).toBe('Welcome to New York, The User can access the system.'); |
| 331 | + expect((result.info?.detected_entities as Record<string, string[]>)?.PERSON).toBeUndefined(); |
| 332 | + }); |
| 333 | + |
| 334 | + it('still detects NRP when explicitly configured', async () => { |
| 335 | + const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); |
| 336 | + |
| 337 | + const config = PIIConfig.parse({ |
| 338 | + entities: [PIIEntity.NRP], |
| 339 | + block: false, |
| 340 | + }); |
| 341 | + const text = 'hello world'; |
| 342 | + |
| 343 | + const result = await pii({}, text, config); |
| 344 | + |
| 345 | + expect((result.info?.detected_entities as Record<string, string[]>)?.NRP).toEqual(['hello world']); |
| 346 | + expect(result.info?.checked_text).toBe('<NRP>'); |
| 347 | + |
| 348 | + consoleWarnSpy.mockRestore(); |
| 349 | + }); |
| 350 | + |
| 351 | + it('still detects PERSON when explicitly configured', async () => { |
| 352 | + const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); |
| 353 | + |
| 354 | + const config = PIIConfig.parse({ |
| 355 | + entities: [PIIEntity.PERSON], |
| 356 | + block: false, |
| 357 | + }); |
| 358 | + const text = 'John Smith lives in New York'; |
| 359 | + |
| 360 | + const result = await pii({}, text, config); |
| 361 | + |
| 362 | + expect((result.info?.detected_entities as Record<string, string[]>)?.PERSON).toContain('John Smith'); |
| 363 | + expect((result.info?.detected_entities as Record<string, string[]>)?.PERSON).toContain('New York'); |
| 364 | + |
| 365 | + consoleWarnSpy.mockRestore(); |
| 366 | + }); |
| 367 | + |
| 368 | + it('shows deprecation warning for NRP', async () => { |
| 369 | + const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); |
| 370 | + |
| 371 | + const config = PIIConfig.parse({ |
| 372 | + entities: [PIIEntity.NRP], |
| 373 | + block: false, |
| 374 | + }); |
| 375 | + |
| 376 | + await pii({}, 'test data', config); |
| 377 | + |
| 378 | + expect(consoleWarnSpy).toHaveBeenCalledWith( |
| 379 | + expect.stringContaining('DEPRECATION: PIIEntity.NRP') |
| 380 | + ); |
| 381 | + expect(consoleWarnSpy).toHaveBeenCalledWith( |
| 382 | + expect.stringContaining('more robust implementation') |
| 383 | + ); |
| 384 | + |
| 385 | + consoleWarnSpy.mockRestore(); |
| 386 | + }); |
| 387 | + |
| 388 | + it('shows deprecation warning for PERSON', async () => { |
| 389 | + const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); |
| 390 | + |
| 391 | + const config = PIIConfig.parse({ |
| 392 | + entities: [PIIEntity.PERSON], |
| 393 | + block: false, |
| 394 | + }); |
| 395 | + |
| 396 | + await pii({}, 'test data', config); |
| 397 | + |
| 398 | + expect(consoleWarnSpy).toHaveBeenCalledWith( |
| 399 | + expect.stringContaining('DEPRECATION: PIIEntity.PERSON') |
| 400 | + ); |
| 401 | + expect(consoleWarnSpy).toHaveBeenCalledWith( |
| 402 | + expect.stringContaining('more robust implementation') |
| 403 | + ); |
| 404 | + |
| 405 | + consoleWarnSpy.mockRestore(); |
| 406 | + }); |
| 407 | + |
| 408 | + it('only shows deprecation warning once per entity', async () => { |
| 409 | + const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); |
| 410 | + |
| 411 | + const config = PIIConfig.parse({ |
| 412 | + entities: [PIIEntity.NRP, PIIEntity.PERSON], |
| 413 | + block: false, |
| 414 | + }); |
| 415 | + |
| 416 | + await pii({}, 'test data', config); |
| 417 | + await pii({}, 'more test data', config); |
| 418 | + await pii({}, 'even more data', config); |
| 419 | + |
| 420 | + // Should only be called once for each entity (2 total) |
| 421 | + expect(consoleWarnSpy).toHaveBeenCalledTimes(2); |
| 422 | + |
| 423 | + consoleWarnSpy.mockRestore(); |
| 424 | + }); |
| 425 | + }); |
289 | 426 | }); |
0 commit comments