@hazeljs/core 0.2.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +522 -0
- package/dist/__tests__/container.test.d.ts +2 -0
- package/dist/__tests__/container.test.d.ts.map +1 -0
- package/dist/__tests__/container.test.js +454 -0
- package/dist/__tests__/decorators.test.d.ts +2 -0
- package/dist/__tests__/decorators.test.d.ts.map +1 -0
- package/dist/__tests__/decorators.test.js +693 -0
- package/dist/__tests__/errors/http.error.test.d.ts +2 -0
- package/dist/__tests__/errors/http.error.test.d.ts.map +1 -0
- package/dist/__tests__/errors/http.error.test.js +117 -0
- package/dist/__tests__/filters/exception-filter.test.d.ts +2 -0
- package/dist/__tests__/filters/exception-filter.test.d.ts.map +1 -0
- package/dist/__tests__/filters/exception-filter.test.js +135 -0
- package/dist/__tests__/filters/http-exception.filter.test.d.ts +2 -0
- package/dist/__tests__/filters/http-exception.filter.test.d.ts.map +1 -0
- package/dist/__tests__/filters/http-exception.filter.test.js +119 -0
- package/dist/__tests__/hazel-app.test.d.ts +2 -0
- package/dist/__tests__/hazel-app.test.d.ts.map +1 -0
- package/dist/__tests__/hazel-app.test.js +682 -0
- package/dist/__tests__/hazel-module.test.d.ts +2 -0
- package/dist/__tests__/hazel-module.test.d.ts.map +1 -0
- package/dist/__tests__/hazel-module.test.js +408 -0
- package/dist/__tests__/hazel-response.test.d.ts +2 -0
- package/dist/__tests__/hazel-response.test.d.ts.map +1 -0
- package/dist/__tests__/hazel-response.test.js +138 -0
- package/dist/__tests__/health.test.d.ts +2 -0
- package/dist/__tests__/health.test.d.ts.map +1 -0
- package/dist/__tests__/health.test.js +147 -0
- package/dist/__tests__/index.test.d.ts +2 -0
- package/dist/__tests__/index.test.d.ts.map +1 -0
- package/dist/__tests__/index.test.js +239 -0
- package/dist/__tests__/interceptors/interceptor.test.d.ts +2 -0
- package/dist/__tests__/interceptors/interceptor.test.d.ts.map +1 -0
- package/dist/__tests__/interceptors/interceptor.test.js +166 -0
- package/dist/__tests__/logger.test.d.ts +2 -0
- package/dist/__tests__/logger.test.d.ts.map +1 -0
- package/dist/__tests__/logger.test.js +141 -0
- package/dist/__tests__/middleware/cors.test.d.ts +2 -0
- package/dist/__tests__/middleware/cors.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/cors.test.js +129 -0
- package/dist/__tests__/middleware/csrf.test.d.ts +2 -0
- package/dist/__tests__/middleware/csrf.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/csrf.test.js +247 -0
- package/dist/__tests__/middleware/global-middleware.test.d.ts +2 -0
- package/dist/__tests__/middleware/global-middleware.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/global-middleware.test.js +259 -0
- package/dist/__tests__/middleware/rate-limit.test.d.ts +2 -0
- package/dist/__tests__/middleware/rate-limit.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/rate-limit.test.js +264 -0
- package/dist/__tests__/middleware/security-headers.test.d.ts +2 -0
- package/dist/__tests__/middleware/security-headers.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/security-headers.test.js +229 -0
- package/dist/__tests__/middleware/timeout.test.d.ts +2 -0
- package/dist/__tests__/middleware/timeout.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/timeout.test.js +132 -0
- package/dist/__tests__/middleware.test.d.ts +2 -0
- package/dist/__tests__/middleware.test.d.ts.map +1 -0
- package/dist/__tests__/middleware.test.js +180 -0
- package/dist/__tests__/pipes/pipe.test.d.ts +2 -0
- package/dist/__tests__/pipes/pipe.test.d.ts.map +1 -0
- package/dist/__tests__/pipes/pipe.test.js +245 -0
- package/dist/__tests__/pipes/validation.pipe.test.d.ts +2 -0
- package/dist/__tests__/pipes/validation.pipe.test.d.ts.map +1 -0
- package/dist/__tests__/pipes/validation.pipe.test.js +297 -0
- package/dist/__tests__/request-parser.test.d.ts +2 -0
- package/dist/__tests__/request-parser.test.d.ts.map +1 -0
- package/dist/__tests__/request-parser.test.js +182 -0
- package/dist/__tests__/router.test.d.ts +2 -0
- package/dist/__tests__/router.test.d.ts.map +1 -0
- package/dist/__tests__/router.test.js +680 -0
- package/dist/__tests__/routing/route-matcher.test.d.ts +2 -0
- package/dist/__tests__/routing/route-matcher.test.d.ts.map +1 -0
- package/dist/__tests__/routing/route-matcher.test.js +219 -0
- package/dist/__tests__/routing/version.decorator.test.d.ts +2 -0
- package/dist/__tests__/routing/version.decorator.test.d.ts.map +1 -0
- package/dist/__tests__/routing/version.decorator.test.js +298 -0
- package/dist/__tests__/service.test.d.ts +2 -0
- package/dist/__tests__/service.test.d.ts.map +1 -0
- package/dist/__tests__/service.test.js +121 -0
- package/dist/__tests__/shutdown.test.d.ts +2 -0
- package/dist/__tests__/shutdown.test.d.ts.map +1 -0
- package/dist/__tests__/shutdown.test.js +250 -0
- package/dist/__tests__/testing/testing.module.test.d.ts +2 -0
- package/dist/__tests__/testing/testing.module.test.d.ts.map +1 -0
- package/dist/__tests__/testing/testing.module.test.js +370 -0
- package/dist/__tests__/upload/file-upload.test.d.ts +2 -0
- package/dist/__tests__/upload/file-upload.test.d.ts.map +1 -0
- package/dist/__tests__/upload/file-upload.test.js +498 -0
- package/dist/__tests__/utils/sanitize.test.d.ts +2 -0
- package/dist/__tests__/utils/sanitize.test.d.ts.map +1 -0
- package/dist/__tests__/utils/sanitize.test.js +291 -0
- package/dist/__tests__/validator.test.d.ts +2 -0
- package/dist/__tests__/validator.test.d.ts.map +1 -0
- package/dist/__tests__/validator.test.js +300 -0
- package/dist/container.d.ts +80 -0
- package/dist/container.d.ts.map +1 -0
- package/dist/container.js +271 -0
- package/dist/decorators.d.ts +92 -0
- package/dist/decorators.d.ts.map +1 -0
- package/dist/decorators.js +343 -0
- package/dist/errors/http.error.d.ts +31 -0
- package/dist/errors/http.error.d.ts.map +1 -0
- package/dist/errors/http.error.js +62 -0
- package/dist/filters/exception-filter.d.ts +39 -0
- package/dist/filters/exception-filter.d.ts.map +1 -0
- package/dist/filters/exception-filter.js +38 -0
- package/dist/filters/http-exception.filter.d.ts +9 -0
- package/dist/filters/http-exception.filter.d.ts.map +1 -0
- package/dist/filters/http-exception.filter.js +42 -0
- package/dist/hazel-app.d.ts +78 -0
- package/dist/hazel-app.d.ts.map +1 -0
- package/dist/hazel-app.js +453 -0
- package/dist/hazel-module.d.ts +20 -0
- package/dist/hazel-module.d.ts.map +1 -0
- package/dist/hazel-module.js +109 -0
- package/dist/hazel-response.d.ts +20 -0
- package/dist/hazel-response.d.ts.map +1 -0
- package/dist/hazel-response.js +68 -0
- package/dist/health.d.ts +73 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +174 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +140 -0
- package/dist/interceptors/interceptor.d.ts +22 -0
- package/dist/interceptors/interceptor.d.ts.map +1 -0
- package/dist/interceptors/interceptor.js +46 -0
- package/dist/logger.d.ts +8 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +238 -0
- package/dist/middleware/cors.middleware.d.ts +44 -0
- package/dist/middleware/cors.middleware.d.ts.map +1 -0
- package/dist/middleware/cors.middleware.js +118 -0
- package/dist/middleware/csrf.middleware.d.ts +82 -0
- package/dist/middleware/csrf.middleware.d.ts.map +1 -0
- package/dist/middleware/csrf.middleware.js +183 -0
- package/dist/middleware/global-middleware.d.ts +111 -0
- package/dist/middleware/global-middleware.d.ts.map +1 -0
- package/dist/middleware/global-middleware.js +179 -0
- package/dist/middleware/rate-limit.middleware.d.ts +73 -0
- package/dist/middleware/rate-limit.middleware.d.ts.map +1 -0
- package/dist/middleware/rate-limit.middleware.js +124 -0
- package/dist/middleware/security-headers.middleware.d.ts +76 -0
- package/dist/middleware/security-headers.middleware.d.ts.map +1 -0
- package/dist/middleware/security-headers.middleware.js +123 -0
- package/dist/middleware/timeout.middleware.d.ts +25 -0
- package/dist/middleware/timeout.middleware.d.ts.map +1 -0
- package/dist/middleware/timeout.middleware.js +74 -0
- package/dist/middleware.d.ts +13 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +47 -0
- package/dist/pipes/pipe.d.ts +50 -0
- package/dist/pipes/pipe.d.ts.map +1 -0
- package/dist/pipes/pipe.js +96 -0
- package/dist/pipes/validation.pipe.d.ts +6 -0
- package/dist/pipes/validation.pipe.d.ts.map +1 -0
- package/dist/pipes/validation.pipe.js +61 -0
- package/dist/request-context.d.ts +17 -0
- package/dist/request-context.d.ts.map +1 -0
- package/dist/request-context.js +2 -0
- package/dist/request-parser.d.ts +7 -0
- package/dist/request-parser.d.ts.map +1 -0
- package/dist/request-parser.js +60 -0
- package/dist/router.d.ts +33 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +426 -0
- package/dist/routing/route-matcher.d.ts +39 -0
- package/dist/routing/route-matcher.d.ts.map +1 -0
- package/dist/routing/route-matcher.js +93 -0
- package/dist/routing/version.decorator.d.ts +36 -0
- package/dist/routing/version.decorator.d.ts.map +1 -0
- package/dist/routing/version.decorator.js +89 -0
- package/dist/service.d.ts +9 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +39 -0
- package/dist/shutdown.d.ts +32 -0
- package/dist/shutdown.d.ts.map +1 -0
- package/dist/shutdown.js +109 -0
- package/dist/testing/testing.module.d.ts +83 -0
- package/dist/testing/testing.module.d.ts.map +1 -0
- package/dist/testing/testing.module.js +164 -0
- package/dist/types.d.ts +76 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/upload/file-upload.d.ts +75 -0
- package/dist/upload/file-upload.d.ts.map +1 -0
- package/dist/upload/file-upload.js +261 -0
- package/dist/utils/sanitize.d.ts +45 -0
- package/dist/utils/sanitize.d.ts.map +1 -0
- package/dist/utils/sanitize.js +165 -0
- package/dist/validator.d.ts +7 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +119 -0
- package/package.json +65 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const health_1 = require("../health");
|
|
4
|
+
describe('HealthCheckManager', () => {
|
|
5
|
+
let healthManager;
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
healthManager = new health_1.HealthCheckManager();
|
|
8
|
+
});
|
|
9
|
+
describe('registerCheck', () => {
|
|
10
|
+
it('should register a health check', () => {
|
|
11
|
+
const check = {
|
|
12
|
+
name: 'test-check',
|
|
13
|
+
check: async () => ({ status: 'healthy' }),
|
|
14
|
+
};
|
|
15
|
+
healthManager.registerCheck(check);
|
|
16
|
+
expect(healthManager).toBeDefined();
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
describe('runChecks', () => {
|
|
20
|
+
it('should return healthy status when all checks pass', async () => {
|
|
21
|
+
healthManager.registerCheck({
|
|
22
|
+
name: 'check-1',
|
|
23
|
+
check: async () => ({ status: 'healthy' }),
|
|
24
|
+
});
|
|
25
|
+
healthManager.registerCheck({
|
|
26
|
+
name: 'check-2',
|
|
27
|
+
check: async () => ({ status: 'healthy' }),
|
|
28
|
+
});
|
|
29
|
+
const result = await healthManager.runChecks();
|
|
30
|
+
expect(result.status).toBe('healthy');
|
|
31
|
+
expect(result.checks['check-1'].status).toBe('healthy');
|
|
32
|
+
expect(result.checks['check-2'].status).toBe('healthy');
|
|
33
|
+
});
|
|
34
|
+
it('should return degraded status when non-critical check fails', async () => {
|
|
35
|
+
healthManager.registerCheck({
|
|
36
|
+
name: 'critical-check',
|
|
37
|
+
check: async () => ({ status: 'healthy' }),
|
|
38
|
+
critical: true,
|
|
39
|
+
});
|
|
40
|
+
healthManager.registerCheck({
|
|
41
|
+
name: 'non-critical-check',
|
|
42
|
+
check: async () => ({ status: 'degraded' }),
|
|
43
|
+
critical: false,
|
|
44
|
+
});
|
|
45
|
+
const result = await healthManager.runChecks();
|
|
46
|
+
expect(result.status).toBe('degraded');
|
|
47
|
+
});
|
|
48
|
+
it('should return unhealthy status when critical check fails', async () => {
|
|
49
|
+
healthManager.registerCheck({
|
|
50
|
+
name: 'critical-check',
|
|
51
|
+
check: async () => ({ status: 'unhealthy' }),
|
|
52
|
+
critical: true,
|
|
53
|
+
});
|
|
54
|
+
const result = await healthManager.runChecks();
|
|
55
|
+
expect(result.status).toBe('unhealthy');
|
|
56
|
+
});
|
|
57
|
+
it('should handle check timeouts', async () => {
|
|
58
|
+
healthManager.registerCheck({
|
|
59
|
+
name: 'slow-check',
|
|
60
|
+
check: async () => {
|
|
61
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
62
|
+
return { status: 'healthy' };
|
|
63
|
+
},
|
|
64
|
+
timeout: 50,
|
|
65
|
+
});
|
|
66
|
+
const result = await healthManager.runChecks();
|
|
67
|
+
expect(result.checks['slow-check'].status).toBe('unhealthy');
|
|
68
|
+
});
|
|
69
|
+
it('should include response time in results', async () => {
|
|
70
|
+
healthManager.registerCheck({
|
|
71
|
+
name: 'fast-check',
|
|
72
|
+
check: async () => ({ status: 'healthy' }),
|
|
73
|
+
});
|
|
74
|
+
const result = await healthManager.runChecks();
|
|
75
|
+
expect(result.checks['fast-check'].responseTime).toBeDefined();
|
|
76
|
+
expect(typeof result.checks['fast-check'].responseTime).toBe('number');
|
|
77
|
+
});
|
|
78
|
+
it('should include timestamp and uptime', async () => {
|
|
79
|
+
const result = await healthManager.runChecks();
|
|
80
|
+
expect(result.timestamp).toBeDefined();
|
|
81
|
+
expect(result.uptime).toBeDefined();
|
|
82
|
+
expect(typeof result.uptime).toBe('number');
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
describe('getLiveness', () => {
|
|
86
|
+
it('should return alive status', async () => {
|
|
87
|
+
const result = await healthManager.getLiveness();
|
|
88
|
+
expect(result.status).toBe('alive');
|
|
89
|
+
expect(result.timestamp).toBeDefined();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
describe('getReadiness', () => {
|
|
93
|
+
it('should run all checks', async () => {
|
|
94
|
+
healthManager.registerCheck({
|
|
95
|
+
name: 'test-check',
|
|
96
|
+
check: async () => ({ status: 'healthy' }),
|
|
97
|
+
});
|
|
98
|
+
const result = await healthManager.getReadiness();
|
|
99
|
+
expect(result.checks['test-check']).toBeDefined();
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
describe('getStartup', () => {
|
|
103
|
+
it('should return startup status', async () => {
|
|
104
|
+
const result = await healthManager.getStartup();
|
|
105
|
+
expect(result.status).toBe('started');
|
|
106
|
+
expect(result.uptime).toBeDefined();
|
|
107
|
+
expect(result.timestamp).toBeDefined();
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
describe('BuiltInHealthChecks', () => {
|
|
112
|
+
describe('memoryCheck', () => {
|
|
113
|
+
it('should return healthy when memory usage is below threshold', async () => {
|
|
114
|
+
const check = health_1.BuiltInHealthChecks.memoryCheck(10000); // 10GB threshold
|
|
115
|
+
const result = await check.check();
|
|
116
|
+
expect(result.status).toBe('healthy');
|
|
117
|
+
expect(result.details).toBeDefined();
|
|
118
|
+
});
|
|
119
|
+
it('should return degraded when memory usage is above threshold', async () => {
|
|
120
|
+
const check = health_1.BuiltInHealthChecks.memoryCheck(1); // 1MB threshold (very low)
|
|
121
|
+
const result = await check.check();
|
|
122
|
+
expect(result.status).toBe('degraded');
|
|
123
|
+
expect(result.message).toContain('High memory usage');
|
|
124
|
+
});
|
|
125
|
+
it('should include memory details', async () => {
|
|
126
|
+
const check = health_1.BuiltInHealthChecks.memoryCheck();
|
|
127
|
+
const result = await check.check();
|
|
128
|
+
expect(result.details).toBeDefined();
|
|
129
|
+
expect(result.details?.heapUsed).toBeDefined();
|
|
130
|
+
expect(result.details?.heapTotal).toBeDefined();
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
describe('eventLoopCheck', () => {
|
|
134
|
+
it('should return healthy when event loop lag is low', async () => {
|
|
135
|
+
const check = health_1.BuiltInHealthChecks.eventLoopCheck(1000); // 1 second threshold
|
|
136
|
+
const result = await check.check();
|
|
137
|
+
expect(result.status).toBe('healthy');
|
|
138
|
+
expect(result.details).toBeDefined();
|
|
139
|
+
});
|
|
140
|
+
it('should include lag details', async () => {
|
|
141
|
+
const check = health_1.BuiltInHealthChecks.eventLoopCheck();
|
|
142
|
+
const result = await check.check();
|
|
143
|
+
expect(result.details).toBeDefined();
|
|
144
|
+
expect(result.details?.lag).toBeDefined();
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/index.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const HazelExports = __importStar(require("../index"));
|
|
37
|
+
describe('Index exports', () => {
|
|
38
|
+
describe('main exports', () => {
|
|
39
|
+
it('should export HazelApp', () => {
|
|
40
|
+
expect(HazelExports.HazelApp).toBeDefined();
|
|
41
|
+
});
|
|
42
|
+
it('should export HazelModule', () => {
|
|
43
|
+
expect(HazelExports.HazelModule).toBeDefined();
|
|
44
|
+
});
|
|
45
|
+
it('should export Module', () => {
|
|
46
|
+
expect(HazelExports.Module).toBeDefined();
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
describe('decorator exports', () => {
|
|
50
|
+
it('should export Controller', () => {
|
|
51
|
+
expect(HazelExports.Controller).toBeDefined();
|
|
52
|
+
});
|
|
53
|
+
it('should export Injectable', () => {
|
|
54
|
+
expect(HazelExports.Injectable).toBeDefined();
|
|
55
|
+
});
|
|
56
|
+
it('should export Service', () => {
|
|
57
|
+
expect(HazelExports.Service).toBeDefined();
|
|
58
|
+
});
|
|
59
|
+
it('should export Get', () => {
|
|
60
|
+
expect(HazelExports.Get).toBeDefined();
|
|
61
|
+
});
|
|
62
|
+
it('should export Post', () => {
|
|
63
|
+
expect(HazelExports.Post).toBeDefined();
|
|
64
|
+
});
|
|
65
|
+
it('should export Put', () => {
|
|
66
|
+
expect(HazelExports.Put).toBeDefined();
|
|
67
|
+
});
|
|
68
|
+
it('should export Delete', () => {
|
|
69
|
+
expect(HazelExports.Delete).toBeDefined();
|
|
70
|
+
});
|
|
71
|
+
it('should export Patch', () => {
|
|
72
|
+
expect(HazelExports.Patch).toBeDefined();
|
|
73
|
+
});
|
|
74
|
+
it('should export Body', () => {
|
|
75
|
+
expect(HazelExports.Body).toBeDefined();
|
|
76
|
+
});
|
|
77
|
+
it('should export Param', () => {
|
|
78
|
+
expect(HazelExports.Param).toBeDefined();
|
|
79
|
+
});
|
|
80
|
+
it('should export Res', () => {
|
|
81
|
+
expect(HazelExports.Res).toBeDefined();
|
|
82
|
+
});
|
|
83
|
+
it('should export Inject', () => {
|
|
84
|
+
expect(HazelExports.Inject).toBeDefined();
|
|
85
|
+
});
|
|
86
|
+
it('should export UsePipes', () => {
|
|
87
|
+
expect(HazelExports.UsePipes).toBeDefined();
|
|
88
|
+
});
|
|
89
|
+
it('should export UseInterceptors', () => {
|
|
90
|
+
expect(HazelExports.UseInterceptors).toBeDefined();
|
|
91
|
+
});
|
|
92
|
+
it('should export UseGuards', () => {
|
|
93
|
+
expect(HazelExports.UseGuards).toBeDefined();
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
describe('container exports', () => {
|
|
97
|
+
it('should export Container', () => {
|
|
98
|
+
expect(HazelExports.Container).toBeDefined();
|
|
99
|
+
});
|
|
100
|
+
it('should export Scope', () => {
|
|
101
|
+
expect(HazelExports.Scope).toBeDefined();
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
describe('error exports', () => {
|
|
105
|
+
it('should export HttpError', () => {
|
|
106
|
+
expect(HazelExports.HttpError).toBeDefined();
|
|
107
|
+
});
|
|
108
|
+
it('should export BadRequestError', () => {
|
|
109
|
+
expect(HazelExports.BadRequestError).toBeDefined();
|
|
110
|
+
});
|
|
111
|
+
it('should export UnauthorizedError', () => {
|
|
112
|
+
expect(HazelExports.UnauthorizedError).toBeDefined();
|
|
113
|
+
});
|
|
114
|
+
it('should export ForbiddenError', () => {
|
|
115
|
+
expect(HazelExports.ForbiddenError).toBeDefined();
|
|
116
|
+
});
|
|
117
|
+
it('should export NotFoundError', () => {
|
|
118
|
+
expect(HazelExports.NotFoundError).toBeDefined();
|
|
119
|
+
});
|
|
120
|
+
it('should export InternalServerError', () => {
|
|
121
|
+
expect(HazelExports.InternalServerError).toBeDefined();
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
describe('pipe exports', () => {
|
|
125
|
+
it('should export ValidationPipe', () => {
|
|
126
|
+
expect(HazelExports.ValidationPipe).toBeDefined();
|
|
127
|
+
});
|
|
128
|
+
it('should export ParseIntPipe', () => {
|
|
129
|
+
expect(HazelExports.ParseIntPipe).toBeDefined();
|
|
130
|
+
});
|
|
131
|
+
it('should export ValidationError', () => {
|
|
132
|
+
expect(HazelExports.ValidationError).toBeDefined();
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
describe('middleware exports', () => {
|
|
136
|
+
it('should export CorsMiddleware', () => {
|
|
137
|
+
expect(HazelExports.CorsMiddleware).toBeDefined();
|
|
138
|
+
});
|
|
139
|
+
it('should export CsrfMiddleware', () => {
|
|
140
|
+
expect(HazelExports.CsrfMiddleware).toBeDefined();
|
|
141
|
+
});
|
|
142
|
+
it('should export RateLimitMiddleware', () => {
|
|
143
|
+
expect(HazelExports.RateLimitMiddleware).toBeDefined();
|
|
144
|
+
});
|
|
145
|
+
it('should export SecurityHeadersMiddleware', () => {
|
|
146
|
+
expect(HazelExports.SecurityHeadersMiddleware).toBeDefined();
|
|
147
|
+
});
|
|
148
|
+
it('should export TimeoutMiddleware', () => {
|
|
149
|
+
expect(HazelExports.TimeoutMiddleware).toBeDefined();
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
describe('filter exports', () => {
|
|
153
|
+
it('should export Catch', () => {
|
|
154
|
+
expect(HazelExports.Catch).toBeDefined();
|
|
155
|
+
});
|
|
156
|
+
it('should export HttpExceptionFilter', () => {
|
|
157
|
+
expect(HazelExports.HttpExceptionFilter).toBeDefined();
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
describe('interceptor exports', () => {
|
|
161
|
+
it('should have interceptor types exported', () => {
|
|
162
|
+
// Interceptor is exported as a type
|
|
163
|
+
expect(HazelExports).toBeDefined();
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
describe('testing exports', () => {
|
|
167
|
+
it('should export Test', () => {
|
|
168
|
+
expect(HazelExports.Test).toBeDefined();
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
describe('health exports', () => {
|
|
172
|
+
it('should export HealthCheckManager', () => {
|
|
173
|
+
expect(HazelExports.HealthCheckManager).toBeDefined();
|
|
174
|
+
});
|
|
175
|
+
it('should export BuiltInHealthChecks', () => {
|
|
176
|
+
expect(HazelExports.BuiltInHealthChecks).toBeDefined();
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
describe('shutdown exports', () => {
|
|
180
|
+
it('should export ShutdownManager', () => {
|
|
181
|
+
expect(HazelExports.ShutdownManager).toBeDefined();
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
describe('upload exports', () => {
|
|
185
|
+
it('should export FileUploadInterceptor', () => {
|
|
186
|
+
expect(HazelExports.FileUploadInterceptor).toBeDefined();
|
|
187
|
+
});
|
|
188
|
+
it('should export UploadedFile', () => {
|
|
189
|
+
expect(HazelExports.UploadedFile).toBeDefined();
|
|
190
|
+
});
|
|
191
|
+
it('should export UploadedFiles', () => {
|
|
192
|
+
expect(HazelExports.UploadedFiles).toBeDefined();
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
describe('utility exports', () => {
|
|
196
|
+
it('should export sanitizeHtml', () => {
|
|
197
|
+
expect(HazelExports.sanitizeHtml).toBeDefined();
|
|
198
|
+
});
|
|
199
|
+
it('should export sanitizeString', () => {
|
|
200
|
+
expect(HazelExports.sanitizeString).toBeDefined();
|
|
201
|
+
});
|
|
202
|
+
it('should export sanitizeUrl', () => {
|
|
203
|
+
expect(HazelExports.sanitizeUrl).toBeDefined();
|
|
204
|
+
});
|
|
205
|
+
it('should export sanitizeEmail', () => {
|
|
206
|
+
expect(HazelExports.sanitizeEmail).toBeDefined();
|
|
207
|
+
});
|
|
208
|
+
it('should export sanitizeObject', () => {
|
|
209
|
+
expect(HazelExports.sanitizeObject).toBeDefined();
|
|
210
|
+
});
|
|
211
|
+
it('should export escapeHtml', () => {
|
|
212
|
+
expect(HazelExports.escapeHtml).toBeDefined();
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
describe('type exports', () => {
|
|
216
|
+
it('should have type exports available', () => {
|
|
217
|
+
// Request and Response are type-only exports
|
|
218
|
+
expect(HazelExports).toBeDefined();
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
describe('all exports are functions or classes', () => {
|
|
222
|
+
it('should have callable decorators', () => {
|
|
223
|
+
expect(typeof HazelExports.Controller).toBe('function');
|
|
224
|
+
expect(typeof HazelExports.Get).toBe('function');
|
|
225
|
+
expect(typeof HazelExports.Post).toBe('function');
|
|
226
|
+
expect(typeof HazelExports.Injectable).toBe('function');
|
|
227
|
+
});
|
|
228
|
+
it('should have instantiable classes', () => {
|
|
229
|
+
expect(typeof HazelExports.HazelApp).toBe('function');
|
|
230
|
+
expect(typeof HazelExports.Container).toBe('function');
|
|
231
|
+
expect(typeof HazelExports.ValidationPipe).toBe('function');
|
|
232
|
+
});
|
|
233
|
+
it('should have utility functions', () => {
|
|
234
|
+
expect(typeof HazelExports.sanitizeHtml).toBe('function');
|
|
235
|
+
expect(typeof HazelExports.sanitizeString).toBe('function');
|
|
236
|
+
expect(typeof HazelExports.escapeHtml).toBe('function');
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interceptor.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/interceptors/interceptor.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const interceptor_1 = require("../../interceptors/interceptor");
|
|
7
|
+
const logger_1 = __importDefault(require("../../logger"));
|
|
8
|
+
// Mock logger
|
|
9
|
+
jest.mock('../../logger', () => ({
|
|
10
|
+
info: jest.fn(),
|
|
11
|
+
error: jest.fn(),
|
|
12
|
+
}));
|
|
13
|
+
describe('Interceptors', () => {
|
|
14
|
+
let context;
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
context = {
|
|
17
|
+
method: 'GET',
|
|
18
|
+
url: '/test',
|
|
19
|
+
headers: {},
|
|
20
|
+
params: {},
|
|
21
|
+
query: {},
|
|
22
|
+
body: {},
|
|
23
|
+
};
|
|
24
|
+
jest.clearAllMocks();
|
|
25
|
+
});
|
|
26
|
+
describe('LoggingInterceptor', () => {
|
|
27
|
+
let interceptor;
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
interceptor = new interceptor_1.LoggingInterceptor();
|
|
30
|
+
});
|
|
31
|
+
it('should log request start', async () => {
|
|
32
|
+
const next = jest.fn().mockResolvedValue({ data: 'test' });
|
|
33
|
+
await interceptor.intercept(context, next);
|
|
34
|
+
expect(logger_1.default.info).toHaveBeenCalledWith('[GET] /test');
|
|
35
|
+
});
|
|
36
|
+
it('should log request completion with duration', async () => {
|
|
37
|
+
const next = jest.fn().mockResolvedValue({ data: 'test' });
|
|
38
|
+
await interceptor.intercept(context, next);
|
|
39
|
+
expect(logger_1.default.info).toHaveBeenCalledWith(expect.stringMatching(/\[GET\] \/test - \d+ms/));
|
|
40
|
+
});
|
|
41
|
+
it('should call next handler', async () => {
|
|
42
|
+
const next = jest.fn().mockResolvedValue({ data: 'test' });
|
|
43
|
+
await interceptor.intercept(context, next);
|
|
44
|
+
expect(next).toHaveBeenCalled();
|
|
45
|
+
});
|
|
46
|
+
it('should return result from next handler', async () => {
|
|
47
|
+
const expectedResult = { data: 'test' };
|
|
48
|
+
const next = jest.fn().mockResolvedValue(expectedResult);
|
|
49
|
+
const result = await interceptor.intercept(context, next);
|
|
50
|
+
expect(result).toBe(expectedResult);
|
|
51
|
+
});
|
|
52
|
+
it('should log errors with duration', async () => {
|
|
53
|
+
const error = new Error('Test error');
|
|
54
|
+
const next = jest.fn().mockRejectedValue(error);
|
|
55
|
+
await expect(interceptor.intercept(context, next)).rejects.toThrow('Test error');
|
|
56
|
+
expect(logger_1.default.error).toHaveBeenCalledWith(expect.stringMatching(/\[GET\] \/test - Test error \(\d+ms\)/));
|
|
57
|
+
});
|
|
58
|
+
it('should rethrow errors', async () => {
|
|
59
|
+
const error = new Error('Test error');
|
|
60
|
+
const next = jest.fn().mockRejectedValue(error);
|
|
61
|
+
await expect(interceptor.intercept(context, next)).rejects.toThrow(error);
|
|
62
|
+
});
|
|
63
|
+
it('should log POST requests', async () => {
|
|
64
|
+
context.method = 'POST';
|
|
65
|
+
context.url = '/api/users';
|
|
66
|
+
const next = jest.fn().mockResolvedValue({ id: 1 });
|
|
67
|
+
await interceptor.intercept(context, next);
|
|
68
|
+
expect(logger_1.default.info).toHaveBeenCalledWith('[POST] /api/users');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe('CacheInterceptor', () => {
|
|
72
|
+
let interceptor;
|
|
73
|
+
beforeEach(() => {
|
|
74
|
+
interceptor = new interceptor_1.CacheInterceptor();
|
|
75
|
+
// Clear cache between tests
|
|
76
|
+
interceptor_1.CacheInterceptor.cache.clear();
|
|
77
|
+
});
|
|
78
|
+
it('should cache GET request results', async () => {
|
|
79
|
+
const next = jest.fn().mockResolvedValue({ data: 'test' });
|
|
80
|
+
const result1 = await interceptor.intercept(context, next);
|
|
81
|
+
const result2 = await interceptor.intercept(context, next);
|
|
82
|
+
expect(next).toHaveBeenCalledTimes(1);
|
|
83
|
+
expect(result1).toEqual(result2);
|
|
84
|
+
});
|
|
85
|
+
it('should not cache non-GET requests', async () => {
|
|
86
|
+
context.method = 'POST';
|
|
87
|
+
const next = jest.fn().mockResolvedValue({ data: 'test' });
|
|
88
|
+
await interceptor.intercept(context, next);
|
|
89
|
+
await interceptor.intercept(context, next);
|
|
90
|
+
expect(next).toHaveBeenCalledTimes(2);
|
|
91
|
+
});
|
|
92
|
+
it('should use custom TTL', async () => {
|
|
93
|
+
jest.useFakeTimers();
|
|
94
|
+
interceptor = new interceptor_1.CacheInterceptor({ ttl: 1000 });
|
|
95
|
+
const next = jest.fn().mockResolvedValue({ data: 'test' });
|
|
96
|
+
// First call - cache miss
|
|
97
|
+
await interceptor.intercept(context, next);
|
|
98
|
+
expect(next).toHaveBeenCalledTimes(1);
|
|
99
|
+
// Second call within TTL - cache hit
|
|
100
|
+
jest.advanceTimersByTime(500);
|
|
101
|
+
await interceptor.intercept(context, next);
|
|
102
|
+
expect(next).toHaveBeenCalledTimes(1);
|
|
103
|
+
// Third call after TTL - cache miss
|
|
104
|
+
jest.advanceTimersByTime(600);
|
|
105
|
+
await interceptor.intercept(context, next);
|
|
106
|
+
expect(next).toHaveBeenCalledTimes(2);
|
|
107
|
+
jest.useRealTimers();
|
|
108
|
+
});
|
|
109
|
+
it('should use default TTL of 60 seconds', async () => {
|
|
110
|
+
jest.useFakeTimers();
|
|
111
|
+
const next = jest.fn().mockResolvedValue({ data: 'test' });
|
|
112
|
+
await interceptor.intercept(context, next);
|
|
113
|
+
jest.advanceTimersByTime(59000);
|
|
114
|
+
await interceptor.intercept(context, next);
|
|
115
|
+
expect(next).toHaveBeenCalledTimes(1);
|
|
116
|
+
jest.useRealTimers();
|
|
117
|
+
});
|
|
118
|
+
it('should cache different URLs separately', async () => {
|
|
119
|
+
const next1 = jest.fn().mockResolvedValue({ data: 'test1' });
|
|
120
|
+
const next2 = jest.fn().mockResolvedValue({ data: 'test2' });
|
|
121
|
+
const context1 = { ...context, url: '/test1' };
|
|
122
|
+
const context2 = { ...context, url: '/test2' };
|
|
123
|
+
await interceptor.intercept(context1, next1);
|
|
124
|
+
await interceptor.intercept(context2, next2);
|
|
125
|
+
expect(next1).toHaveBeenCalledTimes(1);
|
|
126
|
+
expect(next2).toHaveBeenCalledTimes(1);
|
|
127
|
+
});
|
|
128
|
+
it('should return cached data', async () => {
|
|
129
|
+
const expectedData = { data: 'cached' };
|
|
130
|
+
const next = jest.fn().mockResolvedValue(expectedData);
|
|
131
|
+
const result1 = await interceptor.intercept(context, next);
|
|
132
|
+
const result2 = await interceptor.intercept(context, next);
|
|
133
|
+
expect(result1).toEqual(expectedData);
|
|
134
|
+
expect(result2).toEqual(expectedData);
|
|
135
|
+
});
|
|
136
|
+
it('should handle PUT requests without caching', async () => {
|
|
137
|
+
context.method = 'PUT';
|
|
138
|
+
const next = jest.fn().mockResolvedValue({ data: 'updated' });
|
|
139
|
+
await interceptor.intercept(context, next);
|
|
140
|
+
await interceptor.intercept(context, next);
|
|
141
|
+
expect(next).toHaveBeenCalledTimes(2);
|
|
142
|
+
});
|
|
143
|
+
it('should handle DELETE requests without caching', async () => {
|
|
144
|
+
context.method = 'DELETE';
|
|
145
|
+
const next = jest.fn().mockResolvedValue({ success: true });
|
|
146
|
+
await interceptor.intercept(context, next);
|
|
147
|
+
await interceptor.intercept(context, next);
|
|
148
|
+
expect(next).toHaveBeenCalledTimes(2);
|
|
149
|
+
});
|
|
150
|
+
it('should cache complex objects', async () => {
|
|
151
|
+
const complexData = {
|
|
152
|
+
users: [
|
|
153
|
+
{ id: 1, name: 'John' },
|
|
154
|
+
{ id: 2, name: 'Jane' },
|
|
155
|
+
],
|
|
156
|
+
meta: { total: 2, page: 1 },
|
|
157
|
+
};
|
|
158
|
+
const next = jest.fn().mockResolvedValue(complexData);
|
|
159
|
+
const result1 = await interceptor.intercept(context, next);
|
|
160
|
+
const result2 = await interceptor.intercept(context, next);
|
|
161
|
+
expect(next).toHaveBeenCalledTimes(1);
|
|
162
|
+
expect(result1).toEqual(complexData);
|
|
163
|
+
expect(result2).toEqual(complexData);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/logger.test.ts"],"names":[],"mappings":""}
|