Skip to content

Commit 07489d8

Browse files
committed
test: comprehensive test coverage hardening across all packages
Add ~50 new test files with 500+ tests covering services, controllers, guards, strategies, decorators, middleware, providers, and modules. Raise coverage thresholds significantly from 10-25% to 50-90% per package. Packages covered: - nestjs-response: 90%+ thresholds (interceptor, exception filter) - nestjs-prisma: 65-80% thresholds (soft-delete middleware, test utils) - nestjs-pagination: 70-90% thresholds (paginate, decorator) - nestjs-audit-log: 80% thresholds (controller, module, middleware, decorator) - nestjs-auth: 50-65% thresholds (org service/controller, strategies, guards, decorators) - nestjs-storage: 65-80% thresholds (providers, controller, module, file-upload decorator) - nestjs-notifications: 38-50% thresholds (controllers, module, twilio, firebase providers)
1 parent cef4b9e commit 07489d8

57 files changed

Lines changed: 9782 additions & 38 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

jest.preset.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ const baseConfig: Config = {
1111
testEnvironment: 'node',
1212
coverageThreshold: {
1313
global: {
14-
branches: 0,
15-
functions: 8,
16-
lines: 17,
17-
statements: 18,
14+
branches: 35,
15+
functions: 40,
16+
lines: 40,
17+
statements: 40,
1818
},
1919
},
2020
};

