import assert from 'node:assert/strict'; import test from 'node:test'; import { BadRequestException } from '@nestjs/common'; import type { DataSource, EntityManager } from 'typeorm'; import { AuditQueryService } from '../../src/audit/audit-query.service'; import { buildAuditFilters } from '../../src/audit/audit-query'; import { ListAuditQueryDto } from '../../src/audit/dto/list-audit-query.dto'; import { AuditSource } from '../../src/database/entities'; test('buildAuditFilters parameterizes every audit filter', () => { const query = Object.assign(new ListAuditQueryDto(), { actorUsername: 'admin', action: 'USER_CREATED', source: AuditSource.WEB, entityType: 'user', requestId: 'request-12345678', from: '2026-08-01T00:00:00.000Z', to: '2026-08-31T23:59:59.999Z', search: "anything' OR 1=1 --", }); const filters = buildAuditFilters(query); assert.match(filters.clause, /event\.actor_username ILIKE \$1/); assert.match(filters.clause, /event\.action = \$2/); assert.match(filters.clause, /event\.source = \$3/); assert.match(filters.clause, /event\.occurred_at >= \$6/); assert.match(filters.clause, /event\.occurred_at <= \$7/); assert.match(filters.clause, /event\.request_id ILIKE \$8/); assert.equal(filters.clause.includes("anything' OR 1=1"), false); assert.equal(filters.parameters[7], "%anything' OR 1=1 --%"); }); test('AuditQueryService rejects an inverted date range before querying', async () => { const dataSource = { transaction: () => { throw new Error('transaction should not run'); }, } as unknown as DataSource; const service = new AuditQueryService(dataSource); const query = Object.assign(new ListAuditQueryDto(), { from: '2026-08-31T00:00:00.000Z', to: '2026-08-01T00:00:00.000Z', }); await assert.rejects( service.list(query), (error: unknown) => error instanceof BadRequestException && error.getStatus() === 400, ); }); test('AuditQueryService returns stable pagination metadata', async () => { let calls = 0; const manager = { query: async () => { calls += 1; return calls === 1 ? [{ total: 26 }] : [ { id: '0f45472b-541b-4d6c-969f-0821463d0ea7', action: 'USER_CREATED', }, ]; }, } as unknown as EntityManager; const dataSource = { transaction: async ( _isolation: string, operation: (entityManager: EntityManager) => Promise, ) => operation(manager), } as unknown as DataSource; const service = new AuditQueryService(dataSource); const query = Object.assign(new ListAuditQueryDto(), { page: 2, pageSize: 25, }); const result = await service.list(query); assert.equal(result.meta.total, 26); assert.equal(result.meta.totalPages, 2); assert.equal(result.meta.page, 2); assert.equal(result.data.length, 1); });