feat(d27): #8 audit-log viewer (owner-only)
listAuditPage (filters: entity/action/user/entity-id/date; honest total; newest first) + auditFacets. GET /audit owner-only. New /audit 'Audit log' page: entity/ action filters from server facets, paginated table with a per-row before->after key diff, actor names mapped via employees. Reading the log writes no audit row. Test locks filter+pagination. typecheck + web build clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>feat/client-detail-redesign
parent
7f6e2ce904
commit
5761544c74
@ -0,0 +1,28 @@
|
|||||||
|
// apps/hq/test/audit-viewer.test.ts — D27: filtered/paginated audit viewer.
|
||||||
|
import { describe, it, expect } from 'vitest'
|
||||||
|
import { openDb } from '../src/db'
|
||||||
|
import { seedIfEmpty } from '../src/seed'
|
||||||
|
import { createClient, updateClient } from '../src/repos-clients'
|
||||||
|
import { listAuditPage, auditFacets } from '../src/audit'
|
||||||
|
|
||||||
|
describe('listAuditPage (D27)', () => {
|
||||||
|
it('filters by entity/action and paginates with an honest total', async () => {
|
||||||
|
const db = openDb(':memory:'); await seedIfEmpty(db)
|
||||||
|
const c = await createClient(db, 'u1', { name: 'A', stateCode: '32' })
|
||||||
|
for (let i = 0; i < 5; i++) await updateClient(db, 'u1', c.id, { notes: `n${i}` })
|
||||||
|
const clientRows = await listAuditPage(db, { entity: 'client' })
|
||||||
|
expect(clientRows.total).toBe(6) // 1 create + 5 updates
|
||||||
|
const updates = await listAuditPage(db, { entity: 'client', action: 'update' })
|
||||||
|
expect(updates.total).toBe(5)
|
||||||
|
// pagination: honest total, page size honored, newest first.
|
||||||
|
const p1 = await listAuditPage(db, { entity: 'client', pageSize: 2, page: 1 })
|
||||||
|
expect(p1.total).toBe(6)
|
||||||
|
expect(p1.rows).toHaveLength(2)
|
||||||
|
const p2 = await listAuditPage(db, { entity: 'client', pageSize: 2, page: 2 })
|
||||||
|
expect(p2.rows[0]!.id).not.toBe(p1.rows[0]!.id) // no overlap
|
||||||
|
// facets surface the entities/actions present.
|
||||||
|
const f = await auditFacets(db)
|
||||||
|
expect(f.entities).toContain('client')
|
||||||
|
expect(f.actions).toEqual(expect.arrayContaining(['create', 'update']))
|
||||||
|
})
|
||||||
|
})
|
||||||
Loading…
Reference in New Issue