@creator.co/wapi 1.2.1-beta6 → 1.2.3

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 (129) hide show
  1. package/.eslintrc.cjs +29 -22
  2. package/.github/workflows/npmpublish.yml +11 -19
  3. package/.github/workflows/prs.yml +13 -0
  4. package/index.ts +12 -10
  5. package/jest.config.ts +39 -0
  6. package/package.json +15 -4
  7. package/src/API/Request.ts +136 -44
  8. package/src/API/Response.ts +256 -46
  9. package/src/API/Utils.ts +60 -7
  10. package/src/BaseEvent/EventProcessor.ts +93 -28
  11. package/src/BaseEvent/Process.ts +69 -13
  12. package/src/BaseEvent/Transaction.ts +29 -50
  13. package/src/Config/Configuration.ts +119 -19
  14. package/src/Config/EnvironmentVar.ts +100 -21
  15. package/src/Crypto/Crypto.ts +78 -19
  16. package/src/Crypto/JWT.ts +53 -13
  17. package/src/Globals.ts +159 -27
  18. package/src/Logger/Logger.ts +204 -65
  19. package/src/Mailer/Mailer.ts +114 -31
  20. package/src/Publisher/Publisher.ts +57 -16
  21. package/src/Server/RouteResolver.ts +141 -0
  22. package/src/Server/Router.ts +84 -12
  23. package/src/Server/lib/ContainerServer.ts +53 -6
  24. package/src/Server/lib/Server.ts +82 -54
  25. package/src/Server/lib/container/GenericHandler.ts +15 -18
  26. package/src/Server/lib/container/GenericHandlerEvent.ts +78 -50
  27. package/src/Server/lib/container/HealthHandler.ts +2 -2
  28. package/src/Server/lib/container/Proxy.ts +114 -45
  29. package/src/Server/lib/container/Utils.ts +18 -27
  30. package/src/Validation/Validator.ts +23 -7
  31. package/tests/API/Request.test.ts +259 -0
  32. package/tests/API/Response.test.ts +367 -0
  33. package/tests/API/Utils.test.ts +157 -0
  34. package/tests/BaseEvent/EventProcessor.test.ts +262 -0
  35. package/tests/BaseEvent/Process.test.ts +49 -0
  36. package/tests/BaseEvent/Transaction.test.ts +222 -0
  37. package/tests/Config/Config.test.ts +193 -0
  38. package/tests/Config/EnvironmentVar.test.ts +214 -0
  39. package/tests/Crypto/Crypto.test.ts +88 -0
  40. package/tests/Crypto/JWT.test.ts +92 -0
  41. package/tests/Logger/Logger.test.ts +96 -0
  42. package/tests/Mailer/Mailer.test.ts +59 -0
  43. package/tests/Publisher/Publisher.test.ts +60 -0
  44. package/tests/Server/RouteResolver.test.ts +103 -0
  45. package/tests/Server/Router.test.ts +38 -0
  46. package/tests/Server/lib/ContainerServer.test.ts +327 -0
  47. package/tests/Server/lib/Server.test.ts +12 -0
  48. package/tests/Server/lib/container/GenericHandler.test.ts +131 -0
  49. package/tests/Server/lib/container/GenericHandlerEvent.test.ts +102 -0
  50. package/tests/Server/lib/container/HealthHandler.test.ts +30 -0
  51. package/tests/Server/lib/container/Proxy.test.ts +265 -0
  52. package/tests/Server/lib/container/Utils.test.ts +47 -0
  53. package/tests/Test.utils.ts +95 -0
  54. package/tests/Validation/Validator.test.ts +76 -0
  55. package/tests/main.test.ts +15 -0
  56. package/tsconfig.json +1 -0
  57. package/dist/index.d.ts +0 -11
  58. package/dist/index.js +0 -24
  59. package/dist/index.js.map +0 -1
  60. package/dist/package.json +0 -53
  61. package/dist/src/API/Request.d.ts +0 -21
  62. package/dist/src/API/Request.js +0 -86
  63. package/dist/src/API/Request.js.map +0 -1
  64. package/dist/src/API/Response.d.ts +0 -39
  65. package/dist/src/API/Response.js +0 -232
  66. package/dist/src/API/Response.js.map +0 -1
  67. package/dist/src/API/Utils.d.ts +0 -8
  68. package/dist/src/API/Utils.js +0 -49
  69. package/dist/src/API/Utils.js.map +0 -1
  70. package/dist/src/BaseEvent/EventProcessor.d.ts +0 -13
  71. package/dist/src/BaseEvent/EventProcessor.js +0 -151
  72. package/dist/src/BaseEvent/EventProcessor.js.map +0 -1
  73. package/dist/src/BaseEvent/Process.d.ts +0 -12
  74. package/dist/src/BaseEvent/Process.js +0 -114
  75. package/dist/src/BaseEvent/Process.js.map +0 -1
  76. package/dist/src/BaseEvent/Transaction.d.ts +0 -29
  77. package/dist/src/BaseEvent/Transaction.js +0 -248
  78. package/dist/src/BaseEvent/Transaction.js.map +0 -1
  79. package/dist/src/Config/Configuration.d.ts +0 -34
  80. package/dist/src/Config/Configuration.js +0 -93
  81. package/dist/src/Config/Configuration.js.map +0 -1
  82. package/dist/src/Config/EnvironmentVar.d.ts +0 -17
  83. package/dist/src/Config/EnvironmentVar.js +0 -152
  84. package/dist/src/Config/EnvironmentVar.js.map +0 -1
  85. package/dist/src/Crypto/Crypto.d.ts +0 -8
  86. package/dist/src/Crypto/Crypto.js +0 -84
  87. package/dist/src/Crypto/Crypto.js.map +0 -1
  88. package/dist/src/Crypto/JWT.d.ts +0 -16
  89. package/dist/src/Crypto/JWT.js +0 -49
  90. package/dist/src/Crypto/JWT.js.map +0 -1
  91. package/dist/src/Globals.d.ts +0 -21
  92. package/dist/src/Globals.js +0 -35
  93. package/dist/src/Globals.js.map +0 -1
  94. package/dist/src/Logger/Logger.d.ts +0 -34
  95. package/dist/src/Logger/Logger.js +0 -345
  96. package/dist/src/Logger/Logger.js.map +0 -1
  97. package/dist/src/Mailer/Mailer.d.ts +0 -12
  98. package/dist/src/Mailer/Mailer.js +0 -234
  99. package/dist/src/Mailer/Mailer.js.map +0 -1
  100. package/dist/src/Publisher/Publisher.d.ts +0 -10
  101. package/dist/src/Publisher/Publisher.js +0 -109
  102. package/dist/src/Publisher/Publisher.js.map +0 -1
  103. package/dist/src/Server/Router.d.ts +0 -27
  104. package/dist/src/Server/Router.js +0 -22
  105. package/dist/src/Server/Router.js.map +0 -1
  106. package/dist/src/Server/lib/ContainerServer.d.ts +0 -11
  107. package/dist/src/Server/lib/ContainerServer.js +0 -103
  108. package/dist/src/Server/lib/ContainerServer.js.map +0 -1
  109. package/dist/src/Server/lib/Server.d.ts +0 -9
  110. package/dist/src/Server/lib/Server.js +0 -141
  111. package/dist/src/Server/lib/Server.js.map +0 -1
  112. package/dist/src/Server/lib/container/GenericHandler.d.ts +0 -4
  113. package/dist/src/Server/lib/container/GenericHandler.js +0 -136
  114. package/dist/src/Server/lib/container/GenericHandler.js.map +0 -1
  115. package/dist/src/Server/lib/container/GenericHandlerEvent.d.ts +0 -14
  116. package/dist/src/Server/lib/container/GenericHandlerEvent.js +0 -164
  117. package/dist/src/Server/lib/container/GenericHandlerEvent.js.map +0 -1
  118. package/dist/src/Server/lib/container/HealthHandler.d.ts +0 -3
  119. package/dist/src/Server/lib/container/HealthHandler.js +0 -44
  120. package/dist/src/Server/lib/container/HealthHandler.js.map +0 -1
  121. package/dist/src/Server/lib/container/Proxy.d.ts +0 -15
  122. package/dist/src/Server/lib/container/Proxy.js +0 -157
  123. package/dist/src/Server/lib/container/Proxy.js.map +0 -1
  124. package/dist/src/Server/lib/container/Utils.d.ts +0 -6
  125. package/dist/src/Server/lib/container/Utils.js +0 -109
  126. package/dist/src/Server/lib/container/Utils.js.map +0 -1
  127. package/dist/src/Validation/Validator.d.ts +0 -5
  128. package/dist/src/Validation/Validator.js +0 -31
  129. package/dist/src/Validation/Validator.js.map +0 -1
