@creator.co/wapi 1.7.1-alpha4 → 1.7.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.
Files changed (44) hide show
  1. package/.eslintignore +3 -0
  2. package/.eslintrc.cjs +60 -0
  3. package/.github/workflows/npmpublish.yml +11 -0
  4. package/.github/workflows/prs.yml +13 -0
  5. package/dist/package-lock.json +2 -2
  6. package/dist/package.json +1 -1
  7. package/jest.config.ts +33 -0
  8. package/jest.smoke.config.ts +35 -0
  9. package/package.json +1 -1
  10. package/tests/API/Request.test.ts +273 -0
  11. package/tests/API/Response.test.ts +367 -0
  12. package/tests/API/Utils.test.ts +167 -0
  13. package/tests/BaseEvent/EventProcessor.test.ts +261 -0
  14. package/tests/BaseEvent/Process.test.ts +49 -0
  15. package/tests/BaseEvent/Transaction.test.ts +408 -0
  16. package/tests/Cache/Redis-client.test.ts +90 -0
  17. package/tests/Cache/Redis-cluster.test.ts +100 -0
  18. package/tests/Config/Config.test.ts +205 -0
  19. package/tests/Config/EnvironmentVar.test.ts +250 -0
  20. package/tests/Crypto/Crypto.test.ts +88 -0
  21. package/tests/Crypto/JWT.test.ts +92 -0
  22. package/tests/Database/DatabaseManager.test.ts +71 -0
  23. package/tests/Database/integrations/knex/KnexDatabase.test.ts +76 -0
  24. package/tests/Database/integrations/knex/KnexTransaction.test.ts +149 -0
  25. package/tests/Database/integrations/kysely/KyselyDatabase.test.ts +113 -0
  26. package/tests/Database/integrations/kysely/KyselyTransaction.test.ts +119 -0
  27. package/tests/Database/integrations/pg/PostgresDatabase.test.ts +76 -0
  28. package/tests/Database/integrations/pg/PostgresTransaction.test.ts +118 -0
  29. package/tests/Logger/Logger.test.ts +219 -0
  30. package/tests/Mailer/Mailer.test.ts +59 -0
  31. package/tests/Publisher/Publisher.test.ts +94 -0
  32. package/tests/Server/RouteResolver.test.ts +102 -0
  33. package/tests/Server/Router.test.ts +39 -0
  34. package/tests/Server/lib/ContainerServer.test.ts +531 -0
  35. package/tests/Server/lib/Server.test.ts +12 -0
  36. package/tests/Server/lib/container/GenericHandler.test.ts +131 -0
  37. package/tests/Server/lib/container/GenericHandlerEvent.test.ts +103 -0
  38. package/tests/Server/lib/container/HealthHandler.test.ts +30 -0
  39. package/tests/Server/lib/container/Proxy.test.ts +268 -0
  40. package/tests/Server/lib/container/Utils.test.ts +47 -0
  41. package/tests/Test.utils.ts +74 -0
  42. package/tests/Validation/Validator.test.ts +76 -0
  43. package/tsconfig.json +26 -0
  44. package/tsconfig.smoke.json +26 -0
