@mojaloop/sdk-scheme-adapter 18.0.0 → 18.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/.dockerignore +18 -0
  2. package/.eslintignore +2 -0
  3. package/.ncurc.yaml +7 -0
  4. package/CHANGELOG.md +20 -0
  5. package/CODEOWNERS +31 -1
  6. package/README.md +1 -0
  7. package/audit-resolve.json +35 -0
  8. package/package.json +13 -13
  9. package/test/__mocks__/@mojaloop/sdk-standard-components.js +0 -151
  10. package/test/__mocks__/javascript-state-machine.js +0 -21
  11. package/test/__mocks__/redis.js +0 -78
  12. package/test/__mocks__/uuidv4.js +0 -16
  13. package/test/config/integration.env +0 -146
  14. package/test/integration/lib/Outbound/data/quotesPostRequest.json +0 -52
  15. package/test/integration/lib/Outbound/data/transfersPostRequest.json +0 -24
  16. package/test/integration/lib/Outbound/parties.test.js +0 -31
  17. package/test/integration/lib/Outbound/quotes.test.js +0 -62
  18. package/test/integration/lib/Outbound/simpleTransfers.test.js +0 -70
  19. package/test/integration/lib/cache.test.js +0 -79
  20. package/test/integration/testEnv.js +0 -4
  21. package/test/unit/ControlClient.test.js +0 -69
  22. package/test/unit/ControlServer/events.js +0 -41
  23. package/test/unit/ControlServer/index.js +0 -227
  24. package/test/unit/ControlServer.test.js +0 -66
  25. package/test/unit/InboundServer.test.js +0 -443
  26. package/test/unit/TestServer.test.js +0 -392
  27. package/test/unit/api/accounts/accounts.test.js +0 -128
  28. package/test/unit/api/accounts/data/postAccountsBody.json +0 -7
  29. package/test/unit/api/accounts/data/postAccountsErrorMojaloopResponse.json +0 -33
  30. package/test/unit/api/accounts/data/postAccountsErrorTimeoutResponse.json +0 -19
  31. package/test/unit/api/accounts/data/postAccountsSuccessResponse.json +0 -31
  32. package/test/unit/api/accounts/data/postAccountsSuccessResponseWithError1.json +0 -34
  33. package/test/unit/api/accounts/data/postAccountsSuccessResponseWithError2.json +0 -39
  34. package/test/unit/api/accounts/utils.js +0 -79
  35. package/test/unit/api/proxy/data/proxyConfig.yaml +0 -82
  36. package/test/unit/api/proxy/data/requestBody.json +0 -22
  37. package/test/unit/api/proxy/data/requestHeaders.json +0 -5
  38. package/test/unit/api/proxy/data/requestQuery.json +0 -6
  39. package/test/unit/api/proxy/data/responseBody.json +0 -21
  40. package/test/unit/api/proxy/data/responseHeaders.json +0 -5
  41. package/test/unit/api/proxy/proxy.test.js +0 -220
  42. package/test/unit/api/proxy/utils.js +0 -79
  43. package/test/unit/api/transfers/data/getTransfersCommittedResponse.json +0 -24
  44. package/test/unit/api/transfers/data/getTransfersErrorNotFound.json +0 -18
  45. package/test/unit/api/transfers/data/postQuotesBody.json +0 -52
  46. package/test/unit/api/transfers/data/postTransfersBadBody.json +0 -17
  47. package/test/unit/api/transfers/data/postTransfersBody.json +0 -24
  48. package/test/unit/api/transfers/data/postTransfersErrorMojaloopResponse.json +0 -62
  49. package/test/unit/api/transfers/data/postTransfersErrorTimeoutResponse.json +0 -48
  50. package/test/unit/api/transfers/data/postTransfersSimpleBody.json +0 -26
  51. package/test/unit/api/transfers/data/postTransfersSuccessResponse.json +0 -128
  52. package/test/unit/api/transfers/data/putPartiesBody.json +0 -20
  53. package/test/unit/api/transfers/data/putQuotesBody.json +0 -37
  54. package/test/unit/api/transfers/data/putTransfersBody.json +0 -17
  55. package/test/unit/api/transfers/transfers.test.js +0 -191
  56. package/test/unit/api/transfers/utils.js +0 -264
  57. package/test/unit/api/utils.js +0 -86
  58. package/test/unit/config.test.js +0 -119
  59. package/test/unit/data/commonHttpHeaders.json +0 -7
  60. package/test/unit/data/defaultConfig.json +0 -70
  61. package/test/unit/data/postQuotesBody.json +0 -52
  62. package/test/unit/data/putParticipantsBody.json +0 -12
  63. package/test/unit/data/putPartiesBody.json +0 -20
  64. package/test/unit/data/testFile.json +0 -29
  65. package/test/unit/data/testFile.yaml +0 -14
  66. package/test/unit/inboundApi/data/mockArguments.json +0 -117
  67. package/test/unit/inboundApi/data/mockTransactionRequest.json +0 -42
  68. package/test/unit/inboundApi/handlers.test.js +0 -786
  69. package/test/unit/index.test.js +0 -88
  70. package/test/unit/lib/cache.test.js +0 -145
  71. package/test/unit/lib/model/AccountsModel.test.js +0 -124
  72. package/test/unit/lib/model/InboundTransfersModel.test.js +0 -889
  73. package/test/unit/lib/model/OutboundBulkQuotesModel.test.js +0 -253
  74. package/test/unit/lib/model/OutboundBulkTransfersModel.test.js +0 -247
  75. package/test/unit/lib/model/OutboundRequestToPayModel.test.js +0 -166
  76. package/test/unit/lib/model/OutboundRequestToPayTransferModel.test.js +0 -245
  77. package/test/unit/lib/model/OutboundTransfersModel.test.js +0 -1579
  78. package/test/unit/lib/model/PartiesModel.test.js +0 -478
  79. package/test/unit/lib/model/QuotesModel.test.js +0 -477
  80. package/test/unit/lib/model/TransfersModel.test.js +0 -481
  81. package/test/unit/lib/model/common/PersistentStateMachine.test.js +0 -178
  82. package/test/unit/lib/model/data/authorizationsResponse.json +0 -13
  83. package/test/unit/lib/model/data/bulkQuoteRequest.json +0 -27
  84. package/test/unit/lib/model/data/bulkQuoteResponse.json +0 -35
  85. package/test/unit/lib/model/data/bulkTransferFulfil.json +0 -13
  86. package/test/unit/lib/model/data/bulkTransferRequest.json +0 -29
  87. package/test/unit/lib/model/data/defaultConfig.json +0 -59
  88. package/test/unit/lib/model/data/getBulkTransfersBackendResponse.json +0 -42
  89. package/test/unit/lib/model/data/getBulkTransfersMojaloopResponse.json +0 -22
  90. package/test/unit/lib/model/data/getTransfersBackendResponse.json +0 -34
  91. package/test/unit/lib/model/data/getTransfersMojaloopResponse.json +0 -17
  92. package/test/unit/lib/model/data/mockArguments.json +0 -188
  93. package/test/unit/lib/model/data/mockTxnRequestsArguments.json +0 -63
  94. package/test/unit/lib/model/data/notificationAbortedToPayee.json +0 -10
  95. package/test/unit/lib/model/data/notificationReservedToPayee.json +0 -10
  96. package/test/unit/lib/model/data/notificationToPayee.json +0 -10
  97. package/test/unit/lib/model/data/payeeParty.json +0 -18
  98. package/test/unit/lib/model/data/putQuotesResponse.json +0 -33
  99. package/test/unit/lib/model/data/putTransfersResponse.json +0 -5
  100. package/test/unit/lib/model/data/quoteResponse.json +0 -42
  101. package/test/unit/lib/model/data/requestToPayRequest.json +0 -20
  102. package/test/unit/lib/model/data/requestToPayTransferRequest.json +0 -27
  103. package/test/unit/lib/model/data/transactionRequestResponse.json +0 -18
  104. package/test/unit/lib/model/data/transferFulfil.json +0 -10
  105. package/test/unit/lib/model/data/transferRequest.json +0 -26
  106. package/test/unit/lib/model/mockedLibRequests.js +0 -74
  107. package/test/unit/mockLogger.js +0 -39
  108. package/test/unit/outboundApi/data/bulkQuoteRequest.json +0 -28
  109. package/test/unit/outboundApi/data/bulkTransferRequest.json +0 -28
  110. package/test/unit/outboundApi/data/mockBulkQuoteError.json +0 -45
  111. package/test/unit/outboundApi/data/mockBulkTransferError.json +0 -48
  112. package/test/unit/outboundApi/data/mockError.json +0 -41
  113. package/test/unit/outboundApi/data/mockGetPartiesError.json +0 -4
  114. package/test/unit/outboundApi/data/mockRequestToPayError.json +0 -32
  115. package/test/unit/outboundApi/data/mockRequestToPayTransferError.json +0 -39
  116. package/test/unit/outboundApi/data/requestToPay.json +0 -21
  117. package/test/unit/outboundApi/data/requestToPayTransferRequest.json +0 -20
  118. package/test/unit/outboundApi/data/transferRequest.json +0 -21
  119. package/test/unit/outboundApi/handlers.test.js +0 -887