@@ -0,0 +1,157 @@
1
+ import { expect } from 'chai'
2
+
3
+ import Utils from '../../src/API/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('Valid number if numbers and chars after', () => {
118
+ const v = Utils.isValidNumber('123abc')
119
+ expect(v).to.be.true
120
+ })
121
+
122
+ test('Valid number if numbers', () => {
123
+ const v = Utils.isValidNumber('123')
124
+ expect(v).to.be.true
125
+ })
126
+ })
127
+
128
+ describe('caseInsensitiveObjectForKey', () => {
129
+ test('Get a key that is lowercase, asking uppercase', () => {
130
+ const v = Utils.caseInsensitiveObjectForKey({ abc: 123 }, 'ABC')
131
+ expect(v).to.be.a('number')
132
+ expect(v).to.be.equals(123)
133
+ })
134
+
135
+ test('Get a key that is uppercase, asking lowercase', () => {
136
+ const v = Utils.caseInsensitiveObjectForKey({ ABC: 123 }, 'abc')
137
+ expect(v).to.be.a('number')
138
+ expect(v).to.be.equals(123)
139
+ })
140
+
141
+ test('Fails gracefully if key is not found', () => {
142
+ const v = Utils.caseInsensitiveObjectForKey({ ABC: 123 }, 'asd')
143
+ expect(v).to.be.null
144
+ })
145
+
146
+ test('Fails gracefully for null object', () => {
147
+ const v = Utils.caseInsensitiveObjectForKey(null, 'abc')
148
+ expect(v).to.be.null
149
+ })
150
+
151
+ test('Fails gracefully for invalid object', () => {
152
+ const v = Utils.caseInsensitiveObjectForKey('', 'abc')
153
+ expect(v).to.be.null
154
+ })
155
+ })
156
+
157
+ export {}
@@ -0,0 +1,262 @@
1
+ import { expect as j_expect } from '@jest/globals'
2
+ import { expect } from 'chai'
3
+
4
+ import Response from '../../src/API/Response'
5
+ import EventProcessor from '../../src/BaseEvent/EventProcessor'
6
+ import Globals from '../../src/Globals'
7
+ import { emptyQueueEvent, observableContext } from '../Test.utils'
8
+
9
+ describe('EventProcessor success invocation path', () => {
10
+ test('Simple success', async () => {
11
+ const b = { name: '123' }
12
+ const context = observableContext()
13
+ const transaction = new EventProcessor(
14
+ emptyQueueEvent({
15
+ Records: [{ body: JSON.stringify(b) }, { body: JSON.stringify(b) }],
16
+ }),
17
+ context,
18
+ {}
19
+ )
20
+ let count = 0
21
+ const handlerResp = await transaction.processEvent(async (transaction, eventRecord) => {
22
+ expect(eventRecord).to.be.deep.equal(b)
23
+ count++
24
+ return Response.SuccessResponse(null)
25
+ })
26
+ // check resp
27
+ expect(count).to.be.equals(2)
28
+ expect(handlerResp).to.be.an.instanceof(Response)
29
+ if (handlerResp instanceof Response) {
30
+ expect(handlerResp?.getBody()).to.be.deep.equal({
31
+ transactionID: 'unknown',
32
+ })
33
+ expect(handlerResp.getCode()).to.be.equal(200)
34
+ }
35
+ // ctx
36
+ j_expect(context.fail).not.toBeCalled()
37
+ j_expect(context.done).not.toBeCalled()
38
+ j_expect(context.succeed).not.toBeCalled()
39
+ })
40
+
41
+ test('Simple success - do not decode', async () => {
42
+ const b = { name: '123' }
43
+ const context = observableContext()
44
+ const transaction = new EventProcessor(
45
+ emptyQueueEvent({
46
+ Records: [{ body: JSON.stringify(b) }, { body: JSON.stringify(b) }],
47
+ }),
48
+ context,
49
+ {}
50
+ )
51
+ let count = 0
52
+ const handlerResp = await transaction.processEvent(async (transaction, eventRecord) => {
53
+ expect(eventRecord).to.be.deep.equal(JSON.stringify(b))
54
+ count++
55
+ return Response.SuccessResponse(null)
56
+ }, true)
57
+ // check resp
58
+ expect(count).to.be.equals(2)
59
+ expect(handlerResp).to.be.an.instanceof(Response)
60
+ if (handlerResp instanceof Response) {
61
+ expect(handlerResp?.getBody()).to.be.deep.equal({
62
+ transactionID: 'unknown',
63
+ })
64
+ expect(handlerResp.getCode()).to.be.equal(200)
65
+ }
66
+ // ctx
67
+ j_expect(context.fail).not.toBeCalled()
68
+ j_expect(context.done).not.toBeCalled()
69
+ j_expect(context.succeed).not.toBeCalled()
70
+ })
71
+ })
72
+
73
+ describe('EventProcessor failure invocation path', () => {
74
+ test('Simple failure', async () => {
75
+ const b = { name: '123' }
76
+ const context = observableContext()
77
+ const transaction = new EventProcessor(
78
+ emptyQueueEvent({
79
+ Records: [
80
+ { body: JSON.stringify(b) },
81
+ { messageId: '123', body: JSON.stringify(b) },
82
+ { body: JSON.stringify(b) },
83
+ ],
84
+ }),
85
+ context,
86
+ {}
87
+ )
88
+ let count = 0
89
+ let handlerResp: any = null,
90
+ err: any = null
91
+ try {
92
+ handlerResp = await transaction.processEvent(async (transaction, eventRecord) => {
93
+ expect(eventRecord).to.be.deep.equal(b)
94
+ count++
95
+ return count == 1 ? Response.SuccessResponse(null) : Response.BadRequestResponse('Failed!')
96
+ })
97
+ } catch (e) {
98
+ err = e
99
+ }
100
+ // check resp
101
+ expect(count).to.be.equals(2)
102
+ expect(handlerResp).to.be.null
103
+ expect(err).to.be.deep.equal(
104
+ new Error(
105
+ JSON.stringify({
106
+ err: 'Failed!',
107
+ transactionID: 'unknown',
108
+ })
109
+ )
110
+ )
111
+ // ctx
112
+ j_expect(context.fail).not.toBeCalled()
113
+ j_expect(context.done).not.toBeCalled()
114
+ j_expect(context.succeed).not.toBeCalled()
115
+ })
116
+
117
+ test('Simple failure w/ null', async () => {
118
+ const b = { name: '123' }
119
+ const context = observableContext()
120
+ const transaction = new EventProcessor(
121
+ emptyQueueEvent({
122
+ Records: [
123
+ { body: JSON.stringify(b) },
124
+ { messageId: '123', body: JSON.stringify(b) },
125
+ { body: JSON.stringify(b) },
126
+ ],
127
+ }),
128
+ context,
129
+ {}
130
+ )
131
+ let count = 0
132
+ let handlerResp: any = null,
133
+ err: any = null
134
+ try {
135
+ handlerResp = await transaction.processEvent(
136
+ // @ts-ignore
137
+ async (transaction, eventRecord) => {
138
+ expect(eventRecord).to.be.deep.equal(b)
139
+ count++
140
+ return null
141
+ }
142
+ )
143
+ } catch (e) {
144
+ err = e
145
+ }
146
+ // check resp
147
+ expect(count).to.be.equals(1)
148
+ expect(handlerResp).to.be.null
149
+ expect(err).to.be.deep.equal(
150
+ new Error(
151
+ JSON.stringify({
152
+ err: Globals.ErrorResponseInvalidServerResponse,
153
+ rollback: true,
154
+ errCode: Globals.ErrorCode_APIError,
155
+ transactionID: 'unknown',
156
+ })
157
+ )
158
+ )
159
+ // ctx
160
+ j_expect(context.fail).not.toBeCalled()
161
+ j_expect(context.done).not.toBeCalled()
162
+ j_expect(context.succeed).not.toBeCalled()
163
+ })
164
+
165
+ test('Simple failure - allow failures', async () => {
166
+ const b = { name: '123' }
167
+ const context = observableContext()
168
+ const transaction = new EventProcessor(
169
+ emptyQueueEvent({
170
+ Records: [{ body: JSON.stringify(b) }, { messageId: '123', body: JSON.stringify(b) }],
171
+ }),
172
+ context,
173
+ {},
174
+ true
175
+ )
176
+ let count = 0
177
+ const handlerResp = await transaction.processEvent(async (transaction, eventRecord) => {
178
+ expect(eventRecord).to.be.deep.equal(b)
179
+ count++
180
+ return count == 1 ? Response.SuccessResponse(null) : Response.BadRequestResponse('Failed!')
181
+ })
182
+ // check resp
183
+ expect(count).to.be.equals(2)
184
+ expect(handlerResp).to.be.deep.equal({
185
+ batchItemFailures: [{ itemIdentifier: '123' }],
186
+ })
187
+ // ctx
188
+ j_expect(context.fail).not.toBeCalled()
189
+ j_expect(context.done).not.toBeCalled()
190
+ j_expect(context.succeed).not.toBeCalled()
191
+ })
192
+
193
+ test('Simple failure w/ null response - allow failures', async () => {
194
+ const b = { name: '123' }
195
+ const context = observableContext()
196
+ const transaction = new EventProcessor(
197
+ emptyQueueEvent({
198
+ Records: [
199
+ { messageId: '456', body: JSON.stringify(b) },
200
+ { messageId: '123', body: JSON.stringify(b) },
201
+ ],
202
+ }),
203
+ context,
204
+ {},
205
+ true
206
+ )
207
+ let count = 0
208
+ const handlerResp = await transaction.processEvent(
209
+ // @ts-ignore
210
+ async (transaction, eventRecord) => {
211
+ expect(eventRecord).to.be.deep.equal(b)
212
+ count++
213
+ return null
214
+ }
215
+ )
216
+ // check resp
217
+ expect(count).to.be.equals(2)
218
+ expect(handlerResp).to.be.deep.equal({
219
+ batchItemFailures: [{ itemIdentifier: '456' }, { itemIdentifier: '123' }],
220
+ })
221
+ // ctx
222
+ j_expect(context.fail).not.toBeCalled()
223
+ j_expect(context.done).not.toBeCalled()
224
+ j_expect(context.succeed).not.toBeCalled()
225
+ })
226
+
227
+ test('Simple failure no records', async () => {
228
+ const context = observableContext()
229
+ const transaction = new EventProcessor(emptyQueueEvent(), context, {})
230
+ let count = 0
231
+ let handlerResp: any = null,
232
+ err: any = null
233
+ try {
234
+ handlerResp = await transaction.processEvent(
235
+ // @ts-ignore
236
+ async () => {
237
+ count++
238
+ return null
239
+ }
240
+ )
241
+ } catch (e) {
242
+ err = e
243
+ }
244
+ // check resp
245
+ expect(count).to.be.equals(0)
246
+ expect(handlerResp).to.be.null
247
+ expect(err).to.be.deep.equal(
248
+ new Error(
249
+ JSON.stringify({
250
+ err: Globals.ErrorResponseNoRecords,
251
+ errCode: Globals.ErrorCode_NoRecords,
252
+ })
253
+ )
254
+ )
255
+ // ctx
256
+ j_expect(context.fail).not.toBeCalled()
257
+ j_expect(context.done).not.toBeCalled()
258
+ j_expect(context.succeed).not.toBeCalled()
259
+ })
260
+ })
261
+
262
+ export {}
@@ -0,0 +1,49 @@
1
+ import { expect } from 'chai'
2
+
3
+ import Response from '../../src/API/Response'
4
+ import Process from '../../src/BaseEvent/Process'
5
+
6
+ describe('Process success invocation path', () => {
7
+ test('Simple success', async () => {
8
+ const b = { name: '123' }
9
+ const proc = new Process({}, 100)
10
+ let count = 0
11
+ const handlerResp = await proc.execute(async () => {
12
+ count++
13
+ return Response.SuccessResponse(b)
14
+ })
15
+ // check resp
16
+ expect(handlerResp).to.be.undefined
17
+ // check iterations
18
+ return new Promise(resolve => {
19
+ setTimeout(() => {
20
+ expect(count).to.be.equals(2)
21
+ clearInterval(proc.interval)
22
+ resolve(null)
23
+ }, 250)
24
+ })
25
+ })
26
+ })
27
+
28
+ describe('Process failure invocation path', () => {
29
+ test('Simple failure', async () => {
30
+ const proc = new Process({}, 100)
31
+ let count = 0
32
+ const handlerResp = await proc.execute(async () => {
33
+ count++
34
+ throw new Error('Failed!')
35
+ })
36
+ // check resp
37
+ expect(handlerResp).to.be.undefined
38
+ // check iterations
39
+ return new Promise(resolve => {
40
+ setTimeout(() => {
41
+ expect(count).to.be.equals(2)
42
+ clearInterval(proc.interval)
43
+ resolve(null)
44
+ }, 250)
45
+ })
46
+ })
47
+ })
48
+
49
+ export {}
@@ -0,0 +1,222 @@
1
+ import { expect as j_expect } from '@jest/globals'
2
+ import { expect } from 'chai'
3
+
4
+ import Response from '../../src/API/Response'
5
+ import Transaction from '../../src/BaseEvent/Transaction'
6
+ import Globals from '../../src/Globals'
7
+ import { defaultHeaders, emptyEvent, observableContext } from '../Test.utils'
8
+
9
+ describe('Transaction success invocation path', () => {
10
+ test('Simple success', async () => {
11
+ const b = { name: '123' }
12
+ const context = observableContext()
13
+ const transaction = new Transaction<null, typeof b>(emptyEvent(), context)
14
+ const handlerResp = await transaction.execute(async () => {
15
+ return Response.SuccessResponse(b)
16
+ })
17
+ // check resp
18
+ expect(handlerResp).to.be.null
19
+ // ctx
20
+ j_expect(context.fail).not.toBeCalled()
21
+ j_expect(context.done).not.toBeCalled()
22
+ j_expect(context.succeed).toBeCalledWith({
23
+ statusCode: 200,
24
+ body: JSON.stringify(b),
25
+ headers: defaultHeaders,
26
+ })
27
+ })
28
+
29
+ test('Simple success - sync return', async () => {
30
+ const b = { name: '123' }
31
+ const context = observableContext()
32
+ const transaction = new Transaction<null, typeof b>(emptyEvent(), context, {
33
+ syncReturn: true,
34
+ })
35
+ const handlerResp = await transaction.execute(async () => {
36
+ return Response.SuccessResponse(b)
37
+ })
38
+ // check resp
39
+ expect(handlerResp).to.be.an.instanceof(Response)
40
+ expect(handlerResp?.getBody()).to.be.deep.equals(b)
41
+ expect(handlerResp?.getCode()).to.be.equals(200)
42
+ // ctx
43
+ j_expect(context.fail).not.toBeCalled()
44
+ j_expect(context.done).not.toBeCalled()
45
+ j_expect(context.succeed).not.toBeCalled()
46
+ })
47
+ })
48
+
49
+ describe('Transaction error invocation path without response', () => {
50
+ test('Not valid response returned success', async () => {
51
+ const b = {
52
+ err: Globals.ErrorResponseInvalidServerResponse,
53
+ rollback: true,
54
+ errCode: Globals.ErrorCode_APIError,
55
+ transactionID: '123',
56
+ }
57
+ const context = observableContext({ awsRequestId: '123' })
58
+ const transaction = new Transaction<null, typeof b>(emptyEvent(), context)
59
+ const handlerResp = await transaction.execute(async () => {
60
+ return null
61
+ })
62
+ // check resp
63
+ expect(handlerResp).to.be.null
64
+ // ctx
65
+ j_expect(context.fail).not.toBeCalled()
66
+ j_expect(context.done).not.toBeCalled()
67
+ j_expect(context.succeed).toBeCalledWith({
68
+ statusCode: 400,
69
+ body: JSON.stringify(b),
70
+ headers: defaultHeaders,
71
+ })
72
+ })
73
+
74
+ test('Not valid response returned success - sync return', async () => {
75
+ const b = {
76
+ err: Globals.ErrorResponseInvalidServerResponse,
77
+ rollback: true,
78
+ errCode: Globals.ErrorCode_APIError,
79
+ transactionID: '123',
80
+ }
81
+ const context = observableContext()
82
+ const transaction = new Transaction<null, typeof b>(
83
+ emptyEvent({
84
+ requestContext: { requestId: '123' },
85
+ }),
86
+ context,
87
+ {
88
+ syncReturn: true,
89
+ }
90
+ )
91
+ const handlerResp = await transaction.execute(async () => {
92
+ return null
93
+ })
94
+ // check resp
95
+ expect(handlerResp).to.be.an.instanceof(Response)
96
+ expect(handlerResp?.getBody()).to.be.deep.equals(b)
97
+ expect(handlerResp?.getCode()).to.be.equals(400)
98
+ // ctx
99
+ j_expect(context.fail).not.toBeCalled()
100
+ j_expect(context.done).not.toBeCalled()
101
+ j_expect(context.succeed).not.toBeCalled()
102
+ })
103
+ })
104
+
105
+ describe('Transaction error invocation path with non-Response class response', () => {
106
+ test('Not a response-class response returned success', async () => {
107
+ const b = {
108
+ err: Globals.ErrorResponseInvalidServerResponse,
109
+ rollback: true,
110
+ errCode: Globals.ErrorCode_APIError,
111
+ transactionID: 'unknown',
112
+ }
113
+ const b2 = { name: 'abc' }
114
+ const context = observableContext()
115
+ const transaction = new Transaction<null, null, typeof b2>(emptyEvent(), context)
116
+ const handlerResp = await transaction.execute(async () => {
117
+ return b2
118
+ })
119
+ // check resp
120
+ expect(handlerResp).to.be.null
121
+ // ctx
122
+ j_expect(context.fail).not.toBeCalled()
123
+ j_expect(context.done).not.toBeCalled()
124
+ j_expect(context.succeed).toBeCalledWith({
125
+ statusCode: 400,
126
+ body: JSON.stringify(b),
127
+ headers: defaultHeaders,
128
+ })
129
+ })
130
+
131
+ test('Not a response-class response returned success - sync return', async () => {
132
+ const b2 = { name: 'abc' }
133
+ const context = observableContext()
134
+ const transaction = new Transaction<null, null, typeof b2>(emptyEvent(), context, {
135
+ syncReturn: true,
136
+ })
137
+ const handlerResp = await transaction.execute(async () => {
138
+ return b2
139
+ })
140
+ // check resp
141
+ expect(handlerResp).to.be.deep.equals(b2)
142
+ // ctx
143
+ j_expect(context.fail).not.toBeCalled()
144
+ j_expect(context.done).not.toBeCalled()
145
+ j_expect(context.succeed).not.toBeCalled()
146
+ })
147
+ })
148
+
149
+ describe('Transaction error invocation path with exception', () => {
150
+ test('Transaction exception', async () => {
151
+ const b = {
152
+ err: Globals.ErrorResponseUnhandledError,
153
+ rollback: true,
154
+ errCode: Globals.ErrorCode_APIError,
155
+ transactionID: 'unknown',
156
+ }
157
+ const context = observableContext()
158
+ const transaction = new Transaction<null, null, null>(emptyEvent(), context)
159
+ const handlerResp = await transaction.execute(async () => {
160
+ throw new Error('Failed!')
161
+ })
162
+ // check resp
163
+ expect(handlerResp).to.be.null
164
+ // ctx
165
+ j_expect(context.fail).not.toBeCalled()
166
+ j_expect(context.done).not.toBeCalled()
167
+ j_expect(context.succeed).toBeCalledWith({
168
+ statusCode: 400,
169
+ body: JSON.stringify(b),
170
+ headers: defaultHeaders,
171
+ })
172
+ })
173
+
174
+ test('Transaction exception - sync return', async () => {
175
+ const b = {
176
+ err: Globals.ErrorResponseUnhandledError,
177
+ rollback: true,
178
+ errCode: Globals.ErrorCode_APIError,
179
+ transactionID: 'unknown',
180
+ }
181
+ const context = observableContext()
182
+ const transaction = new Transaction<null, null, null>(emptyEvent(), context, {
183
+ syncReturn: true,
184
+ })
185
+ const handlerResp = await transaction.execute(async () => {
186
+ throw new Error('Failed!')
187
+ })
188
+ // check resp
189
+ expect(handlerResp?.getBody()).to.be.deep.equals(b)
190
+ expect(handlerResp?.getCode()).to.be.equals(400)
191
+ // ctx
192
+ j_expect(context.fail).not.toBeCalled()
193
+ j_expect(context.done).not.toBeCalled()
194
+ j_expect(context.succeed).not.toBeCalled()
195
+ })
196
+
197
+ test('Transaction exception - sync return', async () => {
198
+ const context = observableContext()
199
+ const transaction = new Transaction<null, null, null>(emptyEvent(), context, {
200
+ throwOnErrors: true,
201
+ })
202
+ const error = new Error('Failed!')
203
+ let handlerResp: any = null,
204
+ err: any = null
205
+ try {
206
+ handlerResp = await transaction.execute(async () => {
207
+ throw error
208
+ })
209
+ } catch (e) {
210
+ err = e
211
+ }
212
+ // check resp
213
+ expect(handlerResp).to.be.null
214
+ expect(err).to.be.deep.equals(error)
215
+ // ctx
216
+ j_expect(context.fail).not.toBeCalled()
217
+ j_expect(context.done).not.toBeCalled()
218
+ j_expect(context.succeed).not.toBeCalled()
219
+ })
220
+ })
221
+
222
+ export {}