@@ -0,0 +1,102 @@
1
+ import { HttpMethod } from '../../src/API/Request'
2
+ import { Route } from '../../src/Server/Router'
3
+ import RouteResolver from '../../src/Server/RouteResolver'
4
+
5
+ const mockRoute = (method: HttpMethod, path: string) =>
6
+ ({
7
+ method: method,
8
+ path: path,
9
+ }) as any as Route
10
+
11
+ describe('RouteResolver', () => {
12
+ test('no routes configured', () => {
13
+ parameterizedTest({}, () => [
14
+ [HttpMethod.GET, '/', undefined],
15
+ [HttpMethod.GET, '', undefined],
16
+ [HttpMethod.GET, 'hjdah', undefined],
17
+ ])
18
+ })
19
+
20
+ test('one route', () => {
21
+ parameterizedTest(
22
+ {
23
+ route: mockRoute(HttpMethod.GET, '/'),
24
+ },
25
+ routes => [
26
+ [HttpMethod.GET, '/', routes.route],
27
+ [HttpMethod.GET, '', routes.route],
28
+ [HttpMethod.GET, 'hjdah', undefined],
29
+ [HttpMethod.POST, '/', undefined],
30
+ [HttpMethod.DELETE, '/', undefined],
31
+ ]
32
+ )
33
+ })
34
+
35
+ test('basic matching', () => {
36
+ parameterizedTest(
37
+ {
38
+ getBase: mockRoute(HttpMethod.GET, '/'),
39
+ getA: mockRoute(HttpMethod.GET, '/a'),
40
+ getB: mockRoute(HttpMethod.GET, '/b'),
41
+ postBase: mockRoute(HttpMethod.POST, '/'),
42
+ postA: mockRoute(HttpMethod.POST, '/a'),
43
+ variable: mockRoute(HttpMethod.GET, '/:a'),
44
+ getAb: mockRoute(HttpMethod.GET, '/a/b'),
45
+ },
46
+ routes => [
47
+ [HttpMethod.GET, '/', routes.getBase],
48
+ [HttpMethod.GET, '/a', routes.getA],
49
+ [HttpMethod.GET, '/b', routes.getB],
50
+ [HttpMethod.POST, '/', routes.postBase],
51
+ [HttpMethod.POST, '/a', routes.postA],
52
+ [HttpMethod.GET, '/c', routes.variable],
53
+ [HttpMethod.GET, '/a/b', routes.getAb],
54
+ ]
55
+ )
56
+ })
57
+
58
+ test('path variables', () => {
59
+ parameterizedTest(
60
+ {
61
+ path_vars: mockRoute(HttpMethod.GET, '/base/:a/:b/:c'),
62
+ abc: mockRoute(HttpMethod.GET, '/base/a/b/c'),
63
+ abcd: mockRoute(HttpMethod.GET, '/base/a/b/c/d'),
64
+ abc_path: mockRoute(HttpMethod.GET, '/base/a/b/c/:d'),
65
+ },
66
+ routes => [
67
+ [HttpMethod.GET, '/base/1/2/3', routes.path_vars],
68
+ [HttpMethod.GET, '/base/a/b/c', routes.abc],
69
+ [HttpMethod.GET, '/base/a/b/c/d', routes.abcd],
70
+ [HttpMethod.GET, '/base/a/b/c/u', routes.abc_path],
71
+ [HttpMethod.GET, '/base/a/b', undefined],
72
+ [HttpMethod.GET, '/base/a/b/c/d/e', undefined],
73
+ [HttpMethod.GET, '/base/a/b/c/d/e/f', undefined],
74
+ ]
75
+ )
76
+ })
77
+
78
+ test('fails to construct with duplicate routes', () => {
79
+ expect(
80
+ () =>
81
+ new RouteResolver({
82
+ routes: [
83
+ mockRoute(HttpMethod.GET, '/a/b/c/:d/:e/b'),
84
+ mockRoute(HttpMethod.GET, '/a/b/c/:jshj/:e/b'),
85
+ ],
86
+ })
87
+ ).toThrowError('Duplicate route: GET: /a/b/c/:jshj/:e/b')
88
+ })
89
+ })
90
+
91
+ const parameterizedTest = <T extends { [k: string]: Route }>(
92
+ routes: T,
93
+ tests: (routes: T) => [HttpMethod, string, Route?][]
94
+ ) => {
95
+ const underTest = new RouteResolver({
96
+ routes: Object.values(routes),
97
+ })
98
+
99
+ tests(routes).forEach(([method, path, expected]) =>
100
+ expect(underTest.resolveRoute(method, path)).toBe(expected)
101
+ )
102
+ }
@@ -0,0 +1,39 @@
1
+ import { jest } from '@jest/globals'
2
+ import { expect } from 'chai'
3
+
4
+ import ContainerServer from '../../src/Server/lib/ContainerServer'
5
+ import Server from '../../src/Server/lib/Server'
6
+ import Router from '../../src/Server/Router'
7
+
8
+ describe('Router basics', () => {
9
+ // @ts-ignore
10
+ let mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {})
11
+ beforeAll(() => {
12
+ // @ts-ignore
13
+ mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {})
14
+ })
15
+ afterAll(() => {
16
+ mockExit.mockRestore()
17
+ })
18
+ beforeEach(() => {
19
+ mockExit.mockReset()
20
+ })
21
+
22
+ test('Serverless server', async () => {
23
+ process.env['HYBRIDLESS_RUNTIME'] = undefined
24
+ const router = new Router({ routes: [] })
25
+ expect(router.getExport()).to.not.be.undefined
26
+ expect(router['server']).to.be.an.instanceof(Server)
27
+ expect(router['server']).to.not.be.an.instanceof(ContainerServer)
28
+ })
29
+ test('Container server', async () => {
30
+ process.env['HYBRIDLESS_RUNTIME'] = 'true'
31
+ const router = new Router({ routes: [] })
32
+ expect(router.getExport()).to.not.be.undefined
33
+ expect(router['server']).to.be.an.instanceof(Server)
34
+ expect(router['server']).to.be.an.instanceof(ContainerServer)
35
+ await router['server']['stop']()
36
+ })
37
+ })
38
+
39
+ export {}
@@ -0,0 +1,531 @@
1
+ import { jest } from '@jest/globals'
2
+ import { expect as c_expect } from 'chai'
3
+ import request from 'supertest'
4
+ import { z } from 'zod'
5
+
6
+ import { HttpMethod } from '../../../src/API/Request'
7
+ import Response from '../../../src/API/Response'
8
+ import Globals from '../../../src/Globals'
9
+ import ContainerServer from '../../../src/Server/lib/ContainerServer'
10
+ import { defaultUrl } from '../../Test.utils'
11
+
12
+ export const ViewSchema = z.object({
13
+ id: z.string(),
14
+ content: z.string(),
15
+ createdAt: z.string(),
16
+ updatedAt: z.string(),
17
+ })
18
+
19
+ export const QuerySchema = z.object({
20
+ id: z.string(),
21
+ order: z.string().refine(
22
+ v => {
23
+ const n = Number(v)
24
+ return !isNaN(n) && v?.length > 0
25
+ },
26
+ { message: 'Invalid number' }
27
+ ),
28
+ })
29
+
30
+ describe('Container server routing', () => {
31
+ // @ts-ignore
32
+ let mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {})
33
+ beforeAll(() => {
34
+ // @ts-ignore
35
+ mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {})
36
+ })
37
+ afterAll(() => {
38
+ mockExit.mockRestore()
39
+ })
40
+ beforeEach(() => {
41
+ mockExit.mockReset()
42
+ })
43
+
44
+ test('Health & 404 handler', async () => {
45
+ const server = new ContainerServer({ routes: [] })
46
+ await server.start()
47
+ // Health check
48
+ const res = await request(defaultUrl)
49
+ .get(Globals.Listener_HTTP_DefaultHealthCheckRoute)
50
+ .expect('Content-Type', 'text/html; charset=utf-8')
51
+ .expect(200)
52
+ c_expect(res.text).to.be.equals('Healthy!')
53
+ // Not handled
54
+ await request(defaultUrl)
55
+ .get(`/abc`)
56
+ .expect('Content-Type', 'application/json; charset=utf-8')
57
+ .expect(404)
58
+
59
+ // Unload
60
+ await server.stop('Error')
61
+ expect(mockExit).toHaveBeenCalledTimes(1)
62
+ expect(mockExit).toBeCalledWith(1)
63
+ })
64
+
65
+ test('Simple route', async () => {
66
+ const server = new ContainerServer({
67
+ routes: [
68
+ {
69
+ path: '/abc',
70
+ method: HttpMethod.GET,
71
+ handler: async () => {
72
+ return Response.SimpleResponse({ name: 'abc' })
73
+ },
74
+ } as any,
75
+ ],
76
+ })
77
+ await server.start()
78
+ // Health check
79
+ const res = await request(defaultUrl)
80
+ .get(Globals.Listener_HTTP_DefaultHealthCheckRoute)
81
+ .expect('Content-Type', 'text/html; charset=utf-8')
82
+ .expect(200)
83
+ c_expect(res.text).to.be.equals('Healthy!')
84
+ // Found route
85
+ const resG = await request(defaultUrl)
86
+ .get(`/abc`)
87
+ .expect('Content-Type', 'application/json; charset=utf-8')
88
+ .expect(200)
89
+ c_expect(resG.body['name']).to.be.deep.equals('abc')
90
+ c_expect(resG.body['transactionID']).to.not.be.null
91
+ // Found route, but not method
92
+ await request(defaultUrl)
93
+ .post(`/abc`)
94
+ .expect('Content-Type', 'application/json; charset=utf-8')
95
+ .expect(404)
96
+ // Not found route
97
+ await request(defaultUrl)
98
+ .get(`/abc/123`)
99
+ .expect('Content-Type', 'application/json; charset=utf-8')
100
+ .expect(404)
101
+ // Unload
102
+ await server.stop('Error')
103
+ expect(mockExit).toHaveBeenCalledTimes(1)
104
+ expect(mockExit).toBeCalledWith(1)
105
+ })
106
+ })
107
+
108
+ describe('Container server basics', () => {
109
+ // @ts-ignore
110
+ let mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {})
111
+ beforeAll(() => {
112
+ // @ts-ignore
113
+ mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {})
114
+ })
115
+ afterAll(() => {
116
+ mockExit.mockRestore()
117
+ })
118
+ beforeEach(() => {
119
+ mockExit.mockReset()
120
+ })
121
+
122
+ test('Starts with exports', async () => {
123
+ const server = new ContainerServer({ routes: [] })
124
+ server.getExport()
125
+ return new Promise(resolve => {
126
+ setTimeout(async () => {
127
+ // Health check
128
+ const res = await request(defaultUrl)
129
+ .get(Globals.Listener_HTTP_DefaultHealthCheckRoute)
130
+ .expect('Content-Type', 'text/html; charset=utf-8')
131
+ .expect(200)
132
+ c_expect(res.text).to.be.equals('Healthy!')
133
+ // Unload
134
+ await server.stop()
135
+ expect(mockExit).toHaveBeenCalledTimes(1)
136
+ expect(mockExit).toBeCalledWith(0)
137
+ resolve(null)
138
+ }, 2000)
139
+ })
140
+ })
141
+
142
+ test('Stops if process sends message SIGINT', async () => {
143
+ const server = new ContainerServer({ routes: [] })
144
+ await server.start()
145
+ process.emit('SIGINT')
146
+ return new Promise(resolve => {
147
+ setTimeout(async () => {
148
+ expect(mockExit).toHaveBeenCalledTimes(1)
149
+ expect(mockExit).toBeCalledWith(0)
150
+ resolve(null)
151
+ }, 2000)
152
+ })
153
+ }, 10000)
154
+
155
+ test('Stops if process sends message unhandledRejection', async () => {
156
+ const server = new ContainerServer({ routes: [] })
157
+ await server.start()
158
+ // @ts-ignore
159
+ process.emit('unhandledRejection')
160
+ return new Promise(resolve => {
161
+ setTimeout(async () => {
162
+ expect(mockExit).toHaveBeenCalledTimes(1)
163
+ expect(mockExit).toBeCalledWith(0)
164
+ resolve(null)
165
+ }, 2000)
166
+ })
167
+ }, 10000)
168
+ })
169
+
170
+ describe('Container server validation (body)', () => {
171
+ // @ts-ignore
172
+ let mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {})
173
+ beforeAll(() => {
174
+ // @ts-ignore
175
+ mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {})
176
+ })
177
+ afterAll(() => {
178
+ mockExit.mockRestore()
179
+ })
180
+ beforeEach(() => {
181
+ mockExit.mockReset()
182
+ })
183
+
184
+ function validateValidationFailure(res: any, failureCount?: number) {
185
+ c_expect(res.body['err']).to.be.equals(Globals.ErrorResponseValidationFail)
186
+ c_expect(res.body['errCode']).to.be.equals(Globals.ErrorCode_InvalidInput)
187
+ c_expect(res.body['transactionID']).to.not.be.null
188
+ c_expect(res.body['transactionID']).to.be.an('string')
189
+ c_expect(res.body['validationFailure']?.length).to.be.equals(failureCount || 4)
190
+ }
191
+
192
+ test('Validates empty body', async () => {
193
+ const server = new ContainerServer({
194
+ routes: [
195
+ {
196
+ path: '/abc',
197
+ method: HttpMethod.POST,
198
+ inputSchema: ViewSchema,
199
+ handler: async () => {
200
+ return Response.SimpleResponse({ name: 'abc' })
201
+ },
202
+ } as any,
203
+ ],
204
+ })
205
+ await server.start()
206
+ // Validation fails, empty body
207
+ const resG = await request(defaultUrl)
208
+ .post(`/abc`)
209
+ .expect('Content-Type', 'application/json; charset=utf-8')
210
+ .expect(400)
211
+ validateValidationFailure(resG)
212
+ await server.stop()
213
+ })
214
+
215
+ test('Validates empty string body', async () => {
216
+ const server = new ContainerServer({
217
+ routes: [
218
+ {
219
+ path: '/abc',
220
+ method: HttpMethod.POST,
221
+ inputSchema: ViewSchema,
222
+ handler: async () => {
223
+ return Response.SimpleResponse({ name: 'abc' })
224
+ },
225
+ } as any,
226
+ ],
227
+ })
228
+ await server.start()
229
+ // Validation fails, empty body
230
+ const resG = await request(defaultUrl)
231
+ .post(`/abc`)
232
+ .send('')
233
+ .expect('Content-Type', 'application/json; charset=utf-8')
234
+ .expect(400)
235
+ validateValidationFailure(resG)
236
+ await server.stop()
237
+ })
238
+
239
+ test('Validates empty object body', async () => {
240
+ const server = new ContainerServer({
241
+ routes: [
242
+ {
243
+ path: '/abc',
244
+ method: HttpMethod.POST,
245
+ inputSchema: ViewSchema,
246
+ handler: async () => {
247
+ return Response.SimpleResponse({ name: 'abc' })
248
+ },
249
+ } as any,
250
+ ],
251
+ })
252
+ await server.start()
253
+ // Validation fails, empty body
254
+ const resG = await request(defaultUrl)
255
+ .post(`/abc`)
256
+ .send({})
257
+ .expect('Content-Type', 'application/json; charset=utf-8')
258
+ .expect(400)
259
+ validateValidationFailure(resG)
260
+ await server.stop()
261
+ })
262
+
263
+ test('Validates missing props body', async () => {
264
+ const server = new ContainerServer({
265
+ routes: [
266
+ {
267
+ path: '/abc',
268
+ method: HttpMethod.POST,
269
+ inputSchema: ViewSchema,
270
+ handler: async () => {
271
+ return Response.SimpleResponse({ name: 'abc' })
272
+ },
273
+ } as any,
274
+ ],
275
+ })
276
+ await server.start()
277
+ // Validation fails, empty body
278
+ const resG = await request(defaultUrl)
279
+ .post(`/abc`)
280
+ .send({ id: '123' })
281
+ .expect('Content-Type', 'application/json; charset=utf-8')
282
+ .expect(400)
283
+ validateValidationFailure(resG, 3)
284
+ await server.stop()
285
+ })
286
+
287
+ test('Validates wrong type props body', async () => {
288
+ const server = new ContainerServer({
289
+ routes: [
290
+ {
291
+ path: '/abc',
292
+ method: HttpMethod.POST,
293
+ inputSchema: ViewSchema,
294
+ handler: async () => {
295
+ return Response.SimpleResponse({ name: 'abc' })
296
+ },
297
+ } as any,
298
+ ],
299
+ })
300
+ await server.start()
301
+ // Validation fails, empty body
302
+ const resG = await request(defaultUrl)
303
+ .post(`/abc`)
304
+ .send({ id: 123 })
305
+ .expect('Content-Type', 'application/json; charset=utf-8')
306
+ .expect(400)
307
+ validateValidationFailure(resG)
308
+ await server.stop()
309
+ })
310
+
311
+ test('Validates successfully', async () => {
312
+ const server = new ContainerServer({
313
+ routes: [
314
+ {
315
+ path: '/abc',
316
+ method: HttpMethod.POST,
317
+ inputSchema: ViewSchema,
318
+ handler: async () => {
319
+ return Response.SimpleResponse({ name: 'abc' })
320
+ },
321
+ } as any,
322
+ ],
323
+ })
324
+ await server.start()
325
+ // Validation fails, empty body
326
+ await request(defaultUrl)
327
+ .post(`/abc`)
328
+ .send({
329
+ id: '123',
330
+ content: '123',
331
+ createdAt: new Date(),
332
+ updatedAt: new Date(),
333
+ })
334
+ .expect('Content-Type', 'application/json; charset=utf-8')
335
+ .expect(200)
336
+ await server.stop()
337
+ })
338
+ })
339
+
340
+ describe('Container server validation (query)', () => {
341
+ let server: ContainerServer
342
+ // @ts-ignore
343
+ let mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {})
344
+ beforeAll(() => {
345
+ // @ts-ignore
346
+ mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {})
347
+ })
348
+ afterAll(() => {
349
+ mockExit.mockRestore()
350
+ })
351
+ beforeEach(async () => {
352
+ mockExit.mockReset()
353
+ server = new ContainerServer({
354
+ routes: [
355
+ {
356
+ path: '/abc',
357
+ method: HttpMethod.POST,
358
+ querySchema: QuerySchema,
359
+ handler: async () => {
360
+ return Response.SimpleResponse({ name: 'abc' })
361
+ },
362
+ } as any,
363
+ ],
364
+ })
365
+ await server.start()
366
+ })
367
+
368
+ afterEach(async () => {
369
+ await server.stop()
370
+ })
371
+
372
+ function validateValidationFailure(res: any, failureCount?: number) {
373
+ c_expect(res.body['err']).to.be.equals(Globals.ErrorResponseValidationFail)
374
+ c_expect(res.body['errCode']).to.be.equals(Globals.ErrorCode_InvalidInput)
375
+ c_expect(res.body['transactionID']).to.not.be.null
376
+ c_expect(res.body['transactionID']).to.be.an('string')
377
+ c_expect(res.body['validationFailure']?.length).to.be.equals(failureCount || 2)
378
+ }
379
+
380
+ test('Validates empty query', async () => {
381
+ // Validation fails, empty body
382
+ const resG = await request(defaultUrl)
383
+ .post(`/abc`)
384
+ .expect('Content-Type', 'application/json; charset=utf-8')
385
+ .expect(400)
386
+ validateValidationFailure(resG, 2)
387
+ })
388
+
389
+ test('Validates empty query differently', async () => {
390
+ // Validation fails, empty body
391
+ const resG = await request(defaultUrl)
392
+ .post(`/abc?`)
393
+ .expect('Content-Type', 'application/json; charset=utf-8')
394
+ .expect(400)
395
+ validateValidationFailure(resG, 2)
396
+ })
397
+
398
+ test('Validates missing props body', async () => {
399
+ // Validation fails, empty body
400
+ const resG = await request(defaultUrl)
401
+ .post(`/abc?id=myname`)
402
+ .expect('Content-Type', 'application/json; charset=utf-8')
403
+ .expect(400)
404
+ validateValidationFailure(resG, 1)
405
+ })
406
+
407
+ test('Validates wrong type props body', async () => {
408
+ // Validation fails, empty body
409
+ const resG = await request(defaultUrl)
410
+ .post(`/abc?id=name&order=myname`)
411
+ .expect('Content-Type', 'application/json; charset=utf-8')
412
+ .expect(400)
413
+ validateValidationFailure(resG, 1)
414
+ })
415
+
416
+ test('Validates successfully2', async () => {
417
+ // Validation fails, empty body
418
+ await request(defaultUrl)
419
+ .post(`/abc`)
420
+ .query({ id: 'name', order: 123 })
421
+ .expect('Content-Type', 'application/json; charset=utf-8')
422
+ .expect(200)
423
+ })
424
+ })
425
+
426
+ describe('Container server validation (path)', () => {
427
+ let server: ContainerServer
428
+ // @ts-ignore
429
+ let mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {})
430
+ beforeAll(() => {
431
+ // @ts-ignore
432
+ mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {})
433
+ })
434
+ afterAll(() => {
435
+ mockExit.mockRestore()
436
+ })
437
+ beforeEach(async () => {
438
+ mockExit.mockReset()
439
+ server = new ContainerServer({
440
+ routes: [
441
+ {
442
+ path: '/abc/:id/:order',
443
+ method: HttpMethod.POST,
444
+ pathSchema: QuerySchema,
445
+ handler: async () => {
446
+ return Response.SimpleResponse({ name: 'abc' })
447
+ },
448
+ } as any,
449
+ ],
450
+ })
451
+ await server.start()
452
+ })
453
+
454
+ afterEach(async () => {
455
+ await server.stop()
456
+ })
457
+
458
+ function validateValidationFailure(res: any, failureCount?: number) {
459
+ c_expect(res.body['err']).to.be.equals(Globals.ErrorResponseValidationFail)
460
+ c_expect(res.body['errCode']).to.be.equals(Globals.ErrorCode_InvalidInput)
461
+ c_expect(res.body['transactionID']).to.not.be.null
462
+ c_expect(res.body['transactionID']).to.be.an('string')
463
+ c_expect(res.body['validationFailure']?.length).to.be.equals(failureCount || 2)
464
+ }
465
+
466
+ test('Validates wrong type props body', async () => {
467
+ // Validation fails, empty body
468
+ const resG = await request(defaultUrl)
469
+ .post(`/abc/name/myname`)
470
+ .expect('Content-Type', 'application/json; charset=utf-8')
471
+ .expect(400)
472
+ validateValidationFailure(resG, 1)
473
+ })
474
+
475
+ test('Validates successfully4', async () => {
476
+ // Validation fails, empty body
477
+ await request(defaultUrl)
478
+ .post(`/abc/name/123`)
479
+ .expect('Content-Type', 'application/json; charset=utf-8')
480
+ .expect(200)
481
+ })
482
+ })
483
+
484
+ describe('Container server raw body', () => {
485
+ // @ts-ignore
486
+ let mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {})
487
+ beforeAll(() => {
488
+ // @ts-ignore
489
+ mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {})
490
+ process.env['HYBRIDLESS_RUNTIME'] = 'true'
491
+ })
492
+ afterAll(() => {
493
+ mockExit.mockRestore()
494
+ process.env['HYBRIDLESS_RUNTIME'] = undefined
495
+ })
496
+ beforeEach(() => {
497
+ mockExit.mockReset()
498
+ })
499
+
500
+ test('Raw body is available', async () => {
501
+ let raw = null
502
+ const server = new ContainerServer({
503
+ routes: [
504
+ {
505
+ path: '/abc',
506
+ method: HttpMethod.POST,
507
+ handler: async t => {
508
+ raw = t.request.getBody(true)
509
+ return Response.SimpleResponse(null)
510
+ },
511
+ } as any,
512
+ ],
513
+ })
514
+ await server.start()
515
+
516
+ // it's formatted funky, because we're testing for exact match
517
+ const data = ' { "name" : "abc" }'
518
+ await request(defaultUrl)
519
+ .post(`/abc`)
520
+ .send(data)
521
+ .set('Content-Type', 'application/json')
522
+ .expect(200)
523
+
524
+ const s = new TextDecoder('utf-8').decode(raw!)
525
+ c_expect(s).to.be.equals(data)
526
+
527
+ await server.stop()
528
+ })
529
+ })
530
+
531
+ export {}
@@ -0,0 +1,12 @@
1
+ import { expect } from 'chai'
2
+
3
+ import Server from '../../../src/Server/lib/Server'
4
+
5
+ describe('Server basics', () => {
6
+ test('Works', async () => {
7
+ const server = new Server({ routes: [] })
8
+ expect(server.getExport()).to.not.be.undefined
9
+ })
10
+ })
11
+
12
+ export {}