105 lines
3.5 KiB
TypeScript
105 lines
3.5 KiB
TypeScript
import { describe, test, expect } from 'bun:test';
|
|
import { computeAuditDiff, formatFieldName } from '../src/lib/utils/diff';
|
|
|
|
describe('computeAuditDiff', () => {
|
|
test('returns null when no changes', () => {
|
|
expect(computeAuditDiff({ name: 'foo' }, { name: 'foo' })).toBeNull();
|
|
});
|
|
|
|
test('returns null for null inputs', () => {
|
|
expect(computeAuditDiff(null, { name: 'foo' })).toBeNull();
|
|
expect(computeAuditDiff({ name: 'foo' }, null)).toBeNull();
|
|
});
|
|
|
|
test('detects simple field change', () => {
|
|
const diff = computeAuditDiff({ name: 'old' }, { name: 'new' });
|
|
expect(diff).not.toBeNull();
|
|
expect(diff!.changes).toHaveLength(1);
|
|
expect(diff!.changes[0]).toEqual({ field: 'name', oldValue: 'old', newValue: 'new' });
|
|
});
|
|
|
|
test('detects added field', () => {
|
|
const diff = computeAuditDiff({ name: 'foo' }, { name: 'foo', host: 'localhost' });
|
|
expect(diff).not.toBeNull();
|
|
expect(diff!.changes[0].field).toBe('host');
|
|
});
|
|
|
|
test('skips internal fields (id, createdAt, updatedAt)', () => {
|
|
const diff = computeAuditDiff(
|
|
{ id: 1, name: 'foo', createdAt: 'old', updatedAt: 'old' },
|
|
{ id: 2, name: 'foo', createdAt: 'new', updatedAt: 'new' }
|
|
);
|
|
expect(diff).toBeNull();
|
|
});
|
|
|
|
test('masks sensitive fields', () => {
|
|
const diff = computeAuditDiff({ password: 'old-pass' }, { password: 'new-pass' });
|
|
expect(diff).not.toBeNull();
|
|
expect(diff!.changes[0].oldValue).toBe('••••••••');
|
|
expect(diff!.changes[0].newValue).toBe('••••••••');
|
|
});
|
|
|
|
test('shows masked field set to null', () => {
|
|
const diff = computeAuditDiff({ password: 'secret' }, { password: null });
|
|
expect(diff).not.toBeNull();
|
|
expect(diff!.changes[0].oldValue).toBe('••••••••');
|
|
expect(diff!.changes[0].newValue).toBeNull();
|
|
});
|
|
|
|
test('respects includeFields option', () => {
|
|
const diff = computeAuditDiff(
|
|
{ name: 'old', host: 'old', port: 1 },
|
|
{ name: 'new', host: 'new', port: 2 },
|
|
{ includeFields: ['name'] }
|
|
);
|
|
expect(diff!.changes).toHaveLength(1);
|
|
expect(diff!.changes[0].field).toBe('name');
|
|
});
|
|
|
|
test('respects excludeFields option', () => {
|
|
const diff = computeAuditDiff(
|
|
{ name: 'old', host: 'old' },
|
|
{ name: 'new', host: 'new' },
|
|
{ excludeFields: ['host'] }
|
|
);
|
|
expect(diff!.changes).toHaveLength(1);
|
|
expect(diff!.changes[0].field).toBe('name');
|
|
});
|
|
|
|
test('truncates long strings', () => {
|
|
const longStr = 'a'.repeat(300);
|
|
const diff = computeAuditDiff({ desc: 'short' }, { desc: longStr });
|
|
expect(diff!.changes[0].newValue.length).toBeLessThan(300);
|
|
expect(diff!.changes[0].newValue).toContain('...');
|
|
});
|
|
|
|
test('handles array changes', () => {
|
|
const diff = computeAuditDiff({ tags: ['a', 'b'] }, { tags: ['a', 'c'] });
|
|
expect(diff).not.toBeNull();
|
|
expect(diff!.changes[0].field).toBe('tags');
|
|
});
|
|
});
|
|
|
|
describe('formatFieldName', () => {
|
|
test('converts camelCase to title case', () => {
|
|
expect(formatFieldName('hostName')).toBe('Host Name');
|
|
});
|
|
|
|
test('handles special cases', () => {
|
|
expect(formatFieldName('tlsCa')).toBe('TLS CA');
|
|
expect(formatFieldName('tlsCert')).toBe('TLS certificate');
|
|
expect(formatFieldName('sshPrivateKey')).toBe('SSH private key');
|
|
expect(formatFieldName('ipAddress')).toBe('IP address');
|
|
expect(formatFieldName('connectionType')).toBe('Connection type');
|
|
});
|
|
|
|
test('capitalizes first letter', () => {
|
|
expect(formatFieldName('name')).toBe('Name');
|
|
});
|
|
|
|
test('handles multi-word camelCase', () => {
|
|
expect(formatFieldName('socketPath')).toBe('Socket path');
|
|
expect(formatFieldName('collectActivity')).toBe('Collect activity');
|
|
});
|
|
});
|