@@ -1,889 +0,0 @@
1
- /**************************************************************************
2
- * (C) Copyright ModusBox Inc. 2019 - All rights reserved. *
3
- * *
4
- * This file is made available under the terms of the license agreement *
5
- * specified in the corresponding source code repository. *
6
- * *
7
- * ORIGINAL AUTHOR: *
8
- * Vassilis Barzokas - vassilis.barzokas@modusbox.com *
9
- **************************************************************************/
10
- 'use strict';
11
-
12
- // we use a mock standard components lib to intercept and mock certain funcs
13
- jest.mock('@mojaloop/sdk-standard-components');
14
- jest.mock('redis');
15
- jest.mock('~/lib/model/lib/requests',() => require('./mockedLibRequests'));
16
-
17
- const defaultConfig = require('./data/defaultConfig');
18
- const Model = require('~/lib/model').InboundTransfersModel;
19
- const mockArguments = require('./data/mockArguments');
20
- const mockTxnReqquestsArguments = require('./data/mockTxnRequestsArguments');
21
- const { MojaloopRequests, Ilp, Logger } = require('@mojaloop/sdk-standard-components');
22
- const { BackendRequests, HTTPResponseError } = require('~/lib/model/lib/requests');
23
- const Cache = require('~/lib/cache');
24
- const shared = require('~/lib/model/lib/shared');
25
-
26
- const getTransfersBackendResponse = require('./data/getTransfersBackendResponse');
27
- const getTransfersMojaloopResponse = require('./data/getTransfersMojaloopResponse');
28
- const getBulkTransfersBackendResponse = require('./data/getBulkTransfersBackendResponse');
29
- const getBulkTransfersMojaloopResponse = require('./data/getBulkTransfersMojaloopResponse');
30
- const notificationToPayee = require('./data/notificationToPayee');
31
- const notificationAbortedToPayee = require('./data/notificationAbortedToPayee');
32
- const notificationReservedToPayee = require('./data/notificationReservedToPayee');
33
-
34
- const { SDKStateEnum } = require('../../../../src/lib/model/common');
35
- const FSPIOPTransferStateEnum = require('@mojaloop/central-services-shared').Enum.Transfers.TransferState;
36
- const FSPIOPBulkTransferStateEnum = require('@mojaloop/central-services-shared').Enum.Transfers.BulkTransferState;
37
-
38
- describe('inboundModel', () => {
39
- let config;
40
- let mockArgs;
41
- let mockTxnReqArgs;
42
- let logger;
43
-
44
- beforeAll(async () => {
45
- logger = new Logger.Logger({ context: { app: 'inbound-model-unit-tests' }, stringify: () => '' });
46
- });
47
-
48
- beforeEach(async () => {
49
- config = JSON.parse(JSON.stringify(defaultConfig));
50
-
51
- mockArgs = JSON.parse(JSON.stringify(mockArguments));
52
- mockArgs.internalQuoteResponse.expiration = new Date(Date.now());
53
- mockTxnReqArgs = JSON.parse(JSON.stringify(mockTxnReqquestsArguments));
54
- });
55
-
56
- describe('quoteRequest', () => {
57
- let expectedQuoteResponseILP;
58
- let model;
59
- let cache;
60
-
61
- beforeEach(async () => {
62
- expectedQuoteResponseILP = Ilp.__response;
63
- BackendRequests.__postQuoteRequests = jest.fn().mockReturnValue(Promise.resolve(mockArgs.internalQuoteResponse));
64
- MojaloopRequests.__putQuotes = jest.fn().mockReturnValue(Promise.resolve({
65
- originalRequest: {
66
- headers: {},
67
- body: {},
68
- }
69
- }));
70
-
71
- cache = new Cache({
72
- cacheUrl: 'redis://dummy:1234',
73
- logger,
74
- });
75
- await cache.connect();
76
-
77
- model = new Model({
78
- ...config,
79
- cache,
80
- logger,
81
- });
82
- });
83
-
84
- afterEach(async () => {
85
- MojaloopRequests.__putQuotes.mockClear();
86
- await cache.disconnect();
87
- });
88
-
89
- test('calls `mojaloopRequests.putQuotes` with the expected arguments.', async () => {
90
- await model.quoteRequest(mockArgs.quoteRequest, mockArgs.fspId);
91
-
92
- expect(BackendRequests.__postQuoteRequests).toHaveBeenCalledTimes(1);
93
- expect(BackendRequests.__postQuoteRequests.mock.calls[0][0]).toEqual(mockArgs.internalQuoteRequest);
94
-
95
- expect(MojaloopRequests.__putQuotes).toHaveBeenCalledTimes(1);
96
- expect(MojaloopRequests.__putQuotes.mock.calls[0][1].expiration).toBe(mockArgs.internalQuoteResponse.expiration);
97
- expect(MojaloopRequests.__putQuotes.mock.calls[0][1].ilpPacket).toBe(expectedQuoteResponseILP.ilpPacket);
98
- expect(MojaloopRequests.__putQuotes.mock.calls[0][1].condition).toBe(expectedQuoteResponseILP.condition);
99
- expect(MojaloopRequests.__putQuotes.mock.calls[0][2]).toBe(mockArgs.fspId);
100
-
101
- // check the extension list gets translated correctly to the mojaloop form
102
- expect(MojaloopRequests.__putQuotes.mock.calls[0][1].extensionList)
103
- .toStrictEqual(mockArgs.internalQuoteResponse.extensionList);
104
- });
105
-
106
- test('adds a custom `expiration` property in case it is not defined.', async() => {
107
- // set a custom mock time in the global Date object in order to avoid race conditions.
108
- // Make sure to clear it at the end of the test case.
109
- const currentTime = new Date().getTime();
110
- const dateSpy = jest.spyOn(Date.prototype, 'getTime').mockImplementation(() => currentTime);
111
- const expectedExpirationDate = new Date(currentTime + (config.expirySeconds * 1000)).toISOString();
112
-
113
- delete mockArgs.internalQuoteResponse.expiration;
114
-
115
- await model.quoteRequest(mockArgs.quoteRequest, mockArgs.fspId);
116
-
117
- expect(MojaloopRequests.__putQuotes).toHaveBeenCalledTimes(1);
118
- expect(MojaloopRequests.__putQuotes.mock.calls[0][1].expiration).toBe(expectedExpirationDate);
119
- expect(MojaloopRequests.__putQuotes.mock.calls[0][1].ilpPacket).toBe(expectedQuoteResponseILP.ilpPacket);
120
- expect(MojaloopRequests.__putQuotes.mock.calls[0][1].condition).toBe(expectedQuoteResponseILP.condition);
121
- expect(MojaloopRequests.__putQuotes.mock.calls[0][2]).toBe(mockArgs.fspId);
122
-
123
- dateSpy.mockClear();
124
- });
125
-
126
-
127
- });
128
-
129
- describe('bulkQuoteRequest', () => {
130
- let expectedQuoteResponseILP;
131
- let model;
132
- let cache;
133
-
134
- beforeEach(async () => {
135
- // eslint-disable-next-line no-unused-vars
136
- expectedQuoteResponseILP = Ilp.__response;
137
- BackendRequests.__postBulkQuotes = jest.fn().mockReturnValue(Promise.resolve(mockArgs.internalBulkQuoteResponse));
138
-
139
- cache = new Cache({
140
- cacheUrl: 'redis://dummy:1234',
141
- logger,
142
- });
143
- await cache.connect();
144
- // eslint-disable-next-line no-unused-vars
145
- model = new Model({
146
- ...config,
147
- cache,
148
- logger,
149
- });
150
- });
151
-
152
- afterEach(async () => {
153
- MojaloopRequests.__putBulkQuotes.mockClear();
154
- await cache.disconnect();
155
- });
156
-
157
- test('calls mojaloopRequests.putBulkQuotes with the expected arguments.', async () => {
158
- await model.bulkQuoteRequest(mockArgs.bulkQuoteRequest, mockArgs.fspId);
159
-
160
- expect(MojaloopRequests.__putBulkQuotes).toHaveBeenCalledTimes(1);
161
- expect(MojaloopRequests.__putBulkQuotes.mock.calls[0][1].expiration).toBe(mockArgs.internalBulkQuoteResponse.expiration);
162
- expect(MojaloopRequests.__putBulkQuotes.mock.calls[0][1].individualQuoteResults[0].ilpPacket).toBe(expectedQuoteResponseILP.ilpPacket);
163
- expect(MojaloopRequests.__putBulkQuotes.mock.calls[0][1].individualQuoteResults[0].condition).toBe(expectedQuoteResponseILP.condition);
164
- expect(MojaloopRequests.__putBulkQuotes.mock.calls[0][2]).toBe(mockArgs.fspId);
165
- });
166
- test('adds a custom expiration property in case it is not defined.', async() => {
167
- // set a custom mock time in the global Date object in order to avoid race conditions.
168
- // Make sure to clear it at the end of the test case.
169
- const currentTime = new Date().getTime();
170
- const dateSpy = jest.spyOn(Date.prototype, 'getTime').mockImplementation(() => currentTime);
171
- const expectedExpirationDate = new Date(currentTime + (config.expirySeconds * 1000)).toISOString();
172
-
173
- delete mockArgs.internalBulkQuoteResponse.expiration;
174
-
175
- await model.bulkQuoteRequest(mockArgs.bulkQuoteRequest, mockArgs.fspId);
176
-
177
- expect(MojaloopRequests.__putBulkQuotes).toHaveBeenCalledTimes(1);
178
- expect(MojaloopRequests.__putBulkQuotes.mock.calls[0][1].expiration).toBe(expectedExpirationDate);
179
- expect(MojaloopRequests.__putBulkQuotes.mock.calls[0][1].individualQuoteResults[0].ilpPacket).toBe(expectedQuoteResponseILP.ilpPacket);
180
- expect(MojaloopRequests.__putBulkQuotes.mock.calls[0][1].individualQuoteResults[0].condition).toBe(expectedQuoteResponseILP.condition);
181
- expect(MojaloopRequests.__putBulkQuotes.mock.calls[0][2]).toBe(mockArgs.fspId);
182
-
183
- dateSpy.mockClear();
184
- });
185
-
186
- });
187
-
188
- describe('transactionRequest', () => {
189
- let model;
190
- let cache;
191
-
192
- beforeEach(async () => {
193
- BackendRequests.__postTransactionRequests = jest.fn().mockReturnValue(Promise.resolve(mockTxnReqArgs.internalTransactionRequestResponse));
194
-
195
- cache = new Cache({
196
- cacheUrl: 'redis://dummy:1234',
197
- logger,
198
- });
199
- await cache.connect();
200
-
201
- model = new Model({
202
- ...config,
203
- cache,
204
- logger,
205
- });
206
- });
207
-
208
- afterEach(async () => {
209
- MojaloopRequests.__putTransactionRequests.mockClear();
210
- await cache.disconnect();
211
- });
212
-
213
- test('calls `mojaloopRequests.putTransactionRequests` with the expected arguments.', async () => {
214
- await model.transactionRequest(mockTxnReqArgs.transactionRequest, mockTxnReqArgs.fspId);
215
-
216
- expect(MojaloopRequests.__putTransactionRequests).toHaveBeenCalledTimes(1);
217
- expect(MojaloopRequests.__putTransactionRequests.mock.calls[0][1].transactionRequestState).toBe(mockTxnReqArgs.internalTransactionRequestResponse.transactionRequestState);
218
-
219
- });
220
-
221
-
222
- });
223
-
224
- describe('authorizations', () => {
225
- let model;
226
- let cache;
227
-
228
- beforeEach(async () => {
229
- BackendRequests.__getOTP = jest.fn().mockReturnValue(Promise.resolve(mockArgs.internalGetOTPResponse));
230
-
231
- cache = new Cache({
232
- cacheUrl: 'redis://dummy:1234',
233
- logger,
234
- });
235
- await cache.connect();
236
-
237
- model = new Model({
238
- ...config,
239
- cache,
240
- logger,
241
- });
242
- });
243
-
244
- afterEach(async () => {
245
- MojaloopRequests.__putAuthorizations.mockClear();
246
- await cache.disconnect();
247
- });
248
-
249
- test('calls `mojaloopRequests.putAuthorizations` with the expected arguments.', async () => {
250
- await model.getAuthorizations('123456', mockTxnReqArgs.fspId);
251
-
252
- expect(MojaloopRequests.__putAuthorizations).toHaveBeenCalledTimes(1);
253
-
254
- });
255
-
256
-
257
- });
258
-
259
- describe('transferPrepare:', () => {
260
- let cache;
261
-
262
- beforeEach(async () => {
263
- MojaloopRequests.__putTransfersError.mockClear();
264
- BackendRequests.__postTransfers = jest.fn().mockReturnValue(Promise.resolve({}));
265
- MojaloopRequests.__putTransfers = jest.fn().mockReturnValue(Promise.resolve({
266
- originalRequest: {
267
- headers: {},
268
- body: {},
269
- }
270
- }));
271
-
272
- cache = new Cache({
273
- cacheUrl: 'redis://dummy:1234',
274
- logger,
275
- });
276
- await cache.connect();
277
- });
278
-
279
- afterEach(async () => {
280
- await cache.disconnect();
281
- });
282
-
283
- test('fail on quote `expiration` deadline.', async () => {
284
- const TRANSFER_ID = 'fake-transfer-id';
285
- const model = new Model({
286
- ...config,
287
- cache,
288
- logger,
289
- rejectTransfersOnExpiredQuotes: true,
290
- });
291
- cache.set(`transferModel_in_${TRANSFER_ID}`, {
292
- quote: {
293
- mojaloopResponse: {
294
- expiration: new Date(new Date().getTime() - 1000).toISOString(),
295
- }
296
- }
297
- });
298
- const args = {
299
- body: {
300
- transferId: TRANSFER_ID,
301
- }
302
- };
303
-
304
- await model.prepareTransfer(args, mockArgs.fspId);
305
-
306
- expect(MojaloopRequests.__putTransfersError).toHaveBeenCalledTimes(1);
307
- const call = MojaloopRequests.__putTransfersError.mock.calls[0];
308
- expect(call[0]).toEqual(TRANSFER_ID);
309
- expect(call[1].errorInformation.errorCode).toEqual('3302');
310
- });
311
-
312
- test('getTransfer should return COMMITTED transfer', async () => {
313
- const TRANSFER_ID = 'fake-transfer-id';
314
-
315
- const backendResponse = JSON.parse(JSON.stringify(getTransfersBackendResponse));
316
- backendResponse.to.fspId = config.dfspId;
317
- BackendRequests.__getTransfers = jest.fn().mockReturnValue(Promise.resolve(backendResponse));
318
-
319
- const model = new Model({
320
- ...config,
321
- cache,
322
- logger,
323
- });
324
-
325
- await model.getTransfer(TRANSFER_ID, mockArgs.fspId);
326
-
327
- expect(MojaloopRequests.__putTransfers).toHaveBeenCalledTimes(1);
328
- const call = MojaloopRequests.__putTransfers.mock.calls[0];
329
- expect(call[0]).toEqual(TRANSFER_ID);
330
- expect(call[1]).toEqual(getTransfersMojaloopResponse);
331
- expect(call[1].transferState).toEqual(FSPIOPTransferStateEnum.COMMITTED);
332
- });
333
-
334
- test('getTransfer should not return fulfillment from payer', async () => {
335
- const TRANSFER_ID = 'fake-transfer-id';
336
-
337
- const backendResponse = JSON.parse(JSON.stringify(getTransfersBackendResponse));
338
- backendResponse.to.fspId = 'payer-dfsp';
339
- BackendRequests.__getTransfers = jest.fn().mockReturnValue(Promise.resolve(backendResponse));
340
-
341
- const model = new Model({
342
- ...config,
343
- cache,
344
- logger,
345
- });
346
-
347
- await model.getTransfer(TRANSFER_ID, mockArgs.fspId);
348
-
349
- const call = MojaloopRequests.__putTransfers.mock.calls[0];
350
- expect(call[0]).toEqual(TRANSFER_ID);
351
- expect(call[1]).toEqual({...getTransfersMojaloopResponse, fulfilment: undefined});
352
- expect(call[1].transferState).toEqual(FSPIOPTransferStateEnum.COMMITTED);
353
- });
354
-
355
- test('getTransfer should return not found error', async () => {
356
- const TRANSFER_ID = 'fake-transfer-id';
357
-
358
- BackendRequests.__getTransfers = jest.fn().mockReturnValue(
359
- Promise.reject(new HTTPResponseError({
360
- res: {
361
- data: {
362
- statusCode: '3208'
363
- },
364
- }
365
- })));
366
-
367
- const model = new Model({
368
- ...config,
369
- cache,
370
- logger,
371
- });
372
-
373
- await model.getTransfer(TRANSFER_ID, mockArgs.fspId);
374
-
375
- expect(MojaloopRequests.__putTransfersError).toHaveBeenCalledTimes(1);
376
- const call = MojaloopRequests.__putTransfersError.mock.calls[0];
377
- expect(call[0]).toEqual(`${TRANSFER_ID}`);
378
- expect(call[1].errorInformation.errorCode).toEqual('3208');
379
- });
380
-
381
- test('fail on transfer without quote.', async () => {
382
- const TRANSFER_ID = 'without_quote-transfer-id';
383
- const args = {
384
- body: {
385
- transferId: TRANSFER_ID,
386
- amount: {
387
- currency: 'USD',
388
- amount: 20.13
389
- },
390
- ilpPacket: 'mockBase64encodedIlpPacket',
391
- condition: 'mockGeneratedCondition'
392
- }
393
- };
394
-
395
- const model = new Model({
396
- ...config,
397
- cache,
398
- logger,
399
- allowTransferWithoutQuote: false,
400
- });
401
-
402
- await model.prepareTransfer(args, mockArgs.fspId);
403
-
404
- expect(MojaloopRequests.__putTransfersError).toHaveBeenCalledTimes(1);
405
- const call = MojaloopRequests.__putTransfersError.mock.calls[0];
406
- expect(call[0]).toEqual(TRANSFER_ID);
407
- expect(call[1].errorInformation.errorCode).toEqual('2001');
408
- });
409
-
410
- test('stores homeTransactionId in cache when received by dfsp acting as payee', async () => {
411
- const TRANSFER_ID = 'transfer-id';
412
- const HOME_TRANSACTION_ID = 'mockHomeTransactionId';
413
- shared.mojaloopPrepareToInternalTransfer = jest.fn().mockReturnValueOnce({});
414
-
415
- // mock response from dfsp acting as payee
416
- BackendRequests.__postTransfers = jest.fn().mockReturnValueOnce(Promise.resolve({
417
- homeTransactionId: HOME_TRANSACTION_ID,
418
- transferId: TRANSFER_ID
419
- }));
420
-
421
- const args = {
422
- body: {
423
- transferId: TRANSFER_ID,
424
- amount: {
425
- currency: 'USD',
426
- amount: 20.13
427
- },
428
- ilpPacket: 'mockBase64encodedIlpPacket',
429
- condition: 'mockGeneratedCondition'
430
- }
431
- };
432
-
433
- const model = new Model({
434
- ...config,
435
- cache,
436
- logger,
437
- checkIlp: false,
438
- rejectTransfersOnExpiredQuotes: false
439
- });
440
-
441
- cache.set(`transferModel_in_${TRANSFER_ID}`, {
442
- transferId: TRANSFER_ID,
443
- quote: {
444
- fulfilment: 'mockFulfilment',
445
- mojaloopResponse: {
446
- condition: 'mockCondition',
447
- }
448
- }
449
- });
450
-
451
- await model.prepareTransfer(args, mockArgs.fspId);
452
-
453
- expect(MojaloopRequests.__putTransfersError).toHaveBeenCalledTimes(0);
454
- expect(BackendRequests.__postTransfers).toHaveBeenCalledTimes(1);
455
- expect(MojaloopRequests.__putTransfers).toHaveBeenCalledTimes(1);
456
- expect((await cache.get(`transferModel_in_${TRANSFER_ID}`)).homeTransactionId)
457
- .toEqual(HOME_TRANSACTION_ID);
458
- });
459
-
460
- test('pass on transfer without quote.', async () => {
461
- const TRANSFER_ID = 'without_quote-transfer-id';
462
- cache.set(`transferModel_in_${TRANSFER_ID}`, {
463
- fulfilment: '',
464
- mojaloopResponse: {
465
- response: ''
466
- },
467
- quote: null
468
- });
469
-
470
- const args = {
471
- body: {
472
- transferId: TRANSFER_ID,
473
- amount: {
474
- currency: 'USD',
475
- amount: 20.13
476
- },
477
- ilpPacket: 'mockBase64encodedIlpPacket',
478
- condition: 'mockGeneratedCondition'
479
- }
480
- };
481
-
482
- const model = new Model({
483
- ...config,
484
- cache,
485
- logger,
486
- allowTransferWithoutQuote: true,
487
- });
488
-
489
- await model.prepareTransfer(args, mockArgs.fspId);
490
-
491
- expect(MojaloopRequests.__putTransfersError).toHaveBeenCalledTimes(0);
492
- expect(BackendRequests.__postTransfers).toHaveBeenCalledTimes(1);
493
- expect(MojaloopRequests.__putTransfers).toHaveBeenCalledTimes(1);
494
- });
495
-
496
- test('allow different transfer and transaction id', async () => {
497
- const transactionId = 'mockTransactionId';
498
- const TRANSFER_ID = 'transfer-id';
499
- shared.mojaloopPrepareToInternalTransfer = jest.fn().mockReturnValueOnce({});
500
-
501
- cache.set(`transferModel_in_${transactionId}`, {
502
- fulfilment: '',
503
- mojaloopResponse: {
504
- response: ''
505
- },
506
- quote: {
507
- fulfilment: 'mockFulfilment',
508
- mojaloopResponse: {
509
- condition: 'mockCondition',
510
- }
511
- }
512
- });
513
-
514
- const args = {
515
- body: {
516
- transferId: TRANSFER_ID,
517
- amount: {
518
- currency: 'USD',
519
- amount: 20.13
520
- },
521
- ilpPacket: 'mockIlpPacket',
522
- condition: 'mockGeneratedCondition'
523
- }
524
- };
525
-
526
- const model = new Model({
527
- ...config,
528
- cache,
529
- logger,
530
- allowDifferentTransferTransactionId: true,
531
- checkIlp: false,
532
- });
533
-
534
- await model.prepareTransfer(args, mockArgs.fspId);
535
-
536
- expect(MojaloopRequests.__putTransfersError).toHaveBeenCalledTimes(0);
537
- expect(BackendRequests.__postTransfers).toHaveBeenCalledTimes(1);
538
- expect(MojaloopRequests.__putTransfers).toHaveBeenCalledTimes(1);
539
- });
540
- });
541
-
542
- describe('prepareBulkTransfer:', () => {
543
- let cache;
544
-
545
- beforeEach(async () => {
546
- MojaloopRequests.__putBulkTransfersError.mockClear();
547
- MojaloopRequests.__putBulkTransfers = jest.fn().mockReturnValue(Promise.resolve({}));
548
- BackendRequests.__postBulkTransfers = jest.fn().mockReturnValue(Promise.resolve({}));
549
-
550
- cache = new Cache({
551
- cacheUrl: 'redis://dummy:1234',
552
- logger,
553
- });
554
- await cache.connect();
555
- });
556
-
557
- afterEach(async () => {
558
- await cache.disconnect();
559
- });
560
-
561
- test('fail on bulk quote `expiration` deadline.', async () => {
562
- const BULK_TRANSFER_ID = 'fake-bulk-transfer-id';
563
- const BULK_QUOTE_ID = 'fake-bulk-quote-id';
564
- const model = new Model({
565
- ...config,
566
- cache,
567
- logger,
568
- rejectTransfersOnExpiredQuotes: true,
569
- });
570
- cache.set(`bulkQuotes_${BULK_QUOTE_ID}`, {
571
- mojaloopResponse: {
572
- expiration: new Date(new Date().getTime() - 1000).toISOString(),
573
- individualQuoteResults: [],
574
- }
575
- });
576
- const args = {
577
- bulkTransferId: BULK_TRANSFER_ID,
578
- bulkQuoteId: BULK_QUOTE_ID,
579
- individualTransfers: [],
580
- };
581
-
582
- await model.prepareBulkTransfer(args, mockArgs.fspId);
583
-
584
- expect(MojaloopRequests.__putBulkTransfersError).toHaveBeenCalledTimes(1);
585
- const call = MojaloopRequests.__putBulkTransfersError.mock.calls[0];
586
- expect(call[0]).toEqual(BULK_TRANSFER_ID);
587
- expect(call[1].errorInformation.errorCode).toEqual('3302');
588
- });
589
-
590
- test('getBulkTransfer should return COMMITTED bulk transfer', async () => {
591
- const BULK_TRANSFER_ID = 'fake-bulk-transfer-id';
592
-
593
- const backendResponse = JSON.parse(JSON.stringify(getBulkTransfersBackendResponse));
594
- BackendRequests.__getBulkTransfers = jest.fn().mockReturnValue(Promise.resolve(backendResponse));
595
-
596
- const model = new Model({
597
- ...config,
598
- cache,
599
- logger,
600
- });
601
-
602
- await model.getBulkTransfer(BULK_TRANSFER_ID, mockArgs.fspId);
603
-
604
- expect(MojaloopRequests.__putBulkTransfers).toHaveBeenCalledTimes(1);
605
- const call = MojaloopRequests.__putBulkTransfers.mock.calls[0];
606
- expect(call[0]).toEqual(BULK_TRANSFER_ID);
607
- expect(call[1]).toEqual(getBulkTransfersMojaloopResponse);
608
- expect(call[1].bulkTransferState).toEqual(FSPIOPBulkTransferStateEnum.COMPLETED);
609
- });
610
-
611
- test('getBulkTransfer should not return fulfillment from payer', async () => {
612
- const BULK_TRANSFER_ID = 'fake-bulk-transfer-id';
613
-
614
- const backendResponse = JSON.parse(JSON.stringify(getBulkTransfersBackendResponse));
615
- backendResponse.internalRequest.individualTransfers[0].to.fspId = 'payer-dfsp';
616
- BackendRequests.__getBulkTransfers = jest.fn().mockReturnValue(Promise.resolve(backendResponse));
617
-
618
- const model = new Model({
619
- ...config,
620
- cache,
621
- logger,
622
- });
623
-
624
- await model.getBulkTransfer(BULK_TRANSFER_ID, mockArgs.fspId);
625
-
626
- const call = MojaloopRequests.__putBulkTransfers.mock.calls[0];
627
- expect(call[0]).toEqual(BULK_TRANSFER_ID);
628
- expect(call[1].bulkTransferState).toEqual(FSPIOPBulkTransferStateEnum.COMPLETED);
629
- const expectedResponse = {...getBulkTransfersMojaloopResponse};
630
- expectedResponse.individualTransferResults[0].fulfilment = undefined;
631
- expect(call[1]).toMatchObject(expectedResponse);
632
- });
633
-
634
- test('getBulkTransfer should return not found error', async () => {
635
- const BULK_TRANSFER_ID = 'fake-bulk-transfer-id';
636
-
637
- BackendRequests.__getBulkTransfers = jest.fn().mockReturnValue(
638
- Promise.reject(new HTTPResponseError({
639
- res: {
640
- data: {
641
- statusCode: '3208'
642
- },
643
- }
644
- })));
645
-
646
- const model = new Model({
647
- ...config,
648
- cache,
649
- logger,
650
- });
651
-
652
- await model.getBulkTransfer(BULK_TRANSFER_ID, mockArgs.fspId);
653
-
654
- expect(MojaloopRequests.__putBulkTransfersError).toHaveBeenCalledTimes(1);
655
- const call = MojaloopRequests.__putBulkTransfersError.mock.calls[0];
656
- expect(call[0]).toEqual(`${BULK_TRANSFER_ID}`);
657
- expect(call[1].errorInformation.errorCode).toEqual('3208');
658
- });
659
-
660
- test('fail on bulk transfer without bulk quote.', async () => {
661
- const BULK_TRANSFER_ID = 'without_bulk-quote-bulk-transfer-id';
662
- const args = {
663
- bulkTransferId: BULK_TRANSFER_ID,
664
- ilpPacket: 'mockBase64encodedIlpPacket',
665
- condition: 'mockGeneratedCondition',
666
- individualTransfers: [
667
- {
668
- amount: {
669
- currency: 'USD',
670
- amount: 20.13
671
- },
672
- }
673
- ]
674
- };
675
-
676
- const model = new Model({
677
- ...config,
678
- cache,
679
- logger,
680
- allowTransferWithoutQuote: false,
681
- });
682
-
683
- await model.prepareBulkTransfer(args, mockArgs.fspId);
684
-
685
- expect(MojaloopRequests.__putBulkTransfersError).toHaveBeenCalledTimes(1);
686
- const call = MojaloopRequests.__putBulkTransfersError.mock.calls[0];
687
- expect(call[0]).toEqual(BULK_TRANSFER_ID);
688
- expect(call[1].errorInformation.errorCode).toEqual('2001');
689
- });
690
-
691
- test('pass on bulk transfer without bulk quote.', async () => {
692
- const BULK_TRANSFER_ID = 'without_bulk-quote-bulk-transfer-id';
693
- const args = {
694
- bulkTransferId: BULK_TRANSFER_ID,
695
- individualTransfers: [
696
- {
697
- transferId: 'fake-transfer-id',
698
- transferAmount: {
699
- currency: 'USD',
700
- amount: 20.13
701
- },
702
- ilpPacket: 'mockBase64encodedIlpPacket',
703
- condition: 'mockGeneratedCondition',
704
- }
705
- ]
706
- };
707
-
708
- const model = new Model({
709
- ...config,
710
- cache,
711
- logger,
712
- allowTransferWithoutQuote: true,
713
- rejectTransfersOnExpiredQuotes: false,
714
- });
715
-
716
- await model.prepareBulkTransfer(args, mockArgs.fspId);
717
-
718
- expect(MojaloopRequests.__putBulkTransfersError).toHaveBeenCalledTimes(0);
719
- expect(BackendRequests.__postBulkTransfers).toHaveBeenCalledTimes(1);
720
- expect(MojaloopRequests.__putBulkTransfers).toHaveBeenCalledTimes(1);
721
- });
722
- });
723
-
724
- describe('sendNotificationToPayee:', () => {
725
- const transferId = '1234';
726
- let cache;
727
-
728
- beforeEach(async () => {
729
- cache = new Cache({
730
- cacheUrl: 'redis://dummy:1234',
731
- logger,
732
- });
733
- await cache.connect();
734
- });
735
-
736
- afterEach(async () => {
737
- await cache.disconnect();
738
- });
739
-
740
- test('sends notification to fsp backend', async () => {
741
- BackendRequests.__putTransfersNotification = jest.fn().mockReturnValue(Promise.resolve({}));
742
- const notif = JSON.parse(JSON.stringify(notificationToPayee));
743
-
744
- const expectedRequest = {
745
- currentState: SDKStateEnum.COMPLETED,
746
- finalNotification: notif.data,
747
- };
748
-
749
- const model = new Model({
750
- ...config,
751
- cache,
752
- logger,
753
- });
754
-
755
- await model.sendNotificationToPayee(notif.data, transferId);
756
- expect(BackendRequests.__putTransfersNotification).toHaveBeenCalledTimes(1);
757
- const call = BackendRequests.__putTransfersNotification.mock.calls[0];
758
- expect(call[0]).toEqual(expectedRequest);
759
- expect(call[1]).toEqual(transferId);
760
- });
761
-
762
- test('sends ABORTED notification to fsp backend', async () => {
763
- BackendRequests.__putTransfersNotification = jest.fn().mockReturnValue(Promise.resolve({}));
764
- const notif = JSON.parse(JSON.stringify(notificationAbortedToPayee));
765
-
766
- const expectedRequest = {
767
- currentState: SDKStateEnum.ABORTED,
768
- finalNotification: notif.data,
769
- };
770
-
771
- const model = new Model({
772
- ...config,
773
- cache,
774
- logger,
775
- });
776
-
777
- await model.sendNotificationToPayee(notif.data, transferId);
778
- expect(BackendRequests.__putTransfersNotification).toHaveBeenCalledTimes(1);
779
- const call = BackendRequests.__putTransfersNotification.mock.calls[0];
780
- expect(call[0]).toEqual(expectedRequest);
781
- expect(call[1]).toEqual(transferId);
782
- });
783
-
784
- test('sends RESERVED notification to fsp backend', async () => {
785
- BackendRequests.__putTransfersNotification = jest.fn().mockReturnValue(Promise.resolve({}));
786
- const notif = JSON.parse(JSON.stringify(notificationReservedToPayee));
787
-
788
- const expectedRequest = {
789
- finalNotification: notif.data,
790
- lastError: 'Final notification state not COMMITTED',
791
- };
792
-
793
- const model = new Model({
794
- ...config,
795
- cache,
796
- logger,
797
- });
798
-
799
- await model.sendNotificationToPayee(notif.data, transferId);
800
- expect(BackendRequests.__putTransfersNotification).toHaveBeenCalledTimes(1);
801
- const call = BackendRequests.__putTransfersNotification.mock.calls[0];
802
- expect(call[0]).toEqual(expectedRequest);
803
- expect(call[1]).toEqual(transferId);
804
- });
805
-
806
- });
807
-
808
- describe('error handling:', () => {
809
- let cache;
810
- beforeEach(async () => {
811
- cache = new Cache({
812
- cacheUrl: 'redis://dummy:1234',
813
- logger,
814
- });
815
- await cache.connect();
816
- });
817
- afterEach(async () => {
818
- await cache.disconnect();
819
- });
820
- test('creates mojaloop spec error body when backend returns standard error code', async () => {
821
- const model = new Model({
822
- ...config,
823
- cache,
824
- logger,
825
- });
826
- const testErr = new HTTPResponseError({
827
- msg: 'Request returned non-success status code 500',
828
- res: {
829
- data: {
830
- statusCode: '3200',
831
- },
832
- }
833
- });
834
- const err = await model._handleError(testErr);
835
- expect(err).toBeDefined();
836
- expect(err.errorInformation).toBeDefined();
837
- expect(err.errorInformation.errorCode).toEqual('3200');
838
- // error message should be the default one, not custom.
839
- // it is debatibale whether this is truly correct, to overwrite
840
- // and custom error message; but it is the case for now.
841
- expect(err.errorInformation.errorDescription).toEqual('Generic ID not found');
842
- });
843
- test('creates custom error body when backend returns custom error code', async () => {
844
- const model = new Model({
845
- ...config,
846
- cache,
847
- logger,
848
- });
849
- const customMessage = 'some custom message';
850
- const testErr = new HTTPResponseError({
851
- msg: 'Request returned non-success status code 500',
852
- res: {
853
- data: {
854
- statusCode: '3299',
855
- message: customMessage,
856
- },
857
- }
858
- });
859
- const err = await model._handleError(testErr);
860
- expect(err).toBeDefined();
861
- expect(err.errorInformation).toBeDefined();
862
- expect(err.errorInformation.errorCode).toEqual('3299');
863
- expect(err.errorInformation.errorDescription).toEqual(customMessage);
864
- });
865
- test('creates custom error message when backend returns standard error code and message', async () => {
866
- const model = new Model({
867
- ...config,
868
- cache,
869
- logger,
870
- });
871
- const customMessage = 'some custom message';
872
- const testErr = new HTTPResponseError({
873
- msg: 'Request returned non-success status code 500',
874
- res: {
875
- data: {
876
- statusCode: '3200',
877
- message: customMessage,
878
- },
879
- }
880
- });
881
- const err = await model._handleError(testErr);
882
- expect(err).toBeDefined();
883
- expect(err.errorInformation).toBeDefined();
884
- expect(err.errorInformation.errorCode).toEqual('3200');
885
- // error message should be custom
886
- expect(err.errorInformation.errorDescription).toEqual(customMessage);
887
- });
888
- });
889
- });