Skip to content

Commit 763618f

Browse files
committed
feat: adding or fixing unit tests
1 parent 1a41c9b commit 763618f

File tree

19 files changed

+4970
-2605
lines changed

19 files changed

+4970
-2605
lines changed

PruebasJmeter.jmx

Lines changed: 614 additions & 0 deletions
Large diffs are not rendered by default.

jest.config.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module.exports = {
22
preset: 'ts-jest/presets/js-with-ts',
33
testEnvironment: 'node',
4-
// collectCoverage: true,
4+
collectCoverage: true,
55
coveragePathIgnorePatterns: [
66
'/node_modules/',
77
'/build/',
@@ -12,6 +12,12 @@ module.exports = {
1212
'node_modules/(?!(mapboxgl|@mapbox/mapbox-gl-draw)/)',
1313
],
1414
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
15+
transform: {
16+
'^.+\\.ts$': 'ts-jest',
17+
},
18+
// clearMocks: true,
19+
// resetMocks: true,
20+
// restoreMocks: true,
1521
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.[jt]sx?$',
1622
moduleNameMapper: {
1723
'^@/(.*)$': '<rootDir>/src/$1',

package-lock.json

Lines changed: 2951 additions & 2028 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,17 @@
2424
"@aws-sdk/client-s3": "^3.758.0",
2525
"@aws-sdk/client-ses": "^3.772.0",
2626
"@aws-sdk/client-ssm": "^3.759.0",
27+
"compression": "^1.8.0",
2728
"cookie-parser": "^1.4.7",
2829
"dotenv": "^16.4.7",
2930
"express": "^4.21.2",
31+
"express-rate-limit": "^7.5.0",
3032
"express-validator": "^7.2.1",
3133
"ioredis": "^5.6.0",
3234
"jsonwebtoken": "^9.0.2",
3335
"jwks-rsa": "^3.1.0",
3436
"mysql2": "^3.13.0",
37+
"rate-limit-redis": "^4.2.0",
3538
"reflect-metadata": "^0.2.2",
3639
"swagger-jsdoc": "^6.2.8",
3740
"swagger-ui-express": "^5.0.1",
@@ -43,11 +46,13 @@
4346
"@commitlint/cli": "^19.8.0",
4447
"@commitlint/config-conventional": "^19.8.0",
4548
"@eslint/js": "^9.22.0",
49+
"@types/compression": "^1.7.5",
4650
"@types/cookie-parser": "^1.4.8",
4751
"@types/express": "^4.17.21",
4852
"@types/jest": "^29.5.14",
4953
"@types/jsonwebtoken": "^9.0.9",
5054
"@types/node": "^22.13.10",
55+
"@types/redis-mock": "^0.17.3",
5156
"@types/supertest": "^6.0.2",
5257
"@types/swagger-jsdoc": "^6.0.4",
5358
"@types/swagger-ui-express": "^4.1.8",
@@ -63,6 +68,7 @@
6368
"lint-staged": "^15.5.0",
6469
"nodemon": "^3.1.9",
6570
"prettier": "^3.5.3",
71+
"redis-mock": "^0.56.3",
6672
"supertest": "^7.0.0",
6773
"swagger-autogen": "^2.23.7",
6874
"ts-jest": "^29.2.6",
Lines changed: 158 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
import { DataSource, DataSourceOptions } from 'typeorm';
2-
import { getParameterDirect } from '../../utils/ssmUtil';
32

4-
// Mock SSM and logger dependencies
3+
// Provide a manual mock for logger so its methods are jest.fn() instances.
4+
jest.mock('../../utils/logger', () => ({
5+
error: jest.fn(),
6+
info: jest.fn(),
7+
}));
8+
9+
// Mock SSM dependency
510
jest.mock('../../utils/ssmUtil');
6-
jest.mock('../../utils/logger');
711

812
describe('Database Configuration', () => {
9-
const mockGetParameterDirect = getParameterDirect as jest.MockedFunction<
10-
typeof getParameterDirect
11-
>;
12-
let MockedDataSource: jest.Mock;
13-
let getAppDataSource: () => Promise<DataSource>;
14-
1513
const testDbConfig = {
1614
type: 'postgres' as const,
1715
host: 'test-host',
@@ -21,11 +19,16 @@ describe('Database Configuration', () => {
2119
database: 'test-db',
2220
};
2321

22+
let MockedDataSource: jest.Mock;
23+
/* eslint-disable no-unused-vars, @typescript-eslint/no-unused-vars */
24+
let getAppDataSource: () => Promise<DataSource>;
25+
2426
beforeEach(() => {
27+
// Reset modules and clear mocks for tests that don't require error simulation.
2528
jest.resetModules();
2629
jest.clearAllMocks();
2730

28-
// Reset environment variables
31+
// Set environment variables for production branch.
2932
process.env.NODE_ENV = 'development';
3033
process.env.SSM_DB_TYPE = 'db-type-param';
3134
process.env.SSM_DB_HOST = 'db-host-param';
@@ -34,7 +37,7 @@ describe('Database Configuration', () => {
3437
process.env.SSM_DB_PASSWORD = 'db-password-param';
3538
process.env.SSM_DB_NAME = 'db-name-param';
3639

37-
// Setup mock for DataSource
40+
// Setup a default mock for DataSource (used in successful cases)
3841
MockedDataSource = jest
3942
.fn()
4043
.mockImplementation((options: DataSourceOptions) => ({
@@ -43,54 +46,168 @@ describe('Database Configuration', () => {
4346
initialize: jest.fn().mockResolvedValue(true),
4447
}));
4548

46-
// Mock typeorm
47-
jest.mock('typeorm', () => ({
49+
// Mock TypeORM's DataSource using our MockedDataSource.
50+
jest.doMock('typeorm', () => ({
4851
...jest.requireActual('typeorm'),
4952
DataSource: MockedDataSource,
5053
}));
5154

52-
// Setup SSM mock responses
53-
mockGetParameterDirect.mockImplementation(async (paramName: string) => {
54-
switch (paramName) {
55-
case process.env.SSM_DB_TYPE:
56-
return testDbConfig.type;
57-
case process.env.SSM_DB_HOST:
58-
return testDbConfig.host;
59-
case process.env.SSM_DB_PORT:
60-
return testDbConfig.port;
61-
case process.env.SSM_DB_USERNAME:
62-
return testDbConfig.username;
63-
case process.env.SSM_DB_PASSWORD:
64-
return testDbConfig.password;
65-
case process.env.SSM_DB_NAME:
66-
return testDbConfig.database;
67-
default:
68-
throw new Error(`Unexpected SSM param: ${paramName}`);
69-
}
70-
});
71-
72-
// Import the module under test after setting up mocks
55+
// Setup default SSM responses for production branch.
56+
const { getParameterDirect } = require('../../utils/ssmUtil');
57+
(getParameterDirect as jest.Mock).mockImplementation(
58+
async (paramName: string) => {
59+
switch (paramName) {
60+
case process.env.SSM_DB_TYPE:
61+
return testDbConfig.type;
62+
case process.env.SSM_DB_HOST:
63+
return testDbConfig.host;
64+
case process.env.SSM_DB_PORT:
65+
return testDbConfig.port;
66+
case process.env.SSM_DB_USERNAME:
67+
return testDbConfig.username;
68+
case process.env.SSM_DB_PASSWORD:
69+
return testDbConfig.password;
70+
case process.env.SSM_DB_NAME:
71+
return testDbConfig.database;
72+
default:
73+
throw new Error(`Unexpected SSM param: ${paramName}`);
74+
}
75+
},
76+
);
77+
78+
// Import the module under test.
7379
const databaseModule = require('../../config/database');
7480
getAppDataSource = databaseModule.getAppDataSource;
7581
});
7682

7783
it('should create SQLite in-memory database for test environment', async () => {
7884
process.env.NODE_ENV = 'test';
79-
85+
// Re-import the module under test to pick up test env branch.
86+
const databaseModule = require('../../config/database');
87+
const getAppDataSource = databaseModule.getAppDataSource;
8088
await getAppDataSource();
81-
8289
expect(MockedDataSource).toHaveBeenCalled();
8390
});
8491

85-
it('should throw BaseAppException when database initialization fails', async () => {
86-
MockedDataSource.mockImplementationOnce(() => ({
87-
isInitialized: false,
88-
options: {} as DataSourceOptions,
89-
initialize: jest.fn().mockRejectedValue(new Error('Connection failed')),
92+
it('should successfully create production MySQL DataSource', async () => {
93+
// Override SSM responses for MySQL.
94+
process.env.NODE_ENV = 'development';
95+
process.env.SSM_DB_TYPE = 'db-type-param';
96+
process.env.SSM_DB_HOST = 'db-host-param';
97+
process.env.SSM_DB_PORT = 'db-port-param';
98+
process.env.SSM_DB_USERNAME = 'db-username-param';
99+
process.env.SSM_DB_PASSWORD = 'db-password-param';
100+
process.env.SSM_DB_NAME = 'db-name-param';
101+
102+
// Reset modules so updated mocks take effect.
103+
jest.resetModules();
104+
// Reapply TypeORM mock.
105+
jest.doMock('typeorm', () => ({
106+
...jest.requireActual('typeorm'),
107+
DataSource: MockedDataSource,
90108
}));
109+
// Override SSM to return MySQL values.
110+
const { getParameterDirect } = require('../../utils/ssmUtil');
111+
(getParameterDirect as jest.Mock).mockImplementation(
112+
async (paramName: string) => {
113+
if (paramName === 'db-type-param') return 'mysql';
114+
if (paramName === 'db-host-param') return 'mysql-host';
115+
if (paramName === 'db-port-param') return '3306';
116+
if (paramName === 'db-username-param') return 'mysql-user';
117+
if (paramName === 'db-password-param') return 'mysql-pass';
118+
if (paramName === 'db-name-param') return 'mysql-db';
119+
throw new Error(`Unexpected SSM param: ${paramName}`);
120+
},
121+
);
122+
123+
const databaseModule = require('../../config/database');
124+
const getAppDataSource = databaseModule.getAppDataSource;
125+
const ds = await getAppDataSource();
126+
127+
expect(MockedDataSource).toHaveBeenCalledTimes(1);
128+
const options = ds.options as {
129+
type: string;
130+
host: string;
131+
port: number;
132+
username: string;
133+
password: string;
134+
database: string;
135+
};
136+
expect(options.type).toBe('mysql');
137+
expect(options.host).toBe('mysql-host');
138+
expect(options.port).toBe(3306);
139+
expect(options.username).toBe('mysql-user');
140+
expect(options.password).toBe('mysql-pass');
141+
expect(options.database).toBe('mysql-db');
142+
});
143+
144+
it('should throw BaseAppException and log error when SSM parameter retrieval fails', async () => {
145+
process.env.NODE_ENV = 'development';
146+
const ssmError = new Error('SSM error');
147+
148+
// Force getParameterDirect to reject.
149+
jest.resetModules();
150+
const ssmUtil = require('../../utils/ssmUtil');
151+
(ssmUtil.getParameterDirect as jest.Mock).mockRejectedValue(ssmError);
152+
153+
// Re-import the database module so it picks up the updated SSM mock.
154+
const databaseModule = require('../../config/database');
155+
const getAppDataSource = databaseModule.getAppDataSource;
91156

92157
await expect(getAppDataSource()).rejects.toThrow(
93158
'Database initialization failed.',
94159
);
95160
});
161+
162+
it('should throw BaseAppException and log error when DataSource initialization fails', async () => {
163+
process.env.NODE_ENV = 'development';
164+
165+
// For SSM calls, provide valid responses.
166+
jest.resetModules();
167+
const ssmUtil = require('../../utils/ssmUtil');
168+
(ssmUtil.getParameterDirect as jest.Mock).mockImplementation(
169+
async (paramName: string) => {
170+
if (paramName === 'db-type-param') return 'mysql';
171+
if (paramName === 'db-host-param') return 'host';
172+
if (paramName === 'db-port-param') return '3306';
173+
if (paramName === 'db-username-param') return 'user';
174+
if (paramName === 'db-password-param') return 'pass';
175+
if (paramName === 'db-name-param') return 'db';
176+
throw new Error(`Unexpected SSM param: ${paramName}`);
177+
},
178+
);
179+
180+
// Force DataSource.initialize() to fail.
181+
jest.doMock('typeorm', () => ({
182+
...jest.requireActual('typeorm'),
183+
DataSource: jest
184+
.fn()
185+
.mockImplementation((options: DataSourceOptions) => ({
186+
isInitialized: false,
187+
options,
188+
initialize: jest
189+
.fn()
190+
.mockRejectedValue(new Error('Connection failed')),
191+
})),
192+
}));
193+
194+
const databaseModule = require('../../config/database');
195+
const getAppDataSource = databaseModule.getAppDataSource;
196+
197+
await expect(getAppDataSource()).rejects.toThrow(
198+
'Database connection failed',
199+
);
200+
});
201+
202+
it('should reuse existing DataSource instance if already initialized', async () => {
203+
process.env.NODE_ENV = 'test';
204+
// For test environment we don't need error mocks.
205+
const databaseModule = require('../../config/database');
206+
const getAppDataSource = databaseModule.getAppDataSource;
207+
const ds1 = await getAppDataSource();
208+
// Mark the instance as initialized.
209+
Object.defineProperty(ds1, 'isInitialized', { value: true });
210+
const ds2 = await getAppDataSource();
211+
expect(ds2).toBe(ds1);
212+
});
96213
});

0 commit comments

Comments
 (0)