@creator.co/wapi 1.7.1-alpha3 → 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 (114) 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
  45. package/coverage/clover.xml +0 -1088
  46. package/coverage/coverage/coverage.txt +0 -40
  47. package/coverage/coverage-final.json +0 -37
  48. package/coverage/coverage-summary.json +0 -38
  49. package/coverage/coverage.txt +0 -59
  50. package/coverage/lcov-report/base.css +0 -224
  51. package/coverage/lcov-report/block-navigation.js +0 -87
  52. package/coverage/lcov-report/favicon.png +0 -0
  53. package/coverage/lcov-report/index.html +0 -371
  54. package/coverage/lcov-report/prettify.css +0 -1
  55. package/coverage/lcov-report/prettify.js +0 -2
  56. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  57. package/coverage/lcov-report/sorter.js +0 -196
  58. package/coverage/lcov-report/src/API/Request.ts.html +0 -727
  59. package/coverage/lcov-report/src/API/Response.ts.html +0 -1189
  60. package/coverage/lcov-report/src/API/Utils.ts.html +0 -313
  61. package/coverage/lcov-report/src/API/index.html +0 -131
  62. package/coverage/lcov-report/src/BaseEvent/EventProcessor.ts.html +0 -496
  63. package/coverage/lcov-report/src/BaseEvent/Process.ts.html +0 -346
  64. package/coverage/lcov-report/src/BaseEvent/Transaction.ts.html +0 -1015
  65. package/coverage/lcov-report/src/BaseEvent/index.html +0 -146
  66. package/coverage/lcov-report/src/Cache/Redis.ts.html +0 -367
  67. package/coverage/lcov-report/src/Cache/index.html +0 -116
  68. package/coverage/lcov-report/src/Config/Configuration.ts.html +0 -700
  69. package/coverage/lcov-report/src/Config/EnvironmentVar.ts.html +0 -526
  70. package/coverage/lcov-report/src/Config/index.html +0 -131
  71. package/coverage/lcov-report/src/Crypto/Crypto.ts.html +0 -352
  72. package/coverage/lcov-report/src/Crypto/JWT.ts.html +0 -337
  73. package/coverage/lcov-report/src/Crypto/index.html +0 -131
  74. package/coverage/lcov-report/src/Database/Database.ts.html +0 -151
  75. package/coverage/lcov-report/src/Database/DatabaseManager.ts.html +0 -289
  76. package/coverage/lcov-report/src/Database/DatabaseTransaction.ts.html +0 -595
  77. package/coverage/lcov-report/src/Database/index.html +0 -161
  78. package/coverage/lcov-report/src/Database/index.ts.html +0 -169
  79. package/coverage/lcov-report/src/Database/integrations/knex/KnexDatabase.ts.html +0 -283
  80. package/coverage/lcov-report/src/Database/integrations/knex/KnexTransaction.ts.html +0 -337
  81. package/coverage/lcov-report/src/Database/integrations/knex/index.html +0 -131
  82. package/coverage/lcov-report/src/Database/integrations/kysely/KyselyDatabase.ts.html +0 -376
  83. package/coverage/lcov-report/src/Database/integrations/kysely/KyselyTransaction.ts.html +0 -601
  84. package/coverage/lcov-report/src/Database/integrations/kysely/index.html +0 -131
  85. package/coverage/lcov-report/src/Database/integrations/pgsql/PostgresDatabase.ts.html +0 -250
  86. package/coverage/lcov-report/src/Database/integrations/pgsql/PostgresTransaction.ts.html +0 -346
  87. package/coverage/lcov-report/src/Database/integrations/pgsql/index.html +0 -131
  88. package/coverage/lcov-report/src/Database/types.d.ts.html +0 -232
  89. package/coverage/lcov-report/src/Globals.ts.html +0 -394
  90. package/coverage/lcov-report/src/Logger/Logger.ts.html +0 -1138
  91. package/coverage/lcov-report/src/Logger/index.html +0 -116
  92. package/coverage/lcov-report/src/Mailer/Mailer.ts.html +0 -754
  93. package/coverage/lcov-report/src/Mailer/index.html +0 -116
  94. package/coverage/lcov-report/src/Publisher/Publisher.ts.html +0 -460
  95. package/coverage/lcov-report/src/Publisher/index.html +0 -116
  96. package/coverage/lcov-report/src/Server/RouteResolver.ts.html +0 -442
  97. package/coverage/lcov-report/src/Server/Router.ts.html +0 -616
  98. package/coverage/lcov-report/src/Server/index.html +0 -131
  99. package/coverage/lcov-report/src/Server/lib/ContainerServer.ts.html +0 -280
  100. package/coverage/lcov-report/src/Server/lib/Server.ts.html +0 -403
  101. package/coverage/lcov-report/src/Server/lib/container/GenericHandler.ts.html +0 -331
  102. package/coverage/lcov-report/src/Server/lib/container/GenericHandlerEvent.ts.html +0 -547
  103. package/coverage/lcov-report/src/Server/lib/container/HealthHandler.ts.html +0 -118
  104. package/coverage/lcov-report/src/Server/lib/container/Proxy.ts.html +0 -619
  105. package/coverage/lcov-report/src/Server/lib/container/Utils.ts.html +0 -184
  106. package/coverage/lcov-report/src/Server/lib/container/index.html +0 -176
  107. package/coverage/lcov-report/src/Server/lib/index.html +0 -131
  108. package/coverage/lcov-report/src/Util/AsyncSingleton.ts.html +0 -343
  109. package/coverage/lcov-report/src/Util/Utils.ts.html +0 -313
  110. package/coverage/lcov-report/src/Util/index.html +0 -131
  111. package/coverage/lcov-report/src/Validation/Validator.ts.html +0 -217
  112. package/coverage/lcov-report/src/Validation/index.html +0 -116
  113. package/coverage/lcov-report/src/index.html +0 -116
  114. package/coverage/lcov.info +0 -2326
