/** * @vitest-environment node */ import { createMockRequest } from '@sim/testing' import { beforeEach, describe, expect, it, vi } from 'vitest' const { mockCheckInternalAuth, mockMaskPIIBatch } = vi.hoisted(() => ({ mockCheckInternalAuth: vi.fn(), mockMaskPIIBatch: vi.fn(), })) vi.mock('@/lib/auth/hybrid', () => ({ checkInternalAuth: mockCheckInternalAuth, })) vi.mock('@/lib/guardrails/validate_pii', () => ({ maskPIIBatch: mockMaskPIIBatch, })) import { POST } from '@/app/api/guardrails/mask-batch/route' describe('POST /api/guardrails/mask-batch', () => { beforeEach(() => { vi.clearAllMocks() mockCheckInternalAuth.mockResolvedValue({ success: true }) mockMaskPIIBatch.mockImplementation(async (texts: string[]) => texts.map((t) => `M(${t})`)) }) it('returns 401 without internal auth', async () => { mockCheckInternalAuth.mockResolvedValue({ success: false, error: 'Internal authentication required', }) const res = await POST( createMockRequest('POST', { texts: ['a@b.com'], entityTypes: ['EMAIL_ADDRESS'] }) ) expect(res.status).toBe(401) expect(mockMaskPIIBatch).not.toHaveBeenCalled() }) it('masks the batch in-process and preserves order', async () => { const res = await POST( createMockRequest('POST', { texts: ['a@b.com', 'hello'], entityTypes: ['EMAIL_ADDRESS'], language: 'en', }) ) expect(res.status).toBe(200) const json = await res.json() expect(json.masked).toEqual(['M(a@b.com)', 'M(hello)']) expect(mockMaskPIIBatch).toHaveBeenCalledWith(['a@b.com', 'hello'], ['EMAIL_ADDRESS'], 'en') }) it('rejects an invalid body with 400', async () => { const res = await POST(createMockRequest('POST', { texts: 'not-an-array', entityTypes: [] })) expect(res.status).toBe(400) expect(mockMaskPIIBatch).not.toHaveBeenCalled() }) })