packages/nestjs-audit-log/jest.config.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ const config: Config = {
66
rootDir: '.',
77
coverageThreshold: {
88
global: {
9-
branches: 25,
10-
functions: 25,
11-
lines: 25,
12-
statements: 25,
9+
branches: 80,
10+
functions: 80,
11+
lines: 80,
12+
statements: 80,
1313
},
1414
},
1515
};
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
import { AuditLogController } from './audit-log.controller';
2+
import { AuditLogService } from './audit-log.service';
3+
import { AUDIT_LOG_MODULE_OPTIONS, AuditLogModuleOptions } from './interfaces';
4+
5+
describe('AuditLogController', () => {
6+
let controller: AuditLogController;
7+
let mockAuditLogService: jest.Mocked<Pick<AuditLogService, 'findAll' | 'findById' | 'findByEntity'>>;
8+
let mockOptions: AuditLogModuleOptions;
9+
10+
beforeEach(() => {
11+
mockAuditLogService = {
12+
findAll: jest.fn().mockResolvedValue({
13+
data: [],
14+
total: 0,
15+
page: 1,
16+
limit: 20,
17+
totalPages: 0,
18+
}),
19+
findById: jest.fn().mockResolvedValue(null),
20+
findByEntity: jest.fn().mockResolvedValue([]),
21+
};
22+
23+
mockOptions = {
24+
features: { registerController: true },
25+
adminRoles: ['ADMIN'],
26+
};
27+
28+
controller = new AuditLogController(
29+
mockAuditLogService as any,
30+
mockOptions,
31+
);
32+
});
33+
34+
afterEach(() => {
35+
jest.clearAllMocks();
36+
});
37+
38+
describe('findAll', () => {
39+
it('should call service.findAll with all undefined when no query params provided', async () => {
40+
await controller.findAll();
41+
42+
expect(mockAuditLogService.findAll).toHaveBeenCalledWith({
43+
userId: undefined,
44+
entity: undefined,
45+
entityId: undefined,
46+
action: undefined,
47+
startDate: undefined,
48+
endDate: undefined,
49+
page: undefined,
50+
limit: undefined,
51+
});
52+
});
53+
54+
it('should parse page and limit as integers and dates as Date objects', async () => {
55+
const startDate = '2025-01-01T00:00:00.000Z';
56+
const endDate = '2025-12-31T23:59:59.999Z';
57+
58+
await controller.findAll(
59+
'user-1',
60+
'Claim',
61+
'claim-1',
62+
'UPDATE',
63+
startDate,
64+
endDate,
65+
'2',
66+
'10',
67+
);
68+
69+
expect(mockAuditLogService.findAll).toHaveBeenCalledWith({
70+
userId: 'user-1',
71+
entity: 'Claim',
72+
entityId: 'claim-1',
73+
action: 'UPDATE',
74+
startDate: new Date(startDate),
75+
endDate: new Date(endDate),
76+
page: 2,
77+
limit: 10,
78+
});
79+
});
80+
81+
it('should handle partial query params correctly', async () => {
82+
await controller.findAll(
83+
'user-1',
84+
undefined,
85+
undefined,
86+
'CREATE',
87+
undefined,
88+
undefined,
89+
'1',
90+
undefined,
91+
);
92+
93+
expect(mockAuditLogService.findAll).toHaveBeenCalledWith({
94+
userId: 'user-1',
95+
entity: undefined,
96+
entityId: undefined,
97+
action: 'CREATE',
98+
startDate: undefined,
99+
endDate: undefined,
100+
page: 1,
101+
limit: undefined,
102+
});
103+
});
104+
105+
it('should return the result from service.findAll', async () => {
106+
const expectedResult = {
107+
data: [{ id: 'log-1', action: 'CREATE' }],
108+
total: 1,
109+
page: 1,
110+
limit: 20,
111+
totalPages: 1,
112+
};
113+
mockAuditLogService.findAll.mockResolvedValue(expectedResult);
114+
115+
const result = await controller.findAll();
116+
117+
expect(result).toEqual(expectedResult);
118+
});
119+
120+
it('should pass string params through without transformation', async () => {
121+
await controller.findAll(
122+
'user-abc',
123+
'Order',
124+
'order-123',
125+
'DELETE',
126+
);
127+
128+
expect(mockAuditLogService.findAll).toHaveBeenCalledWith(
129+
expect.objectContaining({
130+
userId: 'user-abc',
131+
entity: 'Order',
132+
entityId: 'order-123',
133+
action: 'DELETE',
134+
}),
135+
);
136+
});
137+
});
138+
139+
describe('findById', () => {
140+
it('should delegate to service.findById with the provided id', async () => {
141+
const mockLog = { id: 'log-1', action: 'CREATE', entity: 'Claim' };
142+
mockAuditLogService.findById.mockResolvedValue(mockLog);
143+
144+
const result = await controller.findById('log-1');
145+
146+
expect(mockAuditLogService.findById).toHaveBeenCalledWith('log-1');
147+
expect(result).toEqual(mockLog);
148+
});
149+
150+
it('should return null when log is not found', async () => {
151+
mockAuditLogService.findById.mockResolvedValue(null);
152+
153+
const result = await controller.findById('nonexistent');
154+
155+
expect(result).toBeNull();
156+
});
157+
});
158+
159+
describe('findByEntity', () => {
160+
it('should delegate to service.findByEntity with entity and entityId', async () => {
161+
const mockLogs = [
162+
{ id: 'log-1', entity: 'Claim', entityId: 'c-1', action: 'CREATE' },
163+
{ id: 'log-2', entity: 'Claim', entityId: 'c-1', action: 'UPDATE' },
164+
];
165+
mockAuditLogService.findByEntity.mockResolvedValue(mockLogs);
166+
167+
const result = await controller.findByEntity('Claim', 'c-1');
168+
169+
expect(mockAuditLogService.findByEntity).toHaveBeenCalledWith('Claim', 'c-1');
170+
expect(result).toEqual(mockLogs);
171+
});
172+
173+
it('should return empty array when no logs found for entity', async () => {
174+
mockAuditLogService.findByEntity.mockResolvedValue([]);
175+
176+
const result = await controller.findByEntity('Unknown', 'x-1');
177+
178+
expect(result).toEqual([]);
179+
});
180+
});
181+
});

0 commit comments

Comments
 (0)