@tsed/platform-test-sdk 8.0.0 → 8.0.2

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.
Files changed (42) hide show
  1. package/package.json +15 -14
  2. package/src/components/PlatformTestSdk.ts +30 -0
  3. package/src/data/file.txt +1 -0
  4. package/src/data/response.data.json +3 -0
  5. package/src/data/swagger.json +32 -0
  6. package/src/errors/CustomBadRequest.ts +16 -0
  7. package/src/errors/CustomInternalError.ts +16 -0
  8. package/src/index.ts +40 -0
  9. package/src/interfaces/PlatformTestingSdkOpts.ts +10 -0
  10. package/src/interfaces/index.ts +4 -0
  11. package/src/modules/feature/FeatureModule.ts +10 -0
  12. package/src/modules/feature/controllers/FeatureController.ts +11 -0
  13. package/src/tests/exports.ts +71 -0
  14. package/src/tests/testAcceptMime.ts +99 -0
  15. package/src/tests/testAuth.ts +345 -0
  16. package/src/tests/testBodyParams.ts +488 -0
  17. package/src/tests/testCache.ts +283 -0
  18. package/src/tests/testChildrenControllers.ts +59 -0
  19. package/src/tests/testCookies.ts +41 -0
  20. package/src/tests/testCustom404.ts +35 -0
  21. package/src/tests/testDeepQueryParams.ts +125 -0
  22. package/src/tests/testErrors.ts +233 -0
  23. package/src/tests/testHandlers.ts +94 -0
  24. package/src/tests/testHeaderParams.ts +158 -0
  25. package/src/tests/testHeaders.ts +78 -0
  26. package/src/tests/testInheritanceController.ts +206 -0
  27. package/src/tests/testLocals.ts +53 -0
  28. package/src/tests/testLocation.ts +40 -0
  29. package/src/tests/testMiddlewares.ts +155 -0
  30. package/src/tests/testModule.ts +50 -0
  31. package/src/tests/testMulter.ts +158 -0
  32. package/src/tests/testPathParams.ts +127 -0
  33. package/src/tests/testQueryParams.ts +238 -0
  34. package/src/tests/testRedirect.ts +129 -0
  35. package/src/tests/testResponse.ts +533 -0
  36. package/src/tests/testResponseFilter.ts +106 -0
  37. package/src/tests/testRouting.ts +71 -0
  38. package/src/tests/testScopeRequest.ts +116 -0
  39. package/src/tests/testSession.ts +108 -0
  40. package/src/tests/testStatics.ts +63 -0
  41. package/src/tests/testStream.ts +62 -0
  42. package/src/tests/testView.ts +74 -0
