Skip to content

Commit 37b0848

Browse files
committed
feat: add unit testing
1 parent 6957398 commit 37b0848

6 files changed

Lines changed: 134 additions & 58 deletions

File tree

eslint.config.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import tseslint from 'typescript-eslint';
66

77
export default tseslint.config(
88
{
9-
ignores: ['eslint.config.mjs'],
9+
ignores: ['eslint.config.mjs', 'jest.config.js', 'dist/'],
1010
},
1111
eslint.configs.recommended,
1212
...tseslint.configs.recommendedTypeChecked,
@@ -28,7 +28,7 @@ export default tseslint.config(
2828
rules: {
2929
'@typescript-eslint/no-explicit-any': 'off',
3030
'@typescript-eslint/no-floating-promises': 'warn',
31-
'@typescript-eslint/no-unsafe-argument': 'warn'
31+
'@typescript-eslint/no-unsafe-argument': 'warn',
3232
},
3333
},
3434
);

package.json

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@
1616
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
1717
"test": "jest",
1818
"test:watch": "jest --watch",
19-
"test:cov": "jest --coverage",
20-
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
21-
"test:e2e": "jest --config ./test/jest-e2e.json"
19+
"test:cov": "jest --coverage"
2220
},
2321
"dependencies": {
2422
"@nestjs/common": "^11.0.1",
@@ -68,22 +66,5 @@
6866
"tsconfig-paths": "^4.2.0",
6967
"typescript": "^5.7.3",
7068
"typescript-eslint": "^8.20.0"
71-
},
72-
"jest": {
73-
"moduleFileExtensions": [
74-
"js",
75-
"json",
76-
"ts"
77-
],
78-
"rootDir": "src",
79-
"testRegex": ".*\\.spec\\.ts$",
80-
"transform": {
81-
"^.+\\.(t|j)s$": "ts-jest"
82-
},
83-
"collectCoverageFrom": [
84-
"**/*.(t|j)s"
85-
],
86-
"coverageDirectory": "../coverage",
87-
"testEnvironment": "node"
8869
}
8970
}

test/app.e2e-spec.ts

Lines changed: 0 additions & 25 deletions
This file was deleted.

test/jest-e2e.json

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { Test, TestingModule } from '@nestjs/testing';
2+
import { NotificationController } from '../../src/notification/presentation/controllers/notification.controller';
3+
import { NotificationFactory } from '../../src/notification/application/factories/notification.factory';
4+
import { INotificationRepository } from '../../src/notification/domain/interfaces/notification-repository.interface';
5+
import { LoggerServiceFile } from '../../src/logger/services/logger.service.file';
6+
import { LoggerServiceDb } from '../../src/logger/services/logger.service.db';
7+
import { SendNotificationDto } from '../../src/notification/presentation/dtos/send-notification.dto';
8+
import { Notification } from '../../src/notification/domain/entities/notification.entity';
9+
import { NotificationChannel, NotificationType } from '../../src/config/notification.config';
10+
11+
describe('NotificationController', () => {
12+
let controller: NotificationController;
13+
let factory: NotificationFactory;
14+
let repository: INotificationRepository;
15+
16+
const mockNotification = new Notification(
17+
'test@example.com',
18+
'Test Subject',
19+
'Test Body',
20+
NotificationChannel.EMAIL,
21+
NotificationType.ADMISSION_ID,
22+
new Date(),
23+
);
24+
25+
const mockSendDto: SendNotificationDto = {
26+
recipient: 'test@example.com',
27+
subject: 'Test Subject',
28+
body: 'Test Body',
29+
mediaType: NotificationChannel.EMAIL,
30+
notificationType: NotificationType.ADMISSION_ID,
31+
};
32+
33+
const mockStrategy = {
34+
send: jest.fn().mockResolvedValue(undefined),
35+
};
36+
37+
beforeEach(async () => {
38+
const module: TestingModule = await Test.createTestingModule({
39+
controllers: [NotificationController],
40+
providers: [
41+
{
42+
provide: NotificationFactory,
43+
useValue: {
44+
createStrategy: jest.fn().mockReturnValue(mockStrategy),
45+
},
46+
},
47+
{
48+
provide: 'INotificationRepository',
49+
useValue: {
50+
save: jest.fn().mockResolvedValue(mockNotification),
51+
findAll: jest.fn().mockResolvedValue([mockNotification]),
52+
count: jest.fn().mockResolvedValue(1),
53+
},
54+
},
55+
{
56+
provide: LoggerServiceFile,
57+
useValue: {
58+
log: jest.fn(),
59+
error: jest.fn(),
60+
},
61+
},
62+
{
63+
provide: LoggerServiceDb,
64+
useValue: {
65+
log: jest.fn(),
66+
error: jest.fn().mockResolvedValue(undefined),
67+
},
68+
},
69+
],
70+
}).compile();
71+
72+
controller = module.get<NotificationController>(NotificationController);
73+
factory = module.get<NotificationFactory>(NotificationFactory);
74+
repository = module.get<INotificationRepository>('INotificationRepository');
75+
76+
// Use spies to avoid unbound method errors
77+
jest.spyOn(factory, 'createStrategy');
78+
jest.spyOn(repository, 'save');
79+
jest.spyOn(mockStrategy, 'send');
80+
});
81+
82+
describe('send', () => {
83+
it('should send notification and log successfully', async () => {
84+
await controller.send(mockSendDto);
85+
86+
expect(factory.createStrategy).toHaveBeenCalledWith(mockSendDto.mediaType);
87+
expect(repository.save).toHaveBeenCalledWith(expect.any(Notification));
88+
expect(mockStrategy.send).toHaveBeenCalledWith(expect.any(Notification));
89+
});
90+
91+
it('should throw error if strategy send fails', async () => {
92+
jest.spyOn(factory, 'createStrategy').mockReturnValue({
93+
send: jest.fn().mockRejectedValue(new Error('Send failed')),
94+
});
95+
96+
await expect(controller.send(mockSendDto)).rejects.toThrow('Send failed');
97+
});
98+
});
99+
100+
describe('getNotificationHistory', () => {
101+
it('should return notification history with default pagination', async () => {
102+
jest.spyOn(repository, 'findAll');
103+
const result = await controller.getNotificationHistory(1, 10);
104+
105+
expect(repository.findAll).toHaveBeenCalledWith(0, 10);
106+
expect(result).toEqual({
107+
data: [mockNotification],
108+
total: 1,
109+
page: 1,
110+
totalPages: 1,
111+
});
112+
});
113+
114+
it('should handle custom pagination', async () => {
115+
jest.spyOn(repository, 'findAll').mockResolvedValue([mockNotification, mockNotification]);
116+
const result = await controller.getNotificationHistory(2, 5);
117+
118+
expect(repository.findAll).toHaveBeenCalledWith(5, 5);
119+
expect(result).toEqual({
120+
data: [mockNotification, mockNotification],
121+
total: 2,
122+
page: 2,
123+
totalPages: 1,
124+
});
125+
});
126+
});
127+
});

tsconfig.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,7 @@
1717
"noImplicitAny": true,
1818
"strictBindCallApply": true,
1919
"noFallthroughCasesInSwitch": true
20-
}
21-
}
20+
},
21+
"include": ["src/**/*", "test/**/*"],
22+
"exclude": ["node_modules", "dist"]
23+
}

0 commit comments

Comments
 (0)