@@ -0,0 +1,367 @@
1
+ import { jest } from '@jest/globals'
2
+ import { APIGatewayEvent, Context } from 'aws-lambda'
3
+ import { expect as c_expect } from 'chai'
4
+
5
+ import Response from '../../src/API/Response'
6
+ import Transaction from '../../src/BaseEvent/Transaction'
7
+ import Globals from '../../src/Globals'
8
+ import { observableTransaction, defaultHeaders } from '../Test.utils'
9
+
10
+ async function testResponse(r: Response<any>, body: any, optCode?: number, optHeaders?: any) {
11
+ const t = observableTransaction()
12
+ const context = t['context']
13
+ const buildR = await r.build(context, t, false)
14
+ c_expect(buildR).to.be.undefined
15
+ expect(t.responseProxy).toBeCalledTimes(1)
16
+ expect(context.fail).not.toBeCalled()
17
+ expect(context.done).not.toBeCalled()
18
+ expect(context.succeed).toHaveBeenCalledWith({
19
+ statusCode: optCode || 400,
20
+ headers: {
21
+ ...defaultHeaders,
22
+ ...(optHeaders || {}),
23
+ },
24
+ ...(body
25
+ ? {
26
+ body: JSON.stringify({
27
+ ...body,
28
+ transactionID: 'unknown',
29
+ }),
30
+ }
31
+ : {}),
32
+ })
33
+ }
34
+
35
+ describe('Response basics', () => {
36
+ test('Null body', () => {
37
+ const r = new Response<null>(200, null)
38
+ c_expect(r.getCode()).to.be.equals(200)
39
+ c_expect(r.getBody()).to.be.null
40
+ })
41
+
42
+ test('String body', () => {
43
+ const r = new Response<string>(200, 'abc')
44
+ c_expect(r.getCode()).to.be.equals(200)
45
+ c_expect(r.getBody()).to.be.equals('abc')
46
+ })
47
+
48
+ test('Generic body', () => {
49
+ const r = new Response<any>(200, { name: 'abc' })
50
+ r.appendIntoBody('name2', '123')
51
+ c_expect(r.getCode()).to.be.equals(200)
52
+ c_expect(r.getBody().name).to.be.equals('abc')
53
+ c_expect(r.getBody().name2).to.be.equals('123')
54
+ })
55
+
56
+ test('Append/validate header', () => {
57
+ const r = new Response<any>(200, {})
58
+ r.appendHeader('name2', '123')
59
+ c_expect(r['headers']['name2']).to.be.equals('123')
60
+ })
61
+ })
62
+
63
+ describe('Response build', () => {
64
+ test('Succeeds to transaction context', async () => {
65
+ const b = { name: 'abc' }
66
+ const r = new Response<any>(200, b)
67
+ r.appendHeader('abc', '123')
68
+ // do not use default, so we dont use proxy response for once
69
+ const t = new Transaction(
70
+ <APIGatewayEvent>(<unknown>{}),
71
+ <Context>(<unknown>{
72
+ done: jest.fn(),
73
+ fail: jest.fn(),
74
+ succeed: jest.fn(),
75
+ })
76
+ )
77
+ const context = t['context']
78
+ const buildR = await r.build(context, t, false)
79
+ c_expect(buildR).to.be.undefined
80
+ expect(context.fail).not.toBeCalled()
81
+ expect(context.done).not.toBeCalled()
82
+ expect(context.succeed).toHaveBeenCalledWith({
83
+ statusCode: 200,
84
+ headers: {
85
+ ...defaultHeaders,
86
+ abc: '123',
87
+ },
88
+ body: JSON.stringify({
89
+ ...b,
90
+ transactionID: 'unknown',
91
+ }),
92
+ })
93
+ })
94
+
95
+ test('Succeeds with no context call', async () => {
96
+ const b = { name: 'abc' }
97
+ const r = new Response<any>(200, b)
98
+ const t = observableTransaction()
99
+ const context = t['context']
100
+ const buildR = await r.build(context, t, true)
101
+ c_expect(buildR).to.be.undefined
102
+ expect(context.fail).not.toBeCalled()
103
+ expect(context.done).not.toBeCalled()
104
+ expect(context.succeed).not.toBeCalled()
105
+ })
106
+
107
+ test('Succeeds to transaction context as RAW', async () => {
108
+ const b = { name: 'abc' }
109
+ const r = new Response<any>(200, b, {
110
+ rawBody: true,
111
+ })
112
+ const t = observableTransaction()
113
+ const context = t['context']
114
+ const buildR = await r.build(context, t, false)
115
+ c_expect(buildR).to.be.undefined
116
+ expect(context.fail).not.toBeCalled()
117
+ expect(context.done).not.toBeCalled()
118
+ expect(context.succeed).toHaveBeenCalledWith({
119
+ ...b,
120
+ transactionID: 'unknown',
121
+ })
122
+ })
123
+
124
+ test('Succeeds to transaction piping', async () => {
125
+ const b = { name: 'abc' }
126
+ const r = new Response<any>(200, b, {
127
+ shouldStream: true,
128
+ })
129
+ const t = observableTransaction()
130
+ const context = t['context']
131
+ const buildR = await r.build(context, t, false)
132
+ await r.build(context, t, false) //pipe twice, should not affect
133
+ c_expect(buildR).to.be.undefined
134
+ expect(context.fail).not.toBeCalled()
135
+ expect(context.done).not.toBeCalled()
136
+ expect(context.succeed).toHaveBeenCalledTimes(1)
137
+ expect(context.succeed).toHaveBeenCalledWith({
138
+ statusCode: 200,
139
+ headers: {
140
+ ...defaultHeaders,
141
+ },
142
+ body: {
143
+ ...b,
144
+ },
145
+ })
146
+ })
147
+
148
+ test('Failure to transaction context as RAW', async () => {
149
+ const b = { name: 'abc' }
150
+ const r = new Response<any>(400, b, {
151
+ rawBody: true,
152
+ })
153
+ const t = observableTransaction()
154
+ const context = t['context']
155
+ const buildR = await r.build(context, t, false)
156
+ c_expect(buildR).to.be.undefined
157
+ expect(context.done).not.toBeCalled()
158
+ expect(context.succeed).not.toBeCalled()
159
+ expect(context.fail).toHaveBeenCalledTimes(1)
160
+ })
161
+
162
+ test('Failure exception to transaction context as RAW', async () => {
163
+ const b = { name: 'abc' }
164
+ const r = new Response<any>(400, b, {
165
+ rawBody: true,
166
+ throwOnErrors: true,
167
+ })
168
+ const t = observableTransaction()
169
+ const context = t['context']
170
+ let buildR: any = null,
171
+ exception = null
172
+ try {
173
+ buildR = await r.build(context, t, false)
174
+ } catch (e) {
175
+ exception = e
176
+ }
177
+ c_expect(buildR).to.be.null
178
+ c_expect(exception).to.not.be.null
179
+ expect(context.done).not.toBeCalled()
180
+ expect(context.succeed).not.toBeCalled()
181
+ expect(context.fail).not.toBeCalled()
182
+ })
183
+
184
+ test('Failure exception to transaction context as RAW and null body', async () => {
185
+ const b = null
186
+ const r = new Response<any>(400, b, {
187
+ rawBody: true,
188
+ throwOnErrors: true,
189
+ })
190
+ const t = observableTransaction()
191
+ const context = t['context']
192
+ let buildR: any = null,
193
+ exception = null
194
+ try {
195
+ buildR = await r.build(context, t, false)
196
+ } catch (e) {
197
+ exception = e
198
+ }
199
+ c_expect(buildR).to.be.null
200
+ c_expect(exception).to.not.be.null
201
+ expect(context.done).not.toBeCalled()
202
+ expect(context.succeed).not.toBeCalled()
203
+ expect(context.fail).not.toBeCalled()
204
+ })
205
+
206
+ test('Failure exception to transaction context as RAW and custom ero', async () => {
207
+ const b = { message: 'abc', error: 'error 123' }
208
+ const r = new Response<any>(400, b, {
209
+ rawBody: true,
210
+ throwOnErrors: true,
211
+ })
212
+ const t = observableTransaction()
213
+ const context = t['context']
214
+ let buildR: any = null,
215
+ exception = null
216
+ try {
217
+ buildR = await r.build(context, t, false)
218
+ } catch (e) {
219
+ exception = e
220
+ }
221
+ c_expect(buildR).to.be.null
222
+ c_expect(exception).to.not.be.null
223
+ expect(context.done).not.toBeCalled()
224
+ expect(context.succeed).not.toBeCalled()
225
+ expect(context.fail).not.toBeCalled()
226
+ })
227
+ })
228
+
229
+ describe('Response shortcuts', () => {
230
+ test('MissingParamResponse', async () => {
231
+ const pName = 'abc'
232
+ const r = Response.MissingParamResponse(pName)
233
+ await testResponse(r, {
234
+ err: `Invalid request. Path parameter ${pName} is missing.`,
235
+ errCode: Globals.ErrorCode_MissingParam,
236
+ })
237
+ })
238
+
239
+ test('MissingQueryResponse', async () => {
240
+ const pName = 'abc'
241
+ const r = Response.MissingQueryResponse(pName)
242
+ await testResponse(r, {
243
+ err: `Invalid request. Query parameter ${pName} is missing.`,
244
+ errCode: Globals.ErrorCode_MissingParam,
245
+ })
246
+ })
247
+
248
+ test('BadRequestResponse', async () => {
249
+ const message = 'abc'
250
+ const code = 'CODE'
251
+ const optBody = { additional: 123 }
252
+ const r = Response.BadRequestResponse(message, code, optBody)
253
+ await testResponse(r, {
254
+ err: message,
255
+ errCode: code,
256
+ ...optBody,
257
+ })
258
+ })
259
+
260
+ test('BadRequestResponse no opts', async () => {
261
+ const message = 'abc'
262
+ const r = Response.BadRequestResponse(message)
263
+ await testResponse(r, {
264
+ err: message,
265
+ })
266
+ })
267
+
268
+ test('BadRequestResponseWithRollback', async () => {
269
+ const message = 'abc'
270
+ const code = 'CODE'
271
+ const optBody = { additional: 123 }
272
+ const r = Response.BadRequestResponseWithRollback(message, code, optBody)
273
+ await testResponse(r, {
274
+ err: message,
275
+ rollback: true,
276
+ errCode: code,
277
+ ...optBody,
278
+ })
279
+ })
280
+
281
+ test('BadRequestResponseWithRollback no opts', async () => {
282
+ const message = 'abc'
283
+ const r = Response.BadRequestResponseWithRollback(message)
284
+ await testResponse(r, {
285
+ err: message,
286
+ rollback: true,
287
+ })
288
+ })
289
+
290
+ test('UnauthorizedResponse', async () => {
291
+ const message = 'abc'
292
+ const code = 'CODE'
293
+ const r = Response.UnauthorizedResponse(message, code)
294
+ await testResponse(
295
+ r,
296
+ {
297
+ err: message,
298
+ errCode: code,
299
+ },
300
+ 401
301
+ )
302
+ })
303
+
304
+ test('UnauthorizedResponse no code', async () => {
305
+ const message = 'abc'
306
+ const r = Response.UnauthorizedResponse(message)
307
+ await testResponse(r, { err: message }, 401)
308
+ })
309
+
310
+ test('SuccessResponse', async () => {
311
+ const body = { additional: 123 }
312
+ const r = Response.SuccessResponse(body)
313
+ await testResponse(r, body, 200)
314
+ })
315
+
316
+ test('SuccessResponse null body', async () => {
317
+ const r = Response.SuccessResponse(null)
318
+ await testResponse(r, {}, 200)
319
+ })
320
+
321
+ test('SuccessNoContentResponse', async () => {
322
+ const r = Response.SuccessNoContentResponse()
323
+ await testResponse(r, null, 204)
324
+ })
325
+
326
+ test('SimpleResponse', async () => {
327
+ const r = Response.SimpleResponse(null)
328
+ await testResponse(r, null, 200)
329
+ })
330
+
331
+ test('SimpleResponse override statuscode', async () => {
332
+ const r = Response.SimpleResponse(null, 203)
333
+ await testResponse(r, null, 203)
334
+ })
335
+
336
+ test('RedirectResponse', async () => {
337
+ const url = 'https://google.com'
338
+ const r = Response.RedirectResponse(url)
339
+ await testResponse(r, null, 302, { Location: url })
340
+ })
341
+
342
+ test('SuccessStreamResponse', async () => {
343
+ const b = { name: 'abc' }
344
+ const r = Response.SuccessStreamResponse(b, 'test-stream')
345
+ const t = observableTransaction()
346
+ const context = t['context']
347
+ const buildR = await r.build(context, t, false)
348
+ await r.build(context, t, false) //pipe twice, should not affect
349
+ c_expect(buildR).to.be.undefined
350
+ expect(context.fail).not.toBeCalled()
351
+ expect(context.done).not.toBeCalled()
352
+ expect(context.succeed).toHaveBeenCalledTimes(1)
353
+ expect(context.succeed).toHaveBeenCalledWith({
354
+ statusCode: 200,
355
+ headers: {
356
+ ...defaultHeaders,
357
+ 'Content-Type': 'test-stream',
358
+ Connection: 'keep-alive',
359
+ },
360
+ body: {
361
+ ...b,
362
+ },
363
+ })
364
+ })
365
+ })
366
+
367
+ export {}
@@ -0,0 +1,167 @@
1
+ import { expect } from 'chai'
2
+
3
+ import Utils from '../../src/Util/Utils'
4
+
5
+ describe('isHybridlessContainer', () => {
6
+ test('Simple isHybridlessContainer test', () => {
7
+ const v = Utils.isHybridlessContainer()
8
+ expect(v).to.be.a('boolean')
9
+ // this is done, so tests are reliable based on the testing .env
10
+ expect(v).to.be[process.env.HYBRIDLESS_RUNTIME ? 'true' : 'false']
11
+ })
12
+ })
13
+
14
+ describe('isValidString', () => {
15
+ test('Empty string is not valid', () => {
16
+ const v = Utils.isValidString('')
17
+ expect(v).to.be.a('boolean')
18
+ expect(v).to.be.false
19
+ })
20
+
21
+ test('Number is not a valid string', () => {
22
+ // @ts-ignore
23
+ const v = Utils.isValidString(12)
24
+ expect(v).to.be.a('boolean')
25
+ expect(v).to.be.false
26
+ })
27
+
28
+ test('Simple string is valid', () => {
29
+ const v = Utils.isValidString('abc')
30
+ expect(v).to.be.a('boolean')
31
+ expect(v).to.be.true
32
+ })
33
+ })
34
+
35
+ describe('parseIntNullIfNaN', () => {
36
+ test('Null if only chars', () => {
37
+ const v = Utils.parseIntNullIfNaN('abc')
38
+ expect(v).to.be.null
39
+ })
40
+
41
+ test('Null if chars with numbers', () => {
42
+ const v = Utils.parseIntNullIfNaN('abc123')
43
+ expect(v).to.be.null
44
+ })
45
+
46
+ test('Null if null', () => {
47
+ // @ts-ignore
48
+ const v = Utils.parseIntNullIfNaN(null)
49
+ expect(v).to.be.null
50
+ })
51
+
52
+ test('Not null if starts with numbers (js behavior)', () => {
53
+ const v = Utils.parseIntNullIfNaN('123abc')
54
+ expect(v).to.be.a('number')
55
+ expect(v).to.be.equals(123)
56
+ })
57
+
58
+ test('Not null if numbers', () => {
59
+ const v = Utils.parseIntNullIfNaN('123')
60
+ expect(v).to.be.a('number')
61
+ expect(v).to.be.equals(123)
62
+ })
63
+
64
+ test('Not null if number type', () => {
65
+ // @ts-ignore
66
+ const v = Utils.parseIntNullIfNaN(123)
67
+ expect(v).to.be.a('number')
68
+ expect(v).to.be.equals(123)
69
+ })
70
+ })
71
+
72
+ describe('parseObjectNullIfEmpty', () => {
73
+ test('Null if only chars', () => {
74
+ const v = Utils.parseObjectNullIfEmpty('abc')
75
+ expect(v).to.be.null
76
+ })
77
+
78
+ test('Null if chars with numbers', () => {
79
+ const v = Utils.parseObjectNullIfEmpty('abc123')
80
+ expect(v).to.be.null
81
+ })
82
+
83
+ test('Null if null', () => {
84
+ // @ts-ignore
85
+ const v = Utils.parseObjectNullIfEmpty(null)
86
+ expect(v).to.be.null
87
+ })
88
+
89
+ test('Null if malformed object', () => {
90
+ const v = Utils.parseObjectNullIfEmpty('{d: 123}')
91
+ expect(v).to.be.null
92
+ })
93
+
94
+ test('Null if empty object', () => {
95
+ const v = Utils.parseObjectNullIfEmpty('{}')
96
+ expect(v).to.be.null
97
+ })
98
+
99
+ test('Not null if object with a key', () => {
100
+ const v = Utils.parseObjectNullIfEmpty('{"d": 123}')
101
+ expect(v).to.be.a('object')
102
+ expect(v?.['d']).to.be.equals(123)
103
+ })
104
+ })
105
+
106
+ describe('isValidNumber', () => {
107
+ test('Not a valid number if only chars', () => {
108
+ const v = Utils.isValidNumber('abc')
109
+ expect(v).to.be.false
110
+ })
111
+
112
+ test('Not a valid number if only chars and numbers', () => {
113
+ const v = Utils.isValidNumber('abc123')
114
+ expect(v).to.be.false
115
+ })
116
+
117
+ test('Not a valid number if causes a crash on conversion', () => {
118
+ // @ts-ignore
119
+ const v = Utils.isValidNumber({
120
+ toString: () => {
121
+ throw new Error('Evil object')
122
+ },
123
+ })
124
+ expect(v).to.be.false
125
+ })
126
+
127
+ test('Valid number if numbers and chars after', () => {
128
+ const v = Utils.isValidNumber('123abc')
129
+ expect(v).to.be.true
130
+ })
131
+
132
+ test('Valid number if numbers', () => {
133
+ const v = Utils.isValidNumber('123')
134
+ expect(v).to.be.true
135
+ })
136
+ })
137
+
138
+ describe('caseInsensitiveObjectForKey', () => {
139
+ test('Get a key that is lowercase, asking uppercase', () => {
140
+ const v = Utils.caseInsensitiveObjectForKey({ abc: 123 }, 'ABC')
141
+ expect(v).to.be.a('number')
142
+ expect(v).to.be.equals(123)
143
+ })
144
+
145
+ test('Get a key that is uppercase, asking lowercase', () => {
146
+ const v = Utils.caseInsensitiveObjectForKey({ ABC: 123 }, 'abc')
147
+ expect(v).to.be.a('number')
148
+ expect(v).to.be.equals(123)
149
+ })
150
+
151
+ test('Fails gracefully if key is not found', () => {
152
+ const v = Utils.caseInsensitiveObjectForKey({ ABC: 123 }, 'asd')
153
+ expect(v).to.be.null
154
+ })
155
+
156
+ test('Fails gracefully for null object', () => {
157
+ const v = Utils.caseInsensitiveObjectForKey(null, 'abc')
158
+ expect(v).to.be.null
159
+ })
160
+
161
+ test('Fails gracefully for invalid object', () => {
162
+ const v = Utils.caseInsensitiveObjectForKey('', 'abc')
163
+ expect(v).to.be.null
164
+ })
165
+ })
166
+
167
+ export {}