@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,261 @@
1
+ import { expect as c_expect } from 'chai'
2
+
3
+ import Response from '../../src/API/Response'
4
+ import EventProcessor from '../../src/BaseEvent/EventProcessor'
5
+ import Globals from '../../src/Globals'
6
+ import { emptyQueueEvent, observableContext } from '../Test.utils'
7
+
8
+ describe('EventProcessor success invocation path', () => {
9
+ test('Simple success', async () => {
10
+ const b = { name: '123' }
11
+ const context = observableContext()
12
+ const transaction = new EventProcessor(
13
+ emptyQueueEvent({
14
+ Records: [{ body: JSON.stringify(b) }, { body: JSON.stringify(b) }],
15
+ }),
16
+ context,
17
+ {}
18
+ )
19
+ let count = 0
20
+ const handlerResp = await transaction.processEvent(async (transaction, eventRecord) => {
21
+ c_expect(eventRecord).to.be.deep.equal(b)
22
+ count++
23
+ return Response.SuccessResponse(null)
24
+ })
25
+ // check resp
26
+ c_expect(count).to.be.equals(2)
27
+ c_expect(handlerResp).to.be.an.instanceof(Response)
28
+ if (handlerResp instanceof Response) {
29
+ c_expect(handlerResp?.getBody()).to.be.deep.equal({
30
+ transactionID: 'unknown',
31
+ })
32
+ c_expect(handlerResp.getCode()).to.be.equal(200)
33
+ }
34
+ // ctx
35
+ expect(context.fail).not.toBeCalled()
36
+ expect(context.done).not.toBeCalled()
37
+ expect(context.succeed).not.toBeCalled()
38
+ })
39
+
40
+ test('Simple success - do not decode', async () => {
41
+ const b = { name: '123' }
42
+ const context = observableContext()
43
+ const transaction = new EventProcessor(
44
+ emptyQueueEvent({
45
+ Records: [{ body: JSON.stringify(b) }, { body: JSON.stringify(b) }],
46
+ }),
47
+ context,
48
+ {}
49
+ )
50
+ let count = 0
51
+ const handlerResp = await transaction.processEvent(async (transaction, eventRecord) => {
52
+ c_expect(eventRecord).to.be.deep.equal(JSON.stringify(b))
53
+ count++
54
+ return Response.SuccessResponse(null)
55
+ }, true)
56
+ // check resp
57
+ c_expect(count).to.be.equals(2)
58
+ c_expect(handlerResp).to.be.an.instanceof(Response)
59
+ if (handlerResp instanceof Response) {
60
+ c_expect(handlerResp?.getBody()).to.be.deep.equal({
61
+ transactionID: 'unknown',
62
+ })
63
+ c_expect(handlerResp.getCode()).to.be.equal(200)
64
+ }
65
+ // ctx
66
+ expect(context.fail).not.toBeCalled()
67
+ expect(context.done).not.toBeCalled()
68
+ expect(context.succeed).not.toBeCalled()
69
+ })
70
+ })
71
+
72
+ describe('EventProcessor failure invocation path', () => {
73
+ test('Simple failure', async () => {
74
+ const b = { name: '123' }
75
+ const context = observableContext()
76
+ const transaction = new EventProcessor(
77
+ emptyQueueEvent({
78
+ Records: [
79
+ { body: JSON.stringify(b) },
80
+ { messageId: '123', body: JSON.stringify(b) },
81
+ { body: JSON.stringify(b) },
82
+ ],
83
+ }),
84
+ context,
85
+ {}
86
+ )
87
+ let count = 0
88
+ let handlerResp: any = null,
89
+ err: any = null
90
+ try {
91
+ handlerResp = await transaction.processEvent(async (transaction, eventRecord) => {
92
+ c_expect(eventRecord).to.be.deep.equal(b)
93
+ count++
94
+ return count == 1 ? Response.SuccessResponse(null) : Response.BadRequestResponse('Failed!')
95
+ })
96
+ } catch (e) {
97
+ err = e
98
+ }
99
+ // check resp
100
+ c_expect(count).to.be.equals(2)
101
+ c_expect(handlerResp).to.be.null
102
+ c_expect(err).to.be.deep.equal(
103
+ new Error(
104
+ JSON.stringify({
105
+ err: 'Failed!',
106
+ transactionID: 'unknown',
107
+ })
108
+ )
109
+ )
110
+ // ctx
111
+ expect(context.fail).not.toBeCalled()
112
+ expect(context.done).not.toBeCalled()
113
+ expect(context.succeed).not.toBeCalled()
114
+ })
115
+
116
+ test('Simple failure w/ null', async () => {
117
+ const b = { name: '123' }
118
+ const context = observableContext()
119
+ const transaction = new EventProcessor(
120
+ emptyQueueEvent({
121
+ Records: [
122
+ { body: JSON.stringify(b) },
123
+ { messageId: '123', body: JSON.stringify(b) },
124
+ { body: JSON.stringify(b) },
125
+ ],
126
+ }),
127
+ context,
128
+ {}
129
+ )
130
+ let count = 0
131
+ let handlerResp: any = null,
132
+ err: any = null
133
+ try {
134
+ handlerResp = await transaction.processEvent(
135
+ // @ts-ignore
136
+ async (transaction, eventRecord) => {
137
+ c_expect(eventRecord).to.be.deep.equal(b)
138
+ count++
139
+ return null
140
+ }
141
+ )
142
+ } catch (e) {
143
+ err = e
144
+ }
145
+ // check resp
146
+ c_expect(count).to.be.equals(1)
147
+ c_expect(handlerResp).to.be.null
148
+ c_expect(err).to.be.deep.equal(
149
+ new Error(
150
+ JSON.stringify({
151
+ err: Globals.ErrorResponseInvalidServerResponse,
152
+ rollback: true,
153
+ errCode: Globals.ErrorCode_APIError,
154
+ transactionID: 'unknown',
155
+ })
156
+ )
157
+ )
158
+ // ctx
159
+ expect(context.fail).not.toBeCalled()
160
+ expect(context.done).not.toBeCalled()
161
+ expect(context.succeed).not.toBeCalled()
162
+ })
163
+
164
+ test('Simple failure - allow failures', async () => {
165
+ const b = { name: '123' }
166
+ const context = observableContext()
167
+ const transaction = new EventProcessor(
168
+ emptyQueueEvent({
169
+ Records: [{ body: JSON.stringify(b) }, { messageId: '123', body: JSON.stringify(b) }],
170
+ }),
171
+ context,
172
+ {},
173
+ true
174
+ )
175
+ let count = 0
176
+ const handlerResp = await transaction.processEvent(async (transaction, eventRecord) => {
177
+ c_expect(eventRecord).to.be.deep.equal(b)
178
+ count++
179
+ return count == 1 ? Response.SuccessResponse(null) : Response.BadRequestResponse('Failed!')
180
+ })
181
+ // check resp
182
+ c_expect(count).to.be.equals(2)
183
+ c_expect(handlerResp).to.be.deep.equal({
184
+ batchItemFailures: [{ itemIdentifier: '123' }],
185
+ })
186
+ // ctx
187
+ expect(context.fail).not.toBeCalled()
188
+ expect(context.done).not.toBeCalled()
189
+ expect(context.succeed).not.toBeCalled()
190
+ })
191
+
192
+ test('Simple failure w/ null response - allow failures', async () => {
193
+ const b = { name: '123' }
194
+ const context = observableContext()
195
+ const transaction = new EventProcessor(
196
+ emptyQueueEvent({
197
+ Records: [
198
+ { messageId: '456', body: JSON.stringify(b) },
199
+ { messageId: '123', body: JSON.stringify(b) },
200
+ ],
201
+ }),
202
+ context,
203
+ {},
204
+ true
205
+ )
206
+ let count = 0
207
+ const handlerResp = await transaction.processEvent(
208
+ // @ts-ignore
209
+ async (transaction, eventRecord) => {
210
+ c_expect(eventRecord).to.be.deep.equal(b)
211
+ count++
212
+ return null
213
+ }
214
+ )
215
+ // check resp
216
+ c_expect(count).to.be.equals(2)
217
+ c_expect(handlerResp).to.be.deep.equal({
218
+ batchItemFailures: [{ itemIdentifier: '456' }, { itemIdentifier: '123' }],
219
+ })
220
+ // ctx
221
+ expect(context.fail).not.toBeCalled()
222
+ expect(context.done).not.toBeCalled()
223
+ expect(context.succeed).not.toBeCalled()
224
+ })
225
+
226
+ test('Simple failure no records', async () => {
227
+ const context = observableContext()
228
+ const transaction = new EventProcessor(emptyQueueEvent(), context, {})
229
+ let count = 0
230
+ let handlerResp: any = null,
231
+ err: any = null
232
+ try {
233
+ handlerResp = await transaction.processEvent(
234
+ // @ts-ignore
235
+ async () => {
236
+ count++
237
+ return null
238
+ }
239
+ )
240
+ } catch (e) {
241
+ err = e
242
+ }
243
+ // check resp
244
+ c_expect(count).to.be.equals(0)
245
+ c_expect(handlerResp).to.be.null
246
+ c_expect(err).to.be.deep.equal(
247
+ new Error(
248
+ JSON.stringify({
249
+ err: Globals.ErrorResponseNoRecords,
250
+ errCode: Globals.ErrorCode_NoRecords,
251
+ })
252
+ )
253
+ )
254
+ // ctx
255
+ expect(context.fail).not.toBeCalled()
256
+ expect(context.done).not.toBeCalled()
257
+ expect(context.succeed).not.toBeCalled()
258
+ })
259
+ })
260
+
261
+ 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.timeout)
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.timeout)
43
+ resolve(null)
44
+ }, 250)
45
+ })
46
+ })
47
+ })
48
+
49
+ export {}
@@ -0,0 +1,408 @@
1
+ import { jest } from '@jest/globals'
2
+ import { expect as c_expect } from 'chai'
3
+
4
+ import Response from '../../src/API/Response'
5
+ import Transaction from '../../src/BaseEvent/Transaction'
6
+ import type { DbConfig } from '../../src/Database/types'
7
+ import Globals from '../../src/Globals'
8
+ import { defaultHeaders, emptyEvent, observableContext } from '../Test.utils'
9
+
10
+ describe('Transaction success invocation path', () => {
11
+ test('Simple success', async () => {
12
+ const b = { name: '123' }
13
+ const context = observableContext()
14
+ const transaction = new Transaction<null, typeof b>(emptyEvent(), context)
15
+ const handlerResp = await transaction.execute(async () => {
16
+ return Response.SuccessResponse(b)
17
+ })
18
+ // check resp
19
+ c_expect(handlerResp).to.be.null
20
+ // ctx
21
+ expect(context.fail).not.toBeCalled()
22
+ expect(context.done).not.toBeCalled()
23
+ expect(context.succeed).toBeCalledWith({
24
+ statusCode: 200,
25
+ body: JSON.stringify(b),
26
+ headers: defaultHeaders,
27
+ })
28
+ })
29
+
30
+ test('Simple success - sync return', async () => {
31
+ const b = { name: '123' }
32
+ const context = observableContext()
33
+ const transaction = new Transaction<null, typeof b>(emptyEvent(), context, {
34
+ syncReturn: true,
35
+ })
36
+ const handlerResp = await transaction.execute(async () => {
37
+ return Response.SuccessResponse(b)
38
+ })
39
+ // check resp
40
+ c_expect(handlerResp).to.be.an.instanceof(Response)
41
+ c_expect(handlerResp?.getBody()).to.be.deep.equals(b)
42
+ c_expect(handlerResp?.getCode()).to.be.equals(200)
43
+ // ctx
44
+ expect(context.fail).not.toBeCalled()
45
+ expect(context.done).not.toBeCalled()
46
+ expect(context.succeed).not.toBeCalled()
47
+ })
48
+ })
49
+
50
+ describe('Transaction error invocation path without response', () => {
51
+ test('Not valid response returned success', async () => {
52
+ const b = {
53
+ err: Globals.ErrorResponseInvalidServerResponse,
54
+ rollback: true,
55
+ errCode: Globals.ErrorCode_APIError,
56
+ transactionID: '123',
57
+ }
58
+ const context = observableContext({ awsRequestId: '123' })
59
+ const transaction = new Transaction<null, typeof b>(emptyEvent(), context)
60
+ // @ts-expect-error
61
+ const handlerResp = await transaction.execute(async () => {
62
+ return null
63
+ })
64
+ // check resp
65
+ c_expect(handlerResp).to.be.null
66
+ // ctx
67
+ expect(context.fail).not.toBeCalled()
68
+ expect(context.done).not.toBeCalled()
69
+ expect(context.succeed).toBeCalledWith({
70
+ statusCode: 400,
71
+ body: JSON.stringify(b),
72
+ headers: defaultHeaders,
73
+ })
74
+ })
75
+
76
+ test('Not valid response returned success - sync return', async () => {
77
+ const b = {
78
+ err: Globals.ErrorResponseInvalidServerResponse,
79
+ rollback: true,
80
+ errCode: Globals.ErrorCode_APIError,
81
+ transactionID: '123',
82
+ }
83
+ const context = observableContext()
84
+ const transaction = new Transaction<null, typeof b>(
85
+ emptyEvent({
86
+ requestContext: { requestId: '123' },
87
+ }),
88
+ context,
89
+ {
90
+ syncReturn: true,
91
+ }
92
+ )
93
+ // @ts-expect-error
94
+ const handlerResp = await transaction.execute(async () => {
95
+ return null
96
+ })
97
+ // check resp
98
+ c_expect(handlerResp).to.be.an.instanceof(Response)
99
+ c_expect(handlerResp?.getBody()).to.be.deep.equals(b)
100
+ c_expect(handlerResp?.getCode()).to.be.equals(400)
101
+ // ctx
102
+ expect(context.fail).not.toBeCalled()
103
+ expect(context.done).not.toBeCalled()
104
+ expect(context.succeed).not.toBeCalled()
105
+ })
106
+ })
107
+
108
+ describe('Transaction error invocation path with non-Response class response', () => {
109
+ test('Not a response-class response returned success', async () => {
110
+ const b = {
111
+ err: Globals.ErrorResponseInvalidServerResponse,
112
+ rollback: true,
113
+ errCode: Globals.ErrorCode_APIError,
114
+ transactionID: 'unknown',
115
+ }
116
+ const b2 = { name: 'abc' }
117
+ const context = observableContext()
118
+ const transaction = new Transaction<null, null, typeof b2>(emptyEvent(), context)
119
+ const handlerResp = await transaction.execute(async () => {
120
+ return b2
121
+ })
122
+ // check resp
123
+ c_expect(handlerResp).to.be.null
124
+ // ctx
125
+ expect(context.fail).not.toBeCalled()
126
+ expect(context.done).not.toBeCalled()
127
+ expect(context.succeed).toBeCalledWith({
128
+ statusCode: 400,
129
+ body: JSON.stringify(b),
130
+ headers: defaultHeaders,
131
+ })
132
+ })
133
+
134
+ test('Not a response-class response returned success - sync return', async () => {
135
+ const b2 = { name: 'abc' }
136
+ const context = observableContext()
137
+ const transaction = new Transaction<null, null, typeof b2>(emptyEvent(), context, {
138
+ syncReturn: true,
139
+ })
140
+ const handlerResp = await transaction.execute(async () => {
141
+ return b2
142
+ })
143
+ // check resp
144
+ c_expect(handlerResp).to.be.deep.equals(b2)
145
+ // ctx
146
+ expect(context.fail).not.toBeCalled()
147
+ expect(context.done).not.toBeCalled()
148
+ expect(context.succeed).not.toBeCalled()
149
+ })
150
+ })
151
+
152
+ describe('Transaction error invocation path with exception', () => {
153
+ test('Transaction exception', async () => {
154
+ const b = {
155
+ err: Globals.ErrorResponseUnhandledError,
156
+ rollback: true,
157
+ errCode: Globals.ErrorCode_APIError,
158
+ transactionID: 'unknown',
159
+ }
160
+ const context = observableContext()
161
+ const transaction = new Transaction<null, null, null>(emptyEvent(), context)
162
+ const handlerResp = await transaction.execute(async () => {
163
+ throw new Error('Failed!')
164
+ })
165
+ // check resp
166
+ c_expect(handlerResp).to.be.null
167
+ // ctx
168
+ expect(context.fail).not.toBeCalled()
169
+ expect(context.done).not.toBeCalled()
170
+ expect(context.succeed).toBeCalledWith({
171
+ statusCode: 400,
172
+ body: JSON.stringify(b),
173
+ headers: defaultHeaders,
174
+ })
175
+ })
176
+
177
+ test('Transaction exception - sync return', async () => {
178
+ const b = {
179
+ err: Globals.ErrorResponseUnhandledError,
180
+ rollback: true,
181
+ errCode: Globals.ErrorCode_APIError,
182
+ transactionID: 'unknown',
183
+ }
184
+ const context = observableContext()
185
+ const transaction = new Transaction<null, null, null>(emptyEvent(), context, {
186
+ syncReturn: true,
187
+ })
188
+ const handlerResp = await transaction.execute(async () => {
189
+ throw new Error('Failed!')
190
+ })
191
+ // check resp
192
+ c_expect(handlerResp?.getBody()).to.be.deep.equals(b)
193
+ c_expect(handlerResp?.getCode()).to.be.equals(400)
194
+ // ctx
195
+ expect(context.fail).not.toBeCalled()
196
+ expect(context.done).not.toBeCalled()
197
+ expect(context.succeed).not.toBeCalled()
198
+ })
199
+
200
+ test('Transaction exception - sync return', async () => {
201
+ const context = observableContext()
202
+ const transaction = new Transaction<null, null, null>(emptyEvent(), context, {
203
+ throwOnErrors: true,
204
+ })
205
+ const error = new Error('Failed!')
206
+ let handlerResp: any = null,
207
+ err: any = null
208
+ try {
209
+ handlerResp = await transaction.execute(async () => {
210
+ throw error
211
+ })
212
+ } catch (e) {
213
+ err = e
214
+ }
215
+ // check resp
216
+ c_expect(handlerResp).to.be.null
217
+ c_expect(err).to.be.deep.equals(error)
218
+ // ctx
219
+ expect(context.fail).not.toBeCalled()
220
+ expect(context.done).not.toBeCalled()
221
+ expect(context.succeed).not.toBeCalled()
222
+ })
223
+ })
224
+
225
+ describe('Transaction - db integration', () => {
226
+ const testResources = () => {
227
+ const mockTrans = {
228
+ select: jest.fn(),
229
+ closeSuccess: jest.fn(),
230
+ closeFailure: jest.fn(),
231
+ }
232
+ const mockCreate = jest.fn(
233
+ () => ({ transaction: () => new Promise(resolve => resolve(mockTrans)) }) as any
234
+ )
235
+
236
+ const transaction = new Transaction(emptyEvent(), observableContext())
237
+ transaction['databaseManager'] = {
238
+ create: mockCreate,
239
+ } as any
240
+
241
+ return {
242
+ transaction,
243
+ mockCreate,
244
+ mockTrans,
245
+ }
246
+ }
247
+
248
+ const config = { username: 'test' } as DbConfig<'knex'>
249
+
250
+ test('Transaction provides dbTransaction and calls closeSuccess', async () => {
251
+ const { mockCreate, mockTrans, transaction } = testResources()
252
+
253
+ await transaction.execute(async () => {
254
+ const knexTransaction = await transaction.getDbTransaction(config)
255
+
256
+ knexTransaction.select('name')
257
+
258
+ return Response.SuccessResponse(null)
259
+ })
260
+ expect(mockCreate).toBeCalledWith(config)
261
+ expect(mockTrans.select).toBeCalledWith('name')
262
+ expect(mockTrans.closeSuccess).toBeCalled()
263
+ })
264
+
265
+ test('Errored transaction calls closeFailure', async () => {
266
+ const { mockCreate, transaction, mockTrans } = testResources()
267
+
268
+ const ss = await transaction.execute(async () => {
269
+ const _ii = await transaction.getDbTransaction(config)
270
+ console.log('ii', _ii)
271
+ throw new Error('Something went wrong!')
272
+
273
+ return Response.SuccessResponse(null)
274
+ })
275
+
276
+ console.log(ss)
277
+
278
+ expect(mockCreate).toBeCalledWith(config)
279
+ expect(mockTrans.closeFailure).toBeCalled()
280
+ })
281
+ })
282
+
283
+ describe('Transaction response types', () => {
284
+ test('Non-response return', async () => {
285
+ const b = { name: '123' }
286
+ const b2 = {
287
+ err: Globals.ErrorResponseInvalidServerResponse,
288
+ rollback: true,
289
+ errCode: Globals.ErrorCode_APIError,
290
+ transactionID: 'unknown',
291
+ }
292
+ const context = observableContext()
293
+ const transaction = new Transaction<null, typeof b>(emptyEvent(), context)
294
+ // @ts-expect-error
295
+ const handlerResp = await transaction.execute(async () => {
296
+ return { d: 1 }
297
+ })
298
+ // check resp
299
+ c_expect(handlerResp).to.be.null
300
+ // ctx
301
+ expect(context.fail).not.toBeCalled()
302
+ expect(context.done).not.toBeCalled()
303
+ expect(context.succeed).toBeCalledWith({
304
+ statusCode: 400,
305
+ body: JSON.stringify(b2),
306
+ headers: defaultHeaders,
307
+ })
308
+ })
309
+
310
+ test('Null return', async () => {
311
+ const b = { name: '123' }
312
+ const b2 = {
313
+ err: Globals.ErrorResponseInvalidServerResponse,
314
+ rollback: true,
315
+ errCode: Globals.ErrorCode_APIError,
316
+ transactionID: 'unknown',
317
+ }
318
+ const context = observableContext()
319
+ const transaction = new Transaction<null, typeof b>(emptyEvent(), context)
320
+ // @ts-expect-error
321
+ const handlerResp = await transaction.execute(async () => {
322
+ return null
323
+ })
324
+ // check resp
325
+ c_expect(handlerResp).to.be.null
326
+ // ctx
327
+ expect(context.fail).not.toBeCalled()
328
+ expect(context.done).not.toBeCalled()
329
+ expect(context.succeed).toBeCalledWith({
330
+ statusCode: 400,
331
+ body: JSON.stringify(b2),
332
+ headers: defaultHeaders,
333
+ })
334
+ })
335
+
336
+ test('Undefined return', async () => {
337
+ const b = { name: '123' }
338
+ const b2 = {
339
+ err: Globals.ErrorResponseInvalidServerResponse,
340
+ rollback: true,
341
+ errCode: Globals.ErrorCode_APIError,
342
+ transactionID: 'unknown',
343
+ }
344
+ const context = observableContext()
345
+ const transaction = new Transaction<null, typeof b>(emptyEvent(), context)
346
+ // @ts-expect-error
347
+ const handlerResp = await transaction.execute(async () => {
348
+ return
349
+ })
350
+ // check resp
351
+ c_expect(handlerResp).to.be.null
352
+ // ctx
353
+ expect(context.fail).not.toBeCalled()
354
+ expect(context.done).not.toBeCalled()
355
+ expect(context.succeed).toBeCalledWith({
356
+ statusCode: 400,
357
+ body: JSON.stringify(b2),
358
+ headers: defaultHeaders,
359
+ })
360
+ })
361
+
362
+ test('Null inner-response return', async () => {
363
+ const b = { name: '123' }
364
+ const b2 = { transactionID: 'unknown' }
365
+ const context = observableContext()
366
+ const transaction = new Transaction<null, typeof b>(emptyEvent(), context)
367
+ // @ts-expect-error
368
+ const handlerResp = await transaction.execute(async () => {
369
+ return Response.SuccessResponse(null)
370
+ })
371
+ // check resp
372
+ c_expect(handlerResp).to.be.null
373
+ // ctx
374
+ expect(context.fail).not.toBeCalled()
375
+ expect(context.done).not.toBeCalled()
376
+ expect(context.succeed).toBeCalledWith({
377
+ statusCode: 200,
378
+ body: JSON.stringify(b2),
379
+ headers: defaultHeaders,
380
+ })
381
+ })
382
+
383
+ test('Wrong keys inner-response return', async () => {
384
+ const b = { name: '123' }
385
+ const b2 = {
386
+ notName: '123',
387
+ transactionID: 'unknown',
388
+ }
389
+ const context = observableContext()
390
+ const transaction = new Transaction<null, typeof b>(emptyEvent(), context)
391
+ // @ts-expect-error
392
+ const handlerResp = await transaction.execute(async () => {
393
+ return Response.SuccessResponse({ notName: '123' })
394
+ })
395
+ // check resp
396
+ c_expect(handlerResp).to.be.null
397
+ // ctx
398
+ expect(context.fail).not.toBeCalled()
399
+ expect(context.done).not.toBeCalled()
400
+ expect(context.succeed).toBeCalledWith({
401
+ statusCode: 200,
402
+ body: JSON.stringify(b2),
403
+ headers: defaultHeaders,
404
+ })
405
+ })
406
+ })
407
+
408
+ export {}