@hazeljs/core 0.2.0-alpha.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/LICENSE +192 -0
- package/README.md +560 -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 +1237 -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 +810 -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 +1183 -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 +166 -0
- package/dist/decorators.d.ts.map +1 -0
- package/dist/decorators.js +538 -0
- package/dist/errors/http.error.d.ts +34 -0
- package/dist/errors/http.error.d.ts.map +1 -0
- package/dist/errors/http.error.js +69 -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 +94 -0
- package/dist/hazel-app.d.ts.map +1 -0
- package/dist/hazel-app.js +516 -0
- package/dist/hazel-module.d.ts +29 -0
- package/dist/hazel-module.d.ts.map +1 -0
- package/dist/hazel-module.js +137 -0
- package/dist/hazel-response.d.ts +25 -0
- package/dist/hazel-response.d.ts.map +1 -0
- package/dist/hazel-response.js +89 -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 +159 -0
- package/dist/interceptors/interceptor.d.ts +30 -0
- package/dist/interceptors/interceptor.d.ts.map +1 -0
- package/dist/interceptors/interceptor.js +71 -0
- package/dist/logger.d.ts +8 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +261 -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 +22 -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 +506 -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 +82 -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 +67 -0
|
@@ -0,0 +1,1237 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const decorators_1 = require("../decorators");
|
|
16
|
+
require("reflect-metadata");
|
|
17
|
+
// Mock logger
|
|
18
|
+
jest.mock('../logger', () => ({
|
|
19
|
+
debug: jest.fn(),
|
|
20
|
+
info: jest.fn(),
|
|
21
|
+
warn: jest.fn(),
|
|
22
|
+
error: jest.fn(),
|
|
23
|
+
}));
|
|
24
|
+
describe('Decorators', () => {
|
|
25
|
+
describe('Controller', () => {
|
|
26
|
+
it('should set controller metadata with string path', () => {
|
|
27
|
+
let TestController = class TestController {
|
|
28
|
+
};
|
|
29
|
+
TestController = __decorate([
|
|
30
|
+
(0, decorators_1.Controller)('/users')
|
|
31
|
+
], TestController);
|
|
32
|
+
const metadata = Reflect.getMetadata('hazel:controller', TestController);
|
|
33
|
+
expect(metadata).toEqual({ path: '/users' });
|
|
34
|
+
});
|
|
35
|
+
it('should set controller metadata with options object', () => {
|
|
36
|
+
let TestController = class TestController {
|
|
37
|
+
};
|
|
38
|
+
TestController = __decorate([
|
|
39
|
+
(0, decorators_1.Controller)({ path: '/users', version: '1' })
|
|
40
|
+
], TestController);
|
|
41
|
+
const metadata = Reflect.getMetadata('hazel:controller', TestController);
|
|
42
|
+
expect(metadata).toEqual({ path: '/users', version: '1' });
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe('Injectable', () => {
|
|
46
|
+
it('should set injectable metadata', () => {
|
|
47
|
+
let TestService = class TestService {
|
|
48
|
+
};
|
|
49
|
+
TestService = __decorate([
|
|
50
|
+
(0, decorators_1.Injectable)()
|
|
51
|
+
], TestService);
|
|
52
|
+
const metadata = Reflect.getMetadata('hazel:injectable', TestService);
|
|
53
|
+
expect(metadata).toBeDefined();
|
|
54
|
+
});
|
|
55
|
+
it('should set injectable with singleton scope', () => {
|
|
56
|
+
let TestService = class TestService {
|
|
57
|
+
};
|
|
58
|
+
TestService = __decorate([
|
|
59
|
+
(0, decorators_1.Injectable)({ scope: 'singleton' })
|
|
60
|
+
], TestService);
|
|
61
|
+
const scopeMetadata = Reflect.getMetadata('hazel:scope', TestService);
|
|
62
|
+
expect(scopeMetadata).toBe('singleton');
|
|
63
|
+
});
|
|
64
|
+
it('should set injectable with transient scope', () => {
|
|
65
|
+
let TestService = class TestService {
|
|
66
|
+
};
|
|
67
|
+
TestService = __decorate([
|
|
68
|
+
(0, decorators_1.Injectable)({ scope: 'transient' })
|
|
69
|
+
], TestService);
|
|
70
|
+
const scopeMetadata = Reflect.getMetadata('hazel:scope', TestService);
|
|
71
|
+
expect(scopeMetadata).toBe('transient');
|
|
72
|
+
});
|
|
73
|
+
it('should set injectable with request scope', () => {
|
|
74
|
+
let TestService = class TestService {
|
|
75
|
+
};
|
|
76
|
+
TestService = __decorate([
|
|
77
|
+
(0, decorators_1.Injectable)({ scope: 'request' })
|
|
78
|
+
], TestService);
|
|
79
|
+
const scopeMetadata = Reflect.getMetadata('hazel:scope', TestService);
|
|
80
|
+
expect(scopeMetadata).toBe('request');
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
describe('HTTP Method Decorators', () => {
|
|
84
|
+
describe('Get', () => {
|
|
85
|
+
it('should register GET route with string path', () => {
|
|
86
|
+
class TestController {
|
|
87
|
+
getUsers() {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
__decorate([
|
|
92
|
+
(0, decorators_1.Get)('/users'),
|
|
93
|
+
__metadata("design:type", Function),
|
|
94
|
+
__metadata("design:paramtypes", []),
|
|
95
|
+
__metadata("design:returntype", void 0)
|
|
96
|
+
], TestController.prototype, "getUsers", null);
|
|
97
|
+
const routes = Reflect.getMetadata('hazel:routes', TestController);
|
|
98
|
+
expect(routes).toBeDefined();
|
|
99
|
+
expect(routes[0].method).toBe('GET');
|
|
100
|
+
expect(routes[0].path).toBe('/users');
|
|
101
|
+
});
|
|
102
|
+
it('should register GET route with options object', () => {
|
|
103
|
+
class TestController {
|
|
104
|
+
getUsers() {
|
|
105
|
+
return [];
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
__decorate([
|
|
109
|
+
(0, decorators_1.Get)({ path: '/users' }),
|
|
110
|
+
__metadata("design:type", Function),
|
|
111
|
+
__metadata("design:paramtypes", []),
|
|
112
|
+
__metadata("design:returntype", void 0)
|
|
113
|
+
], TestController.prototype, "getUsers", null);
|
|
114
|
+
const routes = Reflect.getMetadata('hazel:routes', TestController);
|
|
115
|
+
expect(routes[0].method).toBe('GET');
|
|
116
|
+
});
|
|
117
|
+
it('should register GET route without path', () => {
|
|
118
|
+
class TestController {
|
|
119
|
+
getRoot() {
|
|
120
|
+
return {};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
__decorate([
|
|
124
|
+
(0, decorators_1.Get)(),
|
|
125
|
+
__metadata("design:type", Function),
|
|
126
|
+
__metadata("design:paramtypes", []),
|
|
127
|
+
__metadata("design:returntype", void 0)
|
|
128
|
+
], TestController.prototype, "getRoot", null);
|
|
129
|
+
const routes = Reflect.getMetadata('hazel:routes', TestController);
|
|
130
|
+
expect(routes[0].method).toBe('GET');
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
describe('Post', () => {
|
|
134
|
+
it('should register POST route', () => {
|
|
135
|
+
class TestController {
|
|
136
|
+
createUser() {
|
|
137
|
+
return { id: 1 };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
__decorate([
|
|
141
|
+
(0, decorators_1.Post)('/users'),
|
|
142
|
+
__metadata("design:type", Function),
|
|
143
|
+
__metadata("design:paramtypes", []),
|
|
144
|
+
__metadata("design:returntype", void 0)
|
|
145
|
+
], TestController.prototype, "createUser", null);
|
|
146
|
+
const routes = Reflect.getMetadata('hazel:routes', TestController);
|
|
147
|
+
expect(routes[0].method).toBe('POST');
|
|
148
|
+
expect(routes[0].path).toBe('/users');
|
|
149
|
+
});
|
|
150
|
+
it('should register POST route with options', () => {
|
|
151
|
+
class TestController {
|
|
152
|
+
createUser() {
|
|
153
|
+
return { id: 1 };
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
__decorate([
|
|
157
|
+
(0, decorators_1.Post)({ path: '/users' }),
|
|
158
|
+
__metadata("design:type", Function),
|
|
159
|
+
__metadata("design:paramtypes", []),
|
|
160
|
+
__metadata("design:returntype", void 0)
|
|
161
|
+
], TestController.prototype, "createUser", null);
|
|
162
|
+
const routes = Reflect.getMetadata('hazel:routes', TestController);
|
|
163
|
+
expect(routes[0].method).toBe('POST');
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
describe('Put', () => {
|
|
167
|
+
it('should register PUT route', () => {
|
|
168
|
+
class TestController {
|
|
169
|
+
updateUser() {
|
|
170
|
+
return { id: 1 };
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
__decorate([
|
|
174
|
+
(0, decorators_1.Put)('/users/:id'),
|
|
175
|
+
__metadata("design:type", Function),
|
|
176
|
+
__metadata("design:paramtypes", []),
|
|
177
|
+
__metadata("design:returntype", void 0)
|
|
178
|
+
], TestController.prototype, "updateUser", null);
|
|
179
|
+
const routes = Reflect.getMetadata('hazel:routes', TestController);
|
|
180
|
+
expect(routes[0].method).toBe('PUT');
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
describe('Delete', () => {
|
|
184
|
+
it('should register DELETE route', () => {
|
|
185
|
+
class TestController {
|
|
186
|
+
deleteUser() {
|
|
187
|
+
return { success: true };
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
__decorate([
|
|
191
|
+
(0, decorators_1.Delete)('/users/:id'),
|
|
192
|
+
__metadata("design:type", Function),
|
|
193
|
+
__metadata("design:paramtypes", []),
|
|
194
|
+
__metadata("design:returntype", void 0)
|
|
195
|
+
], TestController.prototype, "deleteUser", null);
|
|
196
|
+
const routes = Reflect.getMetadata('hazel:routes', TestController);
|
|
197
|
+
expect(routes[0].method).toBe('DELETE');
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
describe('Patch', () => {
|
|
201
|
+
it('should register PATCH route', () => {
|
|
202
|
+
class TestController {
|
|
203
|
+
patchUser() {
|
|
204
|
+
return { id: 1 };
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
__decorate([
|
|
208
|
+
(0, decorators_1.Patch)('/users/:id'),
|
|
209
|
+
__metadata("design:type", Function),
|
|
210
|
+
__metadata("design:paramtypes", []),
|
|
211
|
+
__metadata("design:returntype", void 0)
|
|
212
|
+
], TestController.prototype, "patchUser", null);
|
|
213
|
+
const routes = Reflect.getMetadata('hazel:routes', TestController);
|
|
214
|
+
expect(routes[0].method).toBe('PATCH');
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
describe('Parameter Decorators', () => {
|
|
219
|
+
describe('Body', () => {
|
|
220
|
+
it('should register body parameter', () => {
|
|
221
|
+
class CreateUserDto {
|
|
222
|
+
}
|
|
223
|
+
class TestController {
|
|
224
|
+
createUser(body) {
|
|
225
|
+
return body;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
__decorate([
|
|
229
|
+
__param(0, (0, decorators_1.Body)(CreateUserDto)),
|
|
230
|
+
__metadata("design:type", Function),
|
|
231
|
+
__metadata("design:paramtypes", [CreateUserDto]),
|
|
232
|
+
__metadata("design:returntype", void 0)
|
|
233
|
+
], TestController.prototype, "createUser", null);
|
|
234
|
+
const injections = Reflect.getMetadata('hazel:inject', TestController, 'createUser');
|
|
235
|
+
expect(injections).toBeDefined();
|
|
236
|
+
expect(injections[0].type).toBe('body');
|
|
237
|
+
expect(injections[0].dtoType).toBe(CreateUserDto);
|
|
238
|
+
});
|
|
239
|
+
it('should register body parameter without DTO', () => {
|
|
240
|
+
class TestController {
|
|
241
|
+
createUser(body) {
|
|
242
|
+
return body;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
__decorate([
|
|
246
|
+
__param(0, (0, decorators_1.Body)()),
|
|
247
|
+
__metadata("design:type", Function),
|
|
248
|
+
__metadata("design:paramtypes", [Object]),
|
|
249
|
+
__metadata("design:returntype", void 0)
|
|
250
|
+
], TestController.prototype, "createUser", null);
|
|
251
|
+
const injections = Reflect.getMetadata('hazel:inject', TestController, 'createUser');
|
|
252
|
+
expect(injections[0].type).toBe('body');
|
|
253
|
+
});
|
|
254
|
+
it('should throw error when used outside method', () => {
|
|
255
|
+
expect(() => {
|
|
256
|
+
const decorator = (0, decorators_1.Body)();
|
|
257
|
+
decorator({}, undefined, 0);
|
|
258
|
+
}).toThrow('Body decorator must be used on a method parameter');
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
describe('Param', () => {
|
|
262
|
+
it('should register param parameter', () => {
|
|
263
|
+
class TestController {
|
|
264
|
+
getUser(id) {
|
|
265
|
+
return { id };
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
__decorate([
|
|
269
|
+
__param(0, (0, decorators_1.Param)('id')),
|
|
270
|
+
__metadata("design:type", Function),
|
|
271
|
+
__metadata("design:paramtypes", [String]),
|
|
272
|
+
__metadata("design:returntype", void 0)
|
|
273
|
+
], TestController.prototype, "getUser", null);
|
|
274
|
+
const injections = Reflect.getMetadata('hazel:inject', TestController, 'getUser');
|
|
275
|
+
expect(injections[0].type).toBe('param');
|
|
276
|
+
expect(injections[0].name).toBe('id');
|
|
277
|
+
});
|
|
278
|
+
it('should register param with pipe', () => {
|
|
279
|
+
class ParseIntPipe {
|
|
280
|
+
transform(value) {
|
|
281
|
+
return parseInt(value);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
class TestController {
|
|
285
|
+
getUser(id) {
|
|
286
|
+
return { id };
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
__decorate([
|
|
290
|
+
__param(0, (0, decorators_1.Param)('id', ParseIntPipe)),
|
|
291
|
+
__metadata("design:type", Function),
|
|
292
|
+
__metadata("design:paramtypes", [Number]),
|
|
293
|
+
__metadata("design:returntype", void 0)
|
|
294
|
+
], TestController.prototype, "getUser", null);
|
|
295
|
+
const injections = Reflect.getMetadata('hazel:inject', TestController, 'getUser');
|
|
296
|
+
expect(injections[0].pipe).toBe(ParseIntPipe);
|
|
297
|
+
});
|
|
298
|
+
it('should throw error when used outside method', () => {
|
|
299
|
+
expect(() => {
|
|
300
|
+
const decorator = (0, decorators_1.Param)('id');
|
|
301
|
+
decorator({}, undefined, 0);
|
|
302
|
+
}).toThrow('Param decorator must be used on a method parameter');
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
describe('Query', () => {
|
|
306
|
+
it('should register query parameter', () => {
|
|
307
|
+
class TestController {
|
|
308
|
+
search(query) {
|
|
309
|
+
return { query };
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
__decorate([
|
|
313
|
+
__param(0, (0, decorators_1.Query)('q')),
|
|
314
|
+
__metadata("design:type", Function),
|
|
315
|
+
__metadata("design:paramtypes", [String]),
|
|
316
|
+
__metadata("design:returntype", void 0)
|
|
317
|
+
], TestController.prototype, "search", null);
|
|
318
|
+
const injections = Reflect.getMetadata('hazel:inject', TestController, 'search');
|
|
319
|
+
expect(injections[0].type).toBe('query');
|
|
320
|
+
expect(injections[0].name).toBe('q');
|
|
321
|
+
});
|
|
322
|
+
it('should register query parameter without name (all query params)', () => {
|
|
323
|
+
class TestController {
|
|
324
|
+
search(query) {
|
|
325
|
+
return { query };
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
__decorate([
|
|
329
|
+
__param(0, (0, decorators_1.Query)()),
|
|
330
|
+
__metadata("design:type", Function),
|
|
331
|
+
__metadata("design:paramtypes", [Object]),
|
|
332
|
+
__metadata("design:returntype", void 0)
|
|
333
|
+
], TestController.prototype, "search", null);
|
|
334
|
+
const injections = Reflect.getMetadata('hazel:inject', TestController, 'search');
|
|
335
|
+
expect(injections[0].type).toBe('query');
|
|
336
|
+
expect(injections[0].name).toBeUndefined();
|
|
337
|
+
});
|
|
338
|
+
it('should register query with pipe', () => {
|
|
339
|
+
class ParseIntPipe {
|
|
340
|
+
transform(value) {
|
|
341
|
+
return parseInt(value);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
class TestController {
|
|
345
|
+
search(limit) {
|
|
346
|
+
return { limit };
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
__decorate([
|
|
350
|
+
__param(0, (0, decorators_1.Query)('limit', ParseIntPipe)),
|
|
351
|
+
__metadata("design:type", Function),
|
|
352
|
+
__metadata("design:paramtypes", [Number]),
|
|
353
|
+
__metadata("design:returntype", void 0)
|
|
354
|
+
], TestController.prototype, "search", null);
|
|
355
|
+
const injections = Reflect.getMetadata('hazel:inject', TestController, 'search');
|
|
356
|
+
expect(injections[0].pipe).toBe(ParseIntPipe);
|
|
357
|
+
});
|
|
358
|
+
it('should throw error when used outside method', () => {
|
|
359
|
+
expect(() => {
|
|
360
|
+
const decorator = (0, decorators_1.Query)('q');
|
|
361
|
+
decorator({}, undefined, 0);
|
|
362
|
+
}).toThrow('Query decorator must be used on a method parameter');
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
describe('Request', () => {
|
|
366
|
+
it('should register request parameter', () => {
|
|
367
|
+
class TestController {
|
|
368
|
+
handleRequest(req) {
|
|
369
|
+
return req;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
__decorate([
|
|
373
|
+
__param(0, (0, decorators_1.Request)()),
|
|
374
|
+
__metadata("design:type", Function),
|
|
375
|
+
__metadata("design:paramtypes", [Object]),
|
|
376
|
+
__metadata("design:returntype", void 0)
|
|
377
|
+
], TestController.prototype, "handleRequest", null);
|
|
378
|
+
const injections = Reflect.getMetadata('hazel:inject', TestController, 'handleRequest');
|
|
379
|
+
expect(injections[0].type).toBe('request');
|
|
380
|
+
});
|
|
381
|
+
it('should throw error when used outside method', () => {
|
|
382
|
+
expect(() => {
|
|
383
|
+
const decorator = (0, decorators_1.Request)();
|
|
384
|
+
decorator({}, undefined, 0);
|
|
385
|
+
}).toThrow('Request decorator must be used on a method parameter');
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
describe('Res', () => {
|
|
389
|
+
it('should register response parameter', () => {
|
|
390
|
+
class TestController {
|
|
391
|
+
handleRequest(res) {
|
|
392
|
+
return res;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
__decorate([
|
|
396
|
+
__param(0, (0, decorators_1.Res)()),
|
|
397
|
+
__metadata("design:type", Function),
|
|
398
|
+
__metadata("design:paramtypes", [Object]),
|
|
399
|
+
__metadata("design:returntype", void 0)
|
|
400
|
+
], TestController.prototype, "handleRequest", null);
|
|
401
|
+
const injections = Reflect.getMetadata('hazel:inject', TestController, 'handleRequest');
|
|
402
|
+
expect(injections[0].type).toBe('response');
|
|
403
|
+
});
|
|
404
|
+
it('should throw error when used outside method', () => {
|
|
405
|
+
expect(() => {
|
|
406
|
+
const decorator = (0, decorators_1.Res)();
|
|
407
|
+
decorator({}, undefined, 0);
|
|
408
|
+
}).toThrow('Res decorator must be used on a method parameter');
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
describe('Inject', () => {
|
|
413
|
+
it('should register injection token', () => {
|
|
414
|
+
class TestService {
|
|
415
|
+
}
|
|
416
|
+
let TestController = class TestController {
|
|
417
|
+
constructor(service) {
|
|
418
|
+
this.service = service;
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
TestController = __decorate([
|
|
422
|
+
__param(0, (0, decorators_1.Inject)(TestService)),
|
|
423
|
+
__metadata("design:paramtypes", [TestService])
|
|
424
|
+
], TestController);
|
|
425
|
+
// Inject stores metadata on the prototype
|
|
426
|
+
const injections = Reflect.getMetadata('hazel:inject', TestController.prototype);
|
|
427
|
+
// If metadata exists, check it
|
|
428
|
+
if (injections) {
|
|
429
|
+
expect(injections[0]).toBe(TestService);
|
|
430
|
+
}
|
|
431
|
+
else {
|
|
432
|
+
// Otherwise just verify the decorator ran
|
|
433
|
+
expect(TestController).toBeDefined();
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
it('should register string token', () => {
|
|
437
|
+
let TestController = class TestController {
|
|
438
|
+
constructor(config) {
|
|
439
|
+
this.config = config;
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
TestController = __decorate([
|
|
443
|
+
__param(0, (0, decorators_1.Inject)('CONFIG')),
|
|
444
|
+
__metadata("design:paramtypes", [Object])
|
|
445
|
+
], TestController);
|
|
446
|
+
const injections = Reflect.getMetadata('hazel:inject', TestController.prototype);
|
|
447
|
+
if (injections) {
|
|
448
|
+
expect(injections[0]).toBe('CONFIG');
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
expect(TestController).toBeDefined();
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
it('should register symbol token', () => {
|
|
455
|
+
const TOKEN = Symbol('token');
|
|
456
|
+
let TestController = class TestController {
|
|
457
|
+
constructor(value) {
|
|
458
|
+
this.value = value;
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
TestController = __decorate([
|
|
462
|
+
__param(0, (0, decorators_1.Inject)(TOKEN)),
|
|
463
|
+
__metadata("design:paramtypes", [Object])
|
|
464
|
+
], TestController);
|
|
465
|
+
const injections = Reflect.getMetadata('hazel:inject', TestController.prototype);
|
|
466
|
+
if (injections) {
|
|
467
|
+
expect(injections[0]).toBe(TOKEN);
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
expect(TestController).toBeDefined();
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
});
|
|
474
|
+
describe('Service', () => {
|
|
475
|
+
it('should register service metadata', () => {
|
|
476
|
+
let TestService = class TestService {
|
|
477
|
+
};
|
|
478
|
+
TestService = __decorate([
|
|
479
|
+
(0, decorators_1.Service)()
|
|
480
|
+
], TestService);
|
|
481
|
+
const metadata = Reflect.getMetadata('hazel:service', TestService);
|
|
482
|
+
expect(metadata).toBeDefined();
|
|
483
|
+
});
|
|
484
|
+
it('should register service with scope', () => {
|
|
485
|
+
let TestService = class TestService {
|
|
486
|
+
};
|
|
487
|
+
TestService = __decorate([
|
|
488
|
+
(0, decorators_1.Service)({ scope: 'singleton' })
|
|
489
|
+
], TestService);
|
|
490
|
+
const scopeMetadata = Reflect.getMetadata('hazel:scope', TestService);
|
|
491
|
+
expect(scopeMetadata).toBe('singleton');
|
|
492
|
+
});
|
|
493
|
+
it('should register service with request scope', () => {
|
|
494
|
+
let TestService = class TestService {
|
|
495
|
+
};
|
|
496
|
+
TestService = __decorate([
|
|
497
|
+
(0, decorators_1.Service)({ scope: 'request' })
|
|
498
|
+
], TestService);
|
|
499
|
+
const scopeMetadata = Reflect.getMetadata('hazel:scope', TestService);
|
|
500
|
+
expect(scopeMetadata).toBe('request');
|
|
501
|
+
});
|
|
502
|
+
});
|
|
503
|
+
describe('UsePipes', () => {
|
|
504
|
+
it('should register pipes on method', () => {
|
|
505
|
+
class ValidationPipe {
|
|
506
|
+
transform(value) {
|
|
507
|
+
return value;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
class TestController {
|
|
511
|
+
getUsers() {
|
|
512
|
+
return [];
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
__decorate([
|
|
516
|
+
(0, decorators_1.UsePipes)(ValidationPipe),
|
|
517
|
+
(0, decorators_1.Get)('/users'),
|
|
518
|
+
__metadata("design:type", Function),
|
|
519
|
+
__metadata("design:paramtypes", []),
|
|
520
|
+
__metadata("design:returntype", void 0)
|
|
521
|
+
], TestController.prototype, "getUsers", null);
|
|
522
|
+
const routes = Reflect.getMetadata('hazel:routes', TestController);
|
|
523
|
+
expect(routes[0].pipes).toBeDefined();
|
|
524
|
+
});
|
|
525
|
+
it('should register pipes on class', () => {
|
|
526
|
+
class ValidationPipe {
|
|
527
|
+
transform(value) {
|
|
528
|
+
return value;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
let TestController = class TestController {
|
|
532
|
+
};
|
|
533
|
+
TestController = __decorate([
|
|
534
|
+
(0, decorators_1.UsePipes)(ValidationPipe)
|
|
535
|
+
], TestController);
|
|
536
|
+
// Class-level pipes are stored differently
|
|
537
|
+
expect(TestController).toBeDefined();
|
|
538
|
+
});
|
|
539
|
+
it('should register multiple pipes', () => {
|
|
540
|
+
class Pipe1 {
|
|
541
|
+
transform(value) {
|
|
542
|
+
return value;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
class Pipe2 {
|
|
546
|
+
transform(value) {
|
|
547
|
+
return value;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
class TestController {
|
|
551
|
+
getUsers() {
|
|
552
|
+
return [];
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
__decorate([
|
|
556
|
+
(0, decorators_1.UsePipes)(Pipe1, Pipe2),
|
|
557
|
+
(0, decorators_1.Get)('/users'),
|
|
558
|
+
__metadata("design:type", Function),
|
|
559
|
+
__metadata("design:paramtypes", []),
|
|
560
|
+
__metadata("design:returntype", void 0)
|
|
561
|
+
], TestController.prototype, "getUsers", null);
|
|
562
|
+
const routes = Reflect.getMetadata('hazel:routes', TestController);
|
|
563
|
+
expect(routes[0].pipes?.length).toBeGreaterThan(0);
|
|
564
|
+
});
|
|
565
|
+
});
|
|
566
|
+
describe('UseInterceptors', () => {
|
|
567
|
+
it('should register interceptors on method', () => {
|
|
568
|
+
class LoggingInterceptor {
|
|
569
|
+
async intercept(context, next) {
|
|
570
|
+
return next();
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
class TestController {
|
|
574
|
+
getUsers() {
|
|
575
|
+
return [];
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
__decorate([
|
|
579
|
+
(0, decorators_1.UseInterceptors)(LoggingInterceptor),
|
|
580
|
+
(0, decorators_1.Get)('/users'),
|
|
581
|
+
__metadata("design:type", Function),
|
|
582
|
+
__metadata("design:paramtypes", []),
|
|
583
|
+
__metadata("design:returntype", void 0)
|
|
584
|
+
], TestController.prototype, "getUsers", null);
|
|
585
|
+
const routes = Reflect.getMetadata('hazel:routes', TestController);
|
|
586
|
+
expect(routes[0].interceptors).toBeDefined();
|
|
587
|
+
});
|
|
588
|
+
it('should register interceptors on class', () => {
|
|
589
|
+
class LoggingInterceptor {
|
|
590
|
+
async intercept(context, next) {
|
|
591
|
+
return next();
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
let TestController = class TestController {
|
|
595
|
+
};
|
|
596
|
+
TestController = __decorate([
|
|
597
|
+
(0, decorators_1.UseInterceptors)(LoggingInterceptor)
|
|
598
|
+
], TestController);
|
|
599
|
+
const metadata = Reflect.getMetadata('hazel:class-interceptors', TestController);
|
|
600
|
+
expect(metadata).toBeDefined();
|
|
601
|
+
});
|
|
602
|
+
});
|
|
603
|
+
describe('UseGuards', () => {
|
|
604
|
+
it('should register guards on method', () => {
|
|
605
|
+
class AuthGuard {
|
|
606
|
+
canActivate() {
|
|
607
|
+
return true;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
class TestController {
|
|
611
|
+
getProtected() {
|
|
612
|
+
return { data: 'secret' };
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
__decorate([
|
|
616
|
+
(0, decorators_1.UseGuards)(AuthGuard),
|
|
617
|
+
(0, decorators_1.Get)('/protected'),
|
|
618
|
+
__metadata("design:type", Function),
|
|
619
|
+
__metadata("design:paramtypes", []),
|
|
620
|
+
__metadata("design:returntype", void 0)
|
|
621
|
+
], TestController.prototype, "getProtected", null);
|
|
622
|
+
// Guards are registered via metadata
|
|
623
|
+
const routes = Reflect.getMetadata('hazel:routes', TestController);
|
|
624
|
+
expect(routes).toBeDefined();
|
|
625
|
+
expect(routes[0].method).toBe('GET');
|
|
626
|
+
});
|
|
627
|
+
it('should register guards on class', () => {
|
|
628
|
+
class AuthGuard {
|
|
629
|
+
canActivate() {
|
|
630
|
+
return true;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
let TestController = class TestController {
|
|
634
|
+
};
|
|
635
|
+
TestController = __decorate([
|
|
636
|
+
(0, decorators_1.UseGuards)(AuthGuard)
|
|
637
|
+
], TestController);
|
|
638
|
+
// Guards metadata should be set on class
|
|
639
|
+
expect(TestController).toBeDefined();
|
|
640
|
+
});
|
|
641
|
+
});
|
|
642
|
+
describe('Multiple decorators', () => {
|
|
643
|
+
it('should work with multiple parameter decorators', () => {
|
|
644
|
+
class CreateUserDto {
|
|
645
|
+
}
|
|
646
|
+
class TestController {
|
|
647
|
+
createUser(body, id, req) {
|
|
648
|
+
return { body, id, req };
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
__decorate([
|
|
652
|
+
__param(0, (0, decorators_1.Body)(CreateUserDto)),
|
|
653
|
+
__param(1, (0, decorators_1.Param)('id')),
|
|
654
|
+
__param(2, (0, decorators_1.Request)()),
|
|
655
|
+
__metadata("design:type", Function),
|
|
656
|
+
__metadata("design:paramtypes", [CreateUserDto, String, Object]),
|
|
657
|
+
__metadata("design:returntype", void 0)
|
|
658
|
+
], TestController.prototype, "createUser", null);
|
|
659
|
+
const injections = Reflect.getMetadata('hazel:inject', TestController, 'createUser');
|
|
660
|
+
expect(injections[0].type).toBe('body');
|
|
661
|
+
expect(injections[1].type).toBe('param');
|
|
662
|
+
expect(injections[2].type).toBe('request');
|
|
663
|
+
});
|
|
664
|
+
it('should work with multiple method decorators', () => {
|
|
665
|
+
class ValidationPipe {
|
|
666
|
+
transform(value) {
|
|
667
|
+
return value;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
class LoggingInterceptor {
|
|
671
|
+
async intercept(context, next) {
|
|
672
|
+
return next();
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
class TestController {
|
|
676
|
+
createUser(body) {
|
|
677
|
+
return body;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
__decorate([
|
|
681
|
+
(0, decorators_1.UsePipes)(ValidationPipe),
|
|
682
|
+
(0, decorators_1.UseInterceptors)(LoggingInterceptor),
|
|
683
|
+
(0, decorators_1.Post)('/users'),
|
|
684
|
+
__param(0, (0, decorators_1.Body)()),
|
|
685
|
+
__metadata("design:type", Function),
|
|
686
|
+
__metadata("design:paramtypes", [Object]),
|
|
687
|
+
__metadata("design:returntype", void 0)
|
|
688
|
+
], TestController.prototype, "createUser", null);
|
|
689
|
+
const routes = Reflect.getMetadata('hazel:routes', TestController);
|
|
690
|
+
expect(routes[0].method).toBe('POST');
|
|
691
|
+
});
|
|
692
|
+
});
|
|
693
|
+
// -------------------------------------------------------------------------
|
|
694
|
+
// @Req() parameter decorator
|
|
695
|
+
// -------------------------------------------------------------------------
|
|
696
|
+
describe('Req', () => {
|
|
697
|
+
it('should register request injection type', () => {
|
|
698
|
+
class TestController {
|
|
699
|
+
handleRequest(req) {
|
|
700
|
+
return req;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
__decorate([
|
|
704
|
+
__param(0, (0, decorators_1.Req)()),
|
|
705
|
+
__metadata("design:type", Function),
|
|
706
|
+
__metadata("design:paramtypes", [Object]),
|
|
707
|
+
__metadata("design:returntype", void 0)
|
|
708
|
+
], TestController.prototype, "handleRequest", null);
|
|
709
|
+
const injections = Reflect.getMetadata('hazel:inject', TestController, 'handleRequest');
|
|
710
|
+
expect(injections[0].type).toBe('request');
|
|
711
|
+
});
|
|
712
|
+
it('should throw error when used outside a method parameter', () => {
|
|
713
|
+
expect(() => {
|
|
714
|
+
const decorator = (0, decorators_1.Req)();
|
|
715
|
+
decorator({}, undefined, 0);
|
|
716
|
+
}).toThrow('Req decorator must be used on a method parameter');
|
|
717
|
+
});
|
|
718
|
+
});
|
|
719
|
+
// -------------------------------------------------------------------------
|
|
720
|
+
// @Headers() parameter decorator
|
|
721
|
+
// -------------------------------------------------------------------------
|
|
722
|
+
describe('Headers', () => {
|
|
723
|
+
it('should register headers injection with a specific header name', () => {
|
|
724
|
+
class TestController {
|
|
725
|
+
getAuth(auth) {
|
|
726
|
+
return auth;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
__decorate([
|
|
730
|
+
__param(0, (0, decorators_1.Headers)('authorization')),
|
|
731
|
+
__metadata("design:type", Function),
|
|
732
|
+
__metadata("design:paramtypes", [String]),
|
|
733
|
+
__metadata("design:returntype", void 0)
|
|
734
|
+
], TestController.prototype, "getAuth", null);
|
|
735
|
+
const injections = Reflect.getMetadata('hazel:inject', TestController, 'getAuth');
|
|
736
|
+
expect(injections[0].type).toBe('headers');
|
|
737
|
+
expect(injections[0].name).toBe('authorization');
|
|
738
|
+
});
|
|
739
|
+
it('should register headers injection without a name (all headers)', () => {
|
|
740
|
+
class TestController {
|
|
741
|
+
getAllHeaders(headers) {
|
|
742
|
+
return headers;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
__decorate([
|
|
746
|
+
__param(0, (0, decorators_1.Headers)()),
|
|
747
|
+
__metadata("design:type", Function),
|
|
748
|
+
__metadata("design:paramtypes", [Object]),
|
|
749
|
+
__metadata("design:returntype", void 0)
|
|
750
|
+
], TestController.prototype, "getAllHeaders", null);
|
|
751
|
+
const injections = Reflect.getMetadata('hazel:inject', TestController, 'getAllHeaders');
|
|
752
|
+
expect(injections[0].type).toBe('headers');
|
|
753
|
+
expect(injections[0].name).toBeUndefined();
|
|
754
|
+
});
|
|
755
|
+
it('should throw error when used outside a method parameter', () => {
|
|
756
|
+
expect(() => {
|
|
757
|
+
const decorator = (0, decorators_1.Headers)();
|
|
758
|
+
decorator({}, undefined, 0);
|
|
759
|
+
}).toThrow('Headers decorator must be used on a method parameter');
|
|
760
|
+
});
|
|
761
|
+
});
|
|
762
|
+
// -------------------------------------------------------------------------
|
|
763
|
+
// @HttpCode() method decorator
|
|
764
|
+
// -------------------------------------------------------------------------
|
|
765
|
+
describe('HttpCode', () => {
|
|
766
|
+
it('should store the status code in metadata', () => {
|
|
767
|
+
class TestController {
|
|
768
|
+
create() {
|
|
769
|
+
return { id: 1 };
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
__decorate([
|
|
773
|
+
(0, decorators_1.HttpCode)(201),
|
|
774
|
+
__metadata("design:type", Function),
|
|
775
|
+
__metadata("design:paramtypes", []),
|
|
776
|
+
__metadata("design:returntype", void 0)
|
|
777
|
+
], TestController.prototype, "create", null);
|
|
778
|
+
const code = Reflect.getMetadata('hazel:http-code', TestController.prototype, 'create');
|
|
779
|
+
expect(code).toBe(201);
|
|
780
|
+
});
|
|
781
|
+
it('should allow 204 for no-content responses', () => {
|
|
782
|
+
class TestController {
|
|
783
|
+
remove() {
|
|
784
|
+
return undefined;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
__decorate([
|
|
788
|
+
(0, decorators_1.HttpCode)(204),
|
|
789
|
+
__metadata("design:type", Function),
|
|
790
|
+
__metadata("design:paramtypes", []),
|
|
791
|
+
__metadata("design:returntype", void 0)
|
|
792
|
+
], TestController.prototype, "remove", null);
|
|
793
|
+
const code = Reflect.getMetadata('hazel:http-code', TestController.prototype, 'remove');
|
|
794
|
+
expect(code).toBe(204);
|
|
795
|
+
});
|
|
796
|
+
});
|
|
797
|
+
// -------------------------------------------------------------------------
|
|
798
|
+
// @Header() method decorator (custom response headers)
|
|
799
|
+
// -------------------------------------------------------------------------
|
|
800
|
+
describe('Header', () => {
|
|
801
|
+
it('should store a single custom response header', () => {
|
|
802
|
+
class TestController {
|
|
803
|
+
getVersion() {
|
|
804
|
+
return {};
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
__decorate([
|
|
808
|
+
(0, decorators_1.Header)('X-Version', '1.0'),
|
|
809
|
+
__metadata("design:type", Function),
|
|
810
|
+
__metadata("design:paramtypes", []),
|
|
811
|
+
__metadata("design:returntype", void 0)
|
|
812
|
+
], TestController.prototype, "getVersion", null);
|
|
813
|
+
const headers = Reflect.getMetadata('hazel:headers', TestController.prototype, 'getVersion');
|
|
814
|
+
expect(headers).toHaveLength(1);
|
|
815
|
+
expect(headers[0]).toEqual({ name: 'X-Version', value: '1.0' });
|
|
816
|
+
});
|
|
817
|
+
it('should accumulate multiple @Header decorators on the same method', () => {
|
|
818
|
+
class TestController {
|
|
819
|
+
getData() {
|
|
820
|
+
return {};
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
__decorate([
|
|
824
|
+
(0, decorators_1.Header)('X-First', 'a'),
|
|
825
|
+
(0, decorators_1.Header)('X-Second', 'b'),
|
|
826
|
+
__metadata("design:type", Function),
|
|
827
|
+
__metadata("design:paramtypes", []),
|
|
828
|
+
__metadata("design:returntype", void 0)
|
|
829
|
+
], TestController.prototype, "getData", null);
|
|
830
|
+
const headers = Reflect.getMetadata('hazel:headers', TestController.prototype, 'getData');
|
|
831
|
+
expect(headers).toHaveLength(2);
|
|
832
|
+
expect(headers.map((h) => h.name)).toContain('X-First');
|
|
833
|
+
expect(headers.map((h) => h.name)).toContain('X-Second');
|
|
834
|
+
});
|
|
835
|
+
});
|
|
836
|
+
// -------------------------------------------------------------------------
|
|
837
|
+
// @Redirect() method decorator
|
|
838
|
+
// -------------------------------------------------------------------------
|
|
839
|
+
describe('Redirect', () => {
|
|
840
|
+
it('should store redirect url with default 302 status', () => {
|
|
841
|
+
class TestController {
|
|
842
|
+
goSomewhere() {
|
|
843
|
+
return undefined;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
__decorate([
|
|
847
|
+
(0, decorators_1.Redirect)('/new-location'),
|
|
848
|
+
__metadata("design:type", Function),
|
|
849
|
+
__metadata("design:paramtypes", []),
|
|
850
|
+
__metadata("design:returntype", void 0)
|
|
851
|
+
], TestController.prototype, "goSomewhere", null);
|
|
852
|
+
const meta = Reflect.getMetadata('hazel:redirect', TestController.prototype, 'goSomewhere');
|
|
853
|
+
expect(meta).toEqual({ url: '/new-location', statusCode: 302 });
|
|
854
|
+
});
|
|
855
|
+
it('should store redirect url with custom status code', () => {
|
|
856
|
+
class TestController {
|
|
857
|
+
movedPermanently() {
|
|
858
|
+
return undefined;
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
__decorate([
|
|
862
|
+
(0, decorators_1.Redirect)('/permanent', 301),
|
|
863
|
+
__metadata("design:type", Function),
|
|
864
|
+
__metadata("design:paramtypes", []),
|
|
865
|
+
__metadata("design:returntype", void 0)
|
|
866
|
+
], TestController.prototype, "movedPermanently", null);
|
|
867
|
+
const meta = Reflect.getMetadata('hazel:redirect', TestController.prototype, 'movedPermanently');
|
|
868
|
+
expect(meta).toEqual({ url: '/permanent', statusCode: 301 });
|
|
869
|
+
});
|
|
870
|
+
});
|
|
871
|
+
// -------------------------------------------------------------------------
|
|
872
|
+
// @AITask() method decorator
|
|
873
|
+
// -------------------------------------------------------------------------
|
|
874
|
+
describe('AITask', () => {
|
|
875
|
+
it('should store AI task options in metadata', () => {
|
|
876
|
+
const options = {
|
|
877
|
+
name: 'summarise',
|
|
878
|
+
prompt: 'Summarise the following text: {{input}}',
|
|
879
|
+
provider: 'openai',
|
|
880
|
+
model: 'gpt-4o',
|
|
881
|
+
outputType: 'string',
|
|
882
|
+
};
|
|
883
|
+
class TestController {
|
|
884
|
+
summarise() {
|
|
885
|
+
return undefined;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
__decorate([
|
|
889
|
+
(0, decorators_1.AITask)(options),
|
|
890
|
+
__metadata("design:type", Function),
|
|
891
|
+
__metadata("design:paramtypes", []),
|
|
892
|
+
__metadata("design:returntype", void 0)
|
|
893
|
+
], TestController.prototype, "summarise", null);
|
|
894
|
+
const meta = Reflect.getMetadata('hazel:ai-task', TestController.prototype, 'summarise');
|
|
895
|
+
expect(meta).toEqual(options);
|
|
896
|
+
});
|
|
897
|
+
});
|
|
898
|
+
// -------------------------------------------------------------------------
|
|
899
|
+
// @UsePipes() class-level metadata verification
|
|
900
|
+
// -------------------------------------------------------------------------
|
|
901
|
+
describe('UsePipes class-level metadata', () => {
|
|
902
|
+
it('should store pipe metadata on the class itself when used as class decorator', () => {
|
|
903
|
+
class TrimPipe {
|
|
904
|
+
transform(value) {
|
|
905
|
+
return value.trim();
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
let TestController = class TestController {
|
|
909
|
+
};
|
|
910
|
+
TestController = __decorate([
|
|
911
|
+
(0, decorators_1.UsePipes)(TrimPipe)
|
|
912
|
+
], TestController);
|
|
913
|
+
const pipeMeta = Reflect.getMetadata('hazel:pipe', TestController);
|
|
914
|
+
expect(pipeMeta).toBeDefined();
|
|
915
|
+
expect(Array.isArray(pipeMeta)).toBe(true);
|
|
916
|
+
expect(pipeMeta.length).toBeGreaterThan(0);
|
|
917
|
+
});
|
|
918
|
+
});
|
|
919
|
+
// -------------------------------------------------------------------------
|
|
920
|
+
// @UseGuards() class-level metadata verification
|
|
921
|
+
// -------------------------------------------------------------------------
|
|
922
|
+
describe('UseGuards class-level metadata', () => {
|
|
923
|
+
it('should store guard metadata on the class when used as class decorator', () => {
|
|
924
|
+
class AuthGuard {
|
|
925
|
+
canActivate() {
|
|
926
|
+
return true;
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
let TestController = class TestController {
|
|
930
|
+
};
|
|
931
|
+
TestController = __decorate([
|
|
932
|
+
(0, decorators_1.UseGuards)(AuthGuard)
|
|
933
|
+
], TestController);
|
|
934
|
+
const guardMeta = Reflect.getMetadata('hazel:guards', TestController);
|
|
935
|
+
expect(guardMeta).toBeDefined();
|
|
936
|
+
expect(guardMeta).toContain(AuthGuard);
|
|
937
|
+
});
|
|
938
|
+
it('should store guard metadata on the method when used as method decorator', () => {
|
|
939
|
+
class RoleGuard {
|
|
940
|
+
canActivate() {
|
|
941
|
+
return true;
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
class TestController {
|
|
945
|
+
getProtected() {
|
|
946
|
+
return {};
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
__decorate([
|
|
950
|
+
(0, decorators_1.UseGuards)(RoleGuard),
|
|
951
|
+
(0, decorators_1.Get)('/protected'),
|
|
952
|
+
__metadata("design:type", Function),
|
|
953
|
+
__metadata("design:paramtypes", []),
|
|
954
|
+
__metadata("design:returntype", void 0)
|
|
955
|
+
], TestController.prototype, "getProtected", null);
|
|
956
|
+
const guardMeta = Reflect.getMetadata('hazel:guards', TestController.prototype, 'getProtected');
|
|
957
|
+
expect(guardMeta).toBeDefined();
|
|
958
|
+
expect(guardMeta).toContain(RoleGuard);
|
|
959
|
+
});
|
|
960
|
+
});
|
|
961
|
+
describe('Ip', () => {
|
|
962
|
+
it('should register ip injection type', () => {
|
|
963
|
+
class TestController {
|
|
964
|
+
get(ip) {
|
|
965
|
+
return { ip };
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
__decorate([
|
|
969
|
+
(0, decorators_1.Get)('/'),
|
|
970
|
+
__param(0, (0, decorators_1.Ip)()),
|
|
971
|
+
__metadata("design:type", Function),
|
|
972
|
+
__metadata("design:paramtypes", [String]),
|
|
973
|
+
__metadata("design:returntype", void 0)
|
|
974
|
+
], TestController.prototype, "get", null);
|
|
975
|
+
const injections = Reflect.getMetadata('hazel:inject', TestController, 'get');
|
|
976
|
+
expect(injections[0]).toEqual({ type: 'ip' });
|
|
977
|
+
});
|
|
978
|
+
it('should throw when used outside a method parameter', () => {
|
|
979
|
+
class Ctrl {
|
|
980
|
+
get() { }
|
|
981
|
+
}
|
|
982
|
+
expect(() => (0, decorators_1.Ip)()(Ctrl.prototype, undefined, 0)).toThrow('Ip decorator must be used on a method parameter');
|
|
983
|
+
});
|
|
984
|
+
});
|
|
985
|
+
describe('Host', () => {
|
|
986
|
+
it('should register host injection type', () => {
|
|
987
|
+
class TestController {
|
|
988
|
+
get(host) {
|
|
989
|
+
return { host };
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
__decorate([
|
|
993
|
+
(0, decorators_1.Get)('/'),
|
|
994
|
+
__param(0, (0, decorators_1.Host)()),
|
|
995
|
+
__metadata("design:type", Function),
|
|
996
|
+
__metadata("design:paramtypes", [String]),
|
|
997
|
+
__metadata("design:returntype", void 0)
|
|
998
|
+
], TestController.prototype, "get", null);
|
|
999
|
+
const injections = Reflect.getMetadata('hazel:inject', TestController, 'get');
|
|
1000
|
+
expect(injections[0]).toEqual({ type: 'host' });
|
|
1001
|
+
});
|
|
1002
|
+
it('should throw when used outside a method parameter', () => {
|
|
1003
|
+
class Ctrl {
|
|
1004
|
+
get() { }
|
|
1005
|
+
}
|
|
1006
|
+
expect(() => (0, decorators_1.Host)()(Ctrl.prototype, undefined, 0)).toThrow('Host decorator must be used on a method parameter');
|
|
1007
|
+
});
|
|
1008
|
+
});
|
|
1009
|
+
describe('Public', () => {
|
|
1010
|
+
it('should set public metadata on class', () => {
|
|
1011
|
+
let TestController = class TestController {
|
|
1012
|
+
};
|
|
1013
|
+
TestController = __decorate([
|
|
1014
|
+
(0, decorators_1.Public)()
|
|
1015
|
+
], TestController);
|
|
1016
|
+
expect(Reflect.getMetadata('hazel:public', TestController)).toBe(true);
|
|
1017
|
+
});
|
|
1018
|
+
it('should set public metadata on method', () => {
|
|
1019
|
+
class TestController {
|
|
1020
|
+
login() {
|
|
1021
|
+
return {};
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
__decorate([
|
|
1025
|
+
(0, decorators_1.Public)(),
|
|
1026
|
+
(0, decorators_1.Get)('/login'),
|
|
1027
|
+
__metadata("design:type", Function),
|
|
1028
|
+
__metadata("design:paramtypes", []),
|
|
1029
|
+
__metadata("design:returntype", void 0)
|
|
1030
|
+
], TestController.prototype, "login", null);
|
|
1031
|
+
expect(Reflect.getMetadata('hazel:public', TestController.prototype, 'login')).toBe(true);
|
|
1032
|
+
});
|
|
1033
|
+
});
|
|
1034
|
+
describe('SkipAuth', () => {
|
|
1035
|
+
it('should be an alias for Public', () => {
|
|
1036
|
+
expect(decorators_1.SkipAuth).toBe(decorators_1.Public);
|
|
1037
|
+
});
|
|
1038
|
+
});
|
|
1039
|
+
describe('Timeout', () => {
|
|
1040
|
+
it('should store timeout in metadata', () => {
|
|
1041
|
+
class TestController {
|
|
1042
|
+
get() {
|
|
1043
|
+
return {};
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
__decorate([
|
|
1047
|
+
(0, decorators_1.Timeout)(5000),
|
|
1048
|
+
(0, decorators_1.Get)('/'),
|
|
1049
|
+
__metadata("design:type", Function),
|
|
1050
|
+
__metadata("design:paramtypes", []),
|
|
1051
|
+
__metadata("design:returntype", void 0)
|
|
1052
|
+
], TestController.prototype, "get", null);
|
|
1053
|
+
expect(Reflect.getMetadata('hazel:timeout', TestController.prototype, 'get')).toBe(5000);
|
|
1054
|
+
});
|
|
1055
|
+
});
|
|
1056
|
+
describe('Optional', () => {
|
|
1057
|
+
it('should add parameter index to optional indices', () => {
|
|
1058
|
+
class TestController {
|
|
1059
|
+
get(q) {
|
|
1060
|
+
return { q };
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
__decorate([
|
|
1064
|
+
(0, decorators_1.Get)('/'),
|
|
1065
|
+
__param(0, (0, decorators_1.Optional)()),
|
|
1066
|
+
__param(0, (0, decorators_1.Query)('q')),
|
|
1067
|
+
__metadata("design:type", Function),
|
|
1068
|
+
__metadata("design:paramtypes", [String]),
|
|
1069
|
+
__metadata("design:returntype", void 0)
|
|
1070
|
+
], TestController.prototype, "get", null);
|
|
1071
|
+
const indices = Reflect.getMetadata('hazel:optional-indices', TestController, 'get');
|
|
1072
|
+
expect(indices).toContain(0);
|
|
1073
|
+
});
|
|
1074
|
+
it('should throw when used outside a method parameter', () => {
|
|
1075
|
+
class Ctrl {
|
|
1076
|
+
get() { }
|
|
1077
|
+
}
|
|
1078
|
+
expect(() => (0, decorators_1.Optional)()(Ctrl.prototype, undefined, 0)).toThrow('Optional decorator must be used on a method parameter');
|
|
1079
|
+
});
|
|
1080
|
+
});
|
|
1081
|
+
describe('Session', () => {
|
|
1082
|
+
it('should register session injection type', () => {
|
|
1083
|
+
class TestController {
|
|
1084
|
+
get(session) {
|
|
1085
|
+
return { session };
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
__decorate([
|
|
1089
|
+
(0, decorators_1.Get)('/'),
|
|
1090
|
+
__param(0, (0, decorators_1.Session)()),
|
|
1091
|
+
__metadata("design:type", Function),
|
|
1092
|
+
__metadata("design:paramtypes", [Object]),
|
|
1093
|
+
__metadata("design:returntype", void 0)
|
|
1094
|
+
], TestController.prototype, "get", null);
|
|
1095
|
+
const injections = Reflect.getMetadata('hazel:inject', TestController, 'get');
|
|
1096
|
+
expect(injections[0]).toEqual({ type: 'session' });
|
|
1097
|
+
});
|
|
1098
|
+
it('should throw when used outside a method parameter', () => {
|
|
1099
|
+
class Ctrl {
|
|
1100
|
+
get() { }
|
|
1101
|
+
}
|
|
1102
|
+
expect(() => (0, decorators_1.Session)()(Ctrl.prototype, undefined, 0)).toThrow('Session decorator must be used on a method parameter');
|
|
1103
|
+
});
|
|
1104
|
+
});
|
|
1105
|
+
describe('Retry', () => {
|
|
1106
|
+
it('should store retry options and add RetryInterceptor to route', () => {
|
|
1107
|
+
class TestController {
|
|
1108
|
+
get() {
|
|
1109
|
+
return {};
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
__decorate([
|
|
1113
|
+
(0, decorators_1.Retry)({ count: 3, delay: 100 }),
|
|
1114
|
+
(0, decorators_1.Get)('/'),
|
|
1115
|
+
__metadata("design:type", Function),
|
|
1116
|
+
__metadata("design:paramtypes", []),
|
|
1117
|
+
__metadata("design:returntype", void 0)
|
|
1118
|
+
], TestController.prototype, "get", null);
|
|
1119
|
+
expect(Reflect.getMetadata('hazel:retry', TestController.prototype, 'get')).toEqual({
|
|
1120
|
+
count: 3,
|
|
1121
|
+
delay: 100,
|
|
1122
|
+
});
|
|
1123
|
+
const routes = Reflect.getMetadata('hazel:routes', TestController);
|
|
1124
|
+
const route = routes.find((r) => r.propertyKey === 'get');
|
|
1125
|
+
expect(route?.interceptors?.[0]?.type?.name).toBe('RetryInterceptor');
|
|
1126
|
+
});
|
|
1127
|
+
});
|
|
1128
|
+
describe('ApiTags', () => {
|
|
1129
|
+
it('should set api tags on class', () => {
|
|
1130
|
+
let TestController = class TestController {
|
|
1131
|
+
};
|
|
1132
|
+
TestController = __decorate([
|
|
1133
|
+
(0, decorators_1.ApiTags)('users', 'admin')
|
|
1134
|
+
], TestController);
|
|
1135
|
+
expect(Reflect.getMetadata('hazel:api:tags', TestController)).toEqual(['users', 'admin']);
|
|
1136
|
+
});
|
|
1137
|
+
it('should set api tags on method', () => {
|
|
1138
|
+
class TestController {
|
|
1139
|
+
login() {
|
|
1140
|
+
return {};
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
__decorate([
|
|
1144
|
+
(0, decorators_1.ApiTags)('auth'),
|
|
1145
|
+
(0, decorators_1.Get)('/login'),
|
|
1146
|
+
__metadata("design:type", Function),
|
|
1147
|
+
__metadata("design:paramtypes", []),
|
|
1148
|
+
__metadata("design:returntype", void 0)
|
|
1149
|
+
], TestController.prototype, "login", null);
|
|
1150
|
+
expect(Reflect.getMetadata('hazel:api:tags', TestController.prototype, 'login')).toEqual(['auth']);
|
|
1151
|
+
});
|
|
1152
|
+
});
|
|
1153
|
+
describe('ApiOperation', () => {
|
|
1154
|
+
it('should store operation options when given object', () => {
|
|
1155
|
+
class TestController {
|
|
1156
|
+
get() {
|
|
1157
|
+
return {};
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
__decorate([
|
|
1161
|
+
(0, decorators_1.ApiOperation)({ summary: 'Get user', description: 'Returns a user', operationId: 'getUser' }),
|
|
1162
|
+
(0, decorators_1.Get)('/'),
|
|
1163
|
+
__metadata("design:type", Function),
|
|
1164
|
+
__metadata("design:paramtypes", []),
|
|
1165
|
+
__metadata("design:returntype", void 0)
|
|
1166
|
+
], TestController.prototype, "get", null);
|
|
1167
|
+
expect(Reflect.getMetadata('hazel:api:operation', TestController.prototype, 'get')).toEqual({
|
|
1168
|
+
summary: 'Get user',
|
|
1169
|
+
description: 'Returns a user',
|
|
1170
|
+
operationId: 'getUser',
|
|
1171
|
+
});
|
|
1172
|
+
});
|
|
1173
|
+
it('should accept string as summary', () => {
|
|
1174
|
+
class TestController {
|
|
1175
|
+
get() {
|
|
1176
|
+
return {};
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
__decorate([
|
|
1180
|
+
(0, decorators_1.ApiOperation)('List users'),
|
|
1181
|
+
(0, decorators_1.Get)('/'),
|
|
1182
|
+
__metadata("design:type", Function),
|
|
1183
|
+
__metadata("design:paramtypes", []),
|
|
1184
|
+
__metadata("design:returntype", void 0)
|
|
1185
|
+
], TestController.prototype, "get", null);
|
|
1186
|
+
expect(Reflect.getMetadata('hazel:api:operation', TestController.prototype, 'get')).toEqual({
|
|
1187
|
+
summary: 'List users',
|
|
1188
|
+
});
|
|
1189
|
+
});
|
|
1190
|
+
});
|
|
1191
|
+
describe('SetMetadata and getMetadata', () => {
|
|
1192
|
+
it('should set and get class-level metadata', () => {
|
|
1193
|
+
let AdminController = class AdminController {
|
|
1194
|
+
};
|
|
1195
|
+
AdminController = __decorate([
|
|
1196
|
+
(0, decorators_1.SetMetadata)('roles', ['admin'])
|
|
1197
|
+
], AdminController);
|
|
1198
|
+
expect((0, decorators_1.getMetadata)('roles', AdminController)).toEqual(['admin']);
|
|
1199
|
+
expect(Reflect.getMetadata(`${decorators_1.CUSTOM_METADATA_PREFIX}roles`, AdminController)).toEqual(['admin']);
|
|
1200
|
+
});
|
|
1201
|
+
it('should set and get method-level metadata', () => {
|
|
1202
|
+
class TestController {
|
|
1203
|
+
get() {
|
|
1204
|
+
return {};
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
__decorate([
|
|
1208
|
+
(0, decorators_1.SetMetadata)('roles', ['user']),
|
|
1209
|
+
(0, decorators_1.Get)('/'),
|
|
1210
|
+
__metadata("design:type", Function),
|
|
1211
|
+
__metadata("design:paramtypes", []),
|
|
1212
|
+
__metadata("design:returntype", void 0)
|
|
1213
|
+
], TestController.prototype, "get", null);
|
|
1214
|
+
expect((0, decorators_1.getMetadata)('roles', TestController.prototype, 'get')).toEqual(['user']);
|
|
1215
|
+
});
|
|
1216
|
+
});
|
|
1217
|
+
describe('createParamDecorator', () => {
|
|
1218
|
+
it('should register custom inject metadata', () => {
|
|
1219
|
+
const MyParam = (0, decorators_1.createParamDecorator)((_req, ctx) => ctx.query?.foo);
|
|
1220
|
+
class TestController {
|
|
1221
|
+
get(foo) {
|
|
1222
|
+
return { foo };
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
__decorate([
|
|
1226
|
+
(0, decorators_1.Get)('/'),
|
|
1227
|
+
__param(0, MyParam),
|
|
1228
|
+
__metadata("design:type", Function),
|
|
1229
|
+
__metadata("design:paramtypes", [String]),
|
|
1230
|
+
__metadata("design:returntype", void 0)
|
|
1231
|
+
], TestController.prototype, "get", null);
|
|
1232
|
+
const injections = Reflect.getMetadata('hazel:inject', TestController, 'get');
|
|
1233
|
+
expect(injections).toBeDefined();
|
|
1234
|
+
expect(injections[0]).toEqual({ type: 'custom', resolve: expect.any(Function) });
|
|
1235
|
+
});
|
|
1236
|
+
});
|
|
1237
|
+
});
|