@@ -0,0 +1,345 @@
1
+ import {useDecorators} from "@tsed/core";
2
+ import {Controller, Inject, Injectable} from "@tsed/di";
3
+ import {BadRequest, Forbidden, Unauthorized} from "@tsed/exceptions";
4
+ import {Req, Res} from "@tsed/platform-http";
5
+ import {PlatformTest} from "@tsed/platform-http/testing";
6
+ import {Middleware, UseAuth} from "@tsed/platform-middlewares";
7
+ import {Context} from "@tsed/platform-params";
8
+ import {Get, In, Post, Returns, Security} from "@tsed/schema";
9
+ import SuperTest from "supertest";
10
+ import {afterAll, beforeAll, describe, expect, it} from "vitest";
11
+
12
+ import baseSpec from "../data/swagger.json";
13
+ import {PlatformTestingSdkOpts} from "../interfaces/index.js";
14
+
15
+ @Injectable()
16
+ export class TokenService {
17
+ private _token: string = "EMPTY";
18
+
19
+ token(token?: string) {
20
+ if (token) {
21
+ this._token = token;
22
+ }
23
+
24
+ return this._token;
25
+ }
26
+
27
+ isValid(token: string | undefined) {
28
+ return String(token).match(/token/);
29
+ }
30
+ }
31
+
32
+ @Middleware()
33
+ class OAuthMiddleware {
34
+ @Inject()
35
+ tokenService: TokenService;
36
+
37
+ public use(@Context() ctx: Context) {
38
+ const {endpoint, request} = ctx;
39
+
40
+ const options = endpoint.get(OAuthMiddleware) || {};
41
+
42
+ if (!request.get("authorization")) {
43
+ throw new Unauthorized("Unauthorized");
44
+ }
45
+
46
+ if (!this.tokenService.isValid(request.get("authorization"))) {
47
+ throw new BadRequest("Bad token format");
48
+ }
49
+
50
+ if (options && options.role === "admin" && request.get("authorization") !== "admin_token") {
51
+ throw new Forbidden("Forbidden");
52
+ }
53
+
54
+ ctx.getRequest().user = {
55
+ id: "id",
56
+ name: "name"
57
+ };
58
+ }
59
+ }
60
+
61
+ export function OAuth(options: any = {}): Function {
62
+ return useDecorators(
63
+ UseAuth(OAuthMiddleware, options),
64
+ Security("global_auth", ...(options.scopes || [])),
65
+ In("header").Type(String).Name("Authorization").Required(),
66
+ Returns(401).Description("Unauthorized"),
67
+ Returns(403).Description("Forbidden")
68
+ );
69
+ }
70
+
71
+ @Controller("/auth")
72
+ class TestAuthCtrl {
73
+ @Inject()
74
+ tokenService: TokenService;
75
+
76
+ @Post("/authorize")
77
+ authorize() {
78
+ this.tokenService.token("access_token");
79
+
80
+ return {
81
+ access_token: this.tokenService.token()
82
+ };
83
+ }
84
+
85
+ @Get("/userinfo")
86
+ @OAuth()
87
+ token(@Req("user") user: any) {
88
+ return user;
89
+ }
90
+
91
+ @Get("/admin")
92
+ @OAuth({role: "admin", scopes: ["admin"]})
93
+ admin() {
94
+ return {
95
+ granted: true
96
+ };
97
+ }
98
+
99
+ @Post("/stepUp")
100
+ stepUp() {
101
+ this.tokenService.token("admin_token");
102
+
103
+ return {
104
+ access_token: this.tokenService.token()
105
+ };
106
+ }
107
+ }
108
+
109
+ export function testAuth(options: PlatformTestingSdkOpts) {
110
+ let request: SuperTest.Agent;
111
+
112
+ beforeAll(
113
+ PlatformTest.bootstrap(options.server, {
114
+ ...options,
115
+ mount: {
116
+ "/rest": [TestAuthCtrl]
117
+ },
118
+ swagger: [
119
+ {
120
+ path: "/doc",
121
+ spec: baseSpec as any
122
+ }
123
+ ]
124
+ })
125
+ );
126
+ beforeAll(() => {
127
+ request = SuperTest.agent(PlatformTest.callback());
128
+ });
129
+ afterAll(PlatformTest.reset);
130
+
131
+ describe("Scenario 1: Create token, test token and stepup token", () => {
132
+ it("should create a token, call /userinfo to get userinfo and try admin route", async () => {
133
+ await request.get("/rest/auth/userinfo").expect(401);
134
+ await request
135
+ .get("/rest/auth/userinfo")
136
+ .set({
137
+ Authorization: "wrong"
138
+ })
139
+ .expect(400);
140
+
141
+ const {body} = await request.post("/rest/auth/authorize").expect(200);
142
+
143
+ expect(body.access_token).toEqual("access_token");
144
+
145
+ const {body: userInfo} = await request
146
+ .get("/rest/auth/userinfo")
147
+ .set({
148
+ Authorization: body.access_token
149
+ })
150
+ .expect(200);
151
+
152
+ expect(userInfo).toEqual({
153
+ id: "id",
154
+ name: "name"
155
+ });
156
+
157
+ await request
158
+ .get("/rest/auth/admin")
159
+ .set({
160
+ Authorization: body.access_token
161
+ })
162
+ .expect(403);
163
+
164
+ const {
165
+ body: {access_token}
166
+ } = await request.post("/rest/auth/stepUp").expect(200);
167
+
168
+ expect(access_token).toEqual("admin_token");
169
+
170
+ const {body: result} = await request
171
+ .get("/rest/auth/admin")
172
+ .set({
173
+ Authorization: access_token
174
+ })
175
+ .expect(200);
176
+
177
+ expect(result).toEqual({
178
+ granted: true
179
+ });
180
+ });
181
+ });
182
+
183
+ describe("Scenario 2: GET /swagger.json", () => {
184
+ it("should generate the swagger.spec", async () => {
185
+ const {body: spec} = await request.get("/doc/swagger.json").expect(200);
186
+
187
+ expect(spec).toEqual({
188
+ openapi: "3.0.1",
189
+ info: {
190
+ version: "1.0.0",
191
+ title: "Swagger Title",
192
+ description: "Swagger description",
193
+ termsOfService: "http://swagger.io/terms/",
194
+ contact: {email: "apiteam@swagger.io"},
195
+ license: {name: "Apache 2.0", url: "http://www.apache.org/licenses/LICENSE-2.0.html"}
196
+ },
197
+ paths: {
198
+ "/rest/auth/authorize": {
199
+ post: {
200
+ operationId: "testAuthCtrlAuthorize",
201
+ responses: {"200": {description: "Success"}},
202
+ parameters: [],
203
+ tags: ["TestAuthCtrl"]
204
+ }
205
+ },
206
+ "/rest/auth/userinfo": {
207
+ get: {
208
+ operationId: "testAuthCtrlToken",
209
+ responses: {
210
+ "401": {
211
+ content: {"application/json": {schema: {$ref: "#/components/schemas/Unauthorized"}}},
212
+ description: "Unauthorized"
213
+ },
214
+ "403": {
215
+ content: {"application/json": {schema: {$ref: "#/components/schemas/Forbidden"}}},
216
+ description: "Forbidden"
217
+ }
218
+ },
219
+ security: [{global_auth: []}],
220
+ parameters: [
221
+ {
222
+ name: "Authorization",
223
+ required: true,
224
+ in: "header",
225
+ schema: {type: "string"}
226
+ }
227
+ ],
228
+ tags: ["TestAuthCtrl"]
229
+ }
230
+ },
231
+ "/rest/auth/admin": {
232
+ get: {
233
+ operationId: "testAuthCtrlAdmin",
234
+ responses: {
235
+ "401": {
236
+ content: {"application/json": {schema: {$ref: "#/components/schemas/Unauthorized"}}},
237
+ description: "Unauthorized"
238
+ },
239
+ "403": {
240
+ content: {"application/json": {schema: {$ref: "#/components/schemas/Forbidden"}}},
241
+ description: "Forbidden"
242
+ }
243
+ },
244
+ security: [{global_auth: ["admin"]}],
245
+ parameters: [
246
+ {
247
+ name: "Authorization",
248
+ required: true,
249
+ in: "header",
250
+ schema: {type: "string"}
251
+ }
252
+ ],
253
+ tags: ["TestAuthCtrl"]
254
+ }
255
+ },
256
+ "/rest/auth/stepUp": {
257
+ post: {
258
+ operationId: "testAuthCtrlStepUp",
259
+ responses: {"200": {description: "Success"}},
260
+ parameters: [],
261
+ tags: ["TestAuthCtrl"]
262
+ }
263
+ }
264
+ },
265
+ components: {
266
+ securitySchemes: {
267
+ global_auth: {
268
+ type: "oauth2",
269
+ flows: {
270
+ implicit: {
271
+ authorizationUrl: "http://petstore.swagger.io/oauth/dialog",
272
+ scopes: {admin: "Admin access"}
273
+ }
274
+ }
275
+ }
276
+ },
277
+ schemas: {
278
+ Unauthorized: {
279
+ type: "object",
280
+ properties: {
281
+ name: {
282
+ type: "string",
283
+ description: "The error name",
284
+ minLength: 1,
285
+ example: "UNAUTHORIZED",
286
+ default: "UNAUTHORIZED"
287
+ },
288
+ message: {type: "string", description: "An error message", minLength: 1},
289
+ status: {
290
+ type: "number",
291
+ description: "The status code of the exception",
292
+ example: 401,
293
+ default: 401
294
+ },
295
+ errors: {
296
+ type: "array",
297
+ items: {$ref: "#/components/schemas/GenericError"},
298
+ description: "A list of related errors"
299
+ },
300
+ stack: {type: "string", description: "The stack trace (only in development mode)"}
301
+ },
302
+ required: ["name", "message", "status"]
303
+ },
304
+ GenericError: {
305
+ type: "object",
306
+ properties: {
307
+ name: {type: "string", description: "The error name", minLength: 1},
308
+ message: {type: "string", description: "An error message", minLength: 1}
309
+ },
310
+ additionalProperties: true,
311
+ required: ["name", "message"]
312
+ },
313
+ Forbidden: {
314
+ type: "object",
315
+ properties: {
316
+ name: {
317
+ type: "string",
318
+ description: "The error name",
319
+ minLength: 1,
320
+ example: "FORBIDDEN",
321
+ default: "FORBIDDEN"
322
+ },
323
+ message: {type: "string", description: "An error message", minLength: 1},
324
+ status: {
325
+ type: "number",
326
+ description: "The status code of the exception",
327
+ example: 403,
328
+ default: 403
329
+ },
330
+ errors: {
331
+ type: "array",
332
+ items: {$ref: "#/components/schemas/GenericError"},
333
+ description: "A list of related errors"
334
+ },
335
+ stack: {type: "string", description: "The stack trace (only in development mode)"}
336
+ },
337
+ required: ["name", "message", "status"]
338
+ }
339
+ }
340
+ },
341
+ tags: [{name: "TestAuthCtrl"}]
342
+ });
343
+ });
344
+ });
345
+ }