wulf-pulse/lib/services/phishing-audit.test.ts
lorentz 98d3e925e5 feat(20-01): add audit-event writer (writeAuditEvent)
- Single parameterized append-only INSERT into audit_events
- Supports optional injected transaction client for atomic writes
- Documents the four canonical event_type strings for this phase
2026-07-16 10:35:35 -04:00

60 lines
1.9 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from 'vitest';
// Mock postgresClient BEFORE importing the module under test.
const queryMock = vi.fn();
vi.mock('./postgres-client', () => ({
postgresClient: {
query: (...args: unknown[]) => queryMock(...args),
},
}));
// eslint-disable-next-line import/first -- imported after vi.mock hoisting
import { writeAuditEvent } from './phishing-audit';
describe('writeAuditEvent', () => {
beforeEach(() => {
queryMock.mockReset();
});
it('issues one parameterized INSERT into audit_events and returns the RETURNING id when no client is passed', async () => {
queryMock.mockResolvedValueOnce({ rows: [{ id: 'audit-1' }] });
const id = await writeAuditEvent({
campaignId: 'campaign-1',
actor: 'operator@example.com',
eventType: 'remediation_approved',
payload: { actionType: 'block_sender' },
});
expect(id).toBe('audit-1');
expect(queryMock).toHaveBeenCalledTimes(1);
const [sql, params] = queryMock.mock.calls[0];
expect(sql).toContain('INSERT INTO audit_events');
expect(sql).toContain('RETURNING id::text AS id');
expect(params).toEqual([
'campaign-1',
'operator@example.com',
'remediation_approved',
JSON.stringify({ actionType: 'block_sender' }),
]);
});
it('routes the query through an explicit client instead of postgresClient when one is supplied', async () => {
const clientQueryMock = vi.fn().mockResolvedValueOnce({ rows: [{ id: 'audit-2' }] });
const fakeClient = { query: clientQueryMock };
const id = await writeAuditEvent(
{
campaignId: 'campaign-2',
actor: null,
eventType: 'remediation_completed',
payload: { actionId: 'action-1' },
},
fakeClient
);
expect(id).toBe('audit-2');
expect(clientQueryMock).toHaveBeenCalledTimes(1);
expect(queryMock).not.toHaveBeenCalled();
});
});