@mojaloop/sdk-scheme-adapter 18.0.0 → 18.0.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 (116) hide show
  1. package/.dockerignore +18 -0
  2. package/.eslintignore +2 -0
  3. package/CHANGELOG.md +8 -0
  4. package/audit-resolve.json +5 -0
  5. package/package.json +2 -2
  6. package/test/__mocks__/@mojaloop/sdk-standard-components.js +0 -151
  7. package/test/__mocks__/javascript-state-machine.js +0 -21
  8. package/test/__mocks__/redis.js +0 -78
  9. package/test/__mocks__/uuidv4.js +0 -16
  10. package/test/config/integration.env +0 -146
  11. package/test/integration/lib/Outbound/data/quotesPostRequest.json +0 -52
  12. package/test/integration/lib/Outbound/data/transfersPostRequest.json +0 -24
  13. package/test/integration/lib/Outbound/parties.test.js +0 -31
  14. package/test/integration/lib/Outbound/quotes.test.js +0 -62
  15. package/test/integration/lib/Outbound/simpleTransfers.test.js +0 -70
  16. package/test/integration/lib/cache.test.js +0 -79
  17. package/test/integration/testEnv.js +0 -4
  18. package/test/unit/ControlClient.test.js +0 -69
  19. package/test/unit/ControlServer/events.js +0 -41
  20. package/test/unit/ControlServer/index.js +0 -227
  21. package/test/unit/ControlServer.test.js +0 -66
  22. package/test/unit/InboundServer.test.js +0 -443
  23. package/test/unit/TestServer.test.js +0 -392
  24. package/test/unit/api/accounts/accounts.test.js +0 -128
  25. package/test/unit/api/accounts/data/postAccountsBody.json +0 -7
  26. package/test/unit/api/accounts/data/postAccountsErrorMojaloopResponse.json +0 -33
  27. package/test/unit/api/accounts/data/postAccountsErrorTimeoutResponse.json +0 -19
  28. package/test/unit/api/accounts/data/postAccountsSuccessResponse.json +0 -31
  29. package/test/unit/api/accounts/data/postAccountsSuccessResponseWithError1.json +0 -34
  30. package/test/unit/api/accounts/data/postAccountsSuccessResponseWithError2.json +0 -39
  31. package/test/unit/api/accounts/utils.js +0 -79
  32. package/test/unit/api/proxy/data/proxyConfig.yaml +0 -82
  33. package/test/unit/api/proxy/data/requestBody.json +0 -22
  34. package/test/unit/api/proxy/data/requestHeaders.json +0 -5
  35. package/test/unit/api/proxy/data/requestQuery.json +0 -6
  36. package/test/unit/api/proxy/data/responseBody.json +0 -21
  37. package/test/unit/api/proxy/data/responseHeaders.json +0 -5
  38. package/test/unit/api/proxy/proxy.test.js +0 -220
  39. package/test/unit/api/proxy/utils.js +0 -79
  40. package/test/unit/api/transfers/data/getTransfersCommittedResponse.json +0 -24
  41. package/test/unit/api/transfers/data/getTransfersErrorNotFound.json +0 -18
  42. package/test/unit/api/transfers/data/postQuotesBody.json +0 -52
  43. package/test/unit/api/transfers/data/postTransfersBadBody.json +0 -17
  44. package/test/unit/api/transfers/data/postTransfersBody.json +0 -24
  45. package/test/unit/api/transfers/data/postTransfersErrorMojaloopResponse.json +0 -62
  46. package/test/unit/api/transfers/data/postTransfersErrorTimeoutResponse.json +0 -48
  47. package/test/unit/api/transfers/data/postTransfersSimpleBody.json +0 -26
  48. package/test/unit/api/transfers/data/postTransfersSuccessResponse.json +0 -128
  49. package/test/unit/api/transfers/data/putPartiesBody.json +0 -20
  50. package/test/unit/api/transfers/data/putQuotesBody.json +0 -37
  51. package/test/unit/api/transfers/data/putTransfersBody.json +0 -17
  52. package/test/unit/api/transfers/transfers.test.js +0 -191
  53. package/test/unit/api/transfers/utils.js +0 -264
  54. package/test/unit/api/utils.js +0 -86
  55. package/test/unit/config.test.js +0 -119
  56. package/test/unit/data/commonHttpHeaders.json +0 -7
  57. package/test/unit/data/defaultConfig.json +0 -70
  58. package/test/unit/data/postQuotesBody.json +0 -52
  59. package/test/unit/data/putParticipantsBody.json +0 -12
  60. package/test/unit/data/putPartiesBody.json +0 -20
  61. package/test/unit/data/testFile.json +0 -29
  62. package/test/unit/data/testFile.yaml +0 -14
  63. package/test/unit/inboundApi/data/mockArguments.json +0 -117
  64. package/test/unit/inboundApi/data/mockTransactionRequest.json +0 -42
  65. package/test/unit/inboundApi/handlers.test.js +0 -786
  66. package/test/unit/index.test.js +0 -88
  67. package/test/unit/lib/cache.test.js +0 -145
  68. package/test/unit/lib/model/AccountsModel.test.js +0 -124
  69. package/test/unit/lib/model/InboundTransfersModel.test.js +0 -889
  70. package/test/unit/lib/model/OutboundBulkQuotesModel.test.js +0 -253
  71. package/test/unit/lib/model/OutboundBulkTransfersModel.test.js +0 -247
  72. package/test/unit/lib/model/OutboundRequestToPayModel.test.js +0 -166
  73. package/test/unit/lib/model/OutboundRequestToPayTransferModel.test.js +0 -245
  74. package/test/unit/lib/model/OutboundTransfersModel.test.js +0 -1579
  75. package/test/unit/lib/model/PartiesModel.test.js +0 -478
  76. package/test/unit/lib/model/QuotesModel.test.js +0 -477
  77. package/test/unit/lib/model/TransfersModel.test.js +0 -481
  78. package/test/unit/lib/model/common/PersistentStateMachine.test.js +0 -178
  79. package/test/unit/lib/model/data/authorizationsResponse.json +0 -13
  80. package/test/unit/lib/model/data/bulkQuoteRequest.json +0 -27
  81. package/test/unit/lib/model/data/bulkQuoteResponse.json +0 -35
  82. package/test/unit/lib/model/data/bulkTransferFulfil.json +0 -13
  83. package/test/unit/lib/model/data/bulkTransferRequest.json +0 -29
  84. package/test/unit/lib/model/data/defaultConfig.json +0 -59
  85. package/test/unit/lib/model/data/getBulkTransfersBackendResponse.json +0 -42
  86. package/test/unit/lib/model/data/getBulkTransfersMojaloopResponse.json +0 -22
  87. package/test/unit/lib/model/data/getTransfersBackendResponse.json +0 -34
  88. package/test/unit/lib/model/data/getTransfersMojaloopResponse.json +0 -17
  89. package/test/unit/lib/model/data/mockArguments.json +0 -188
  90. package/test/unit/lib/model/data/mockTxnRequestsArguments.json +0 -63
  91. package/test/unit/lib/model/data/notificationAbortedToPayee.json +0 -10
  92. package/test/unit/lib/model/data/notificationReservedToPayee.json +0 -10
  93. package/test/unit/lib/model/data/notificationToPayee.json +0 -10
  94. package/test/unit/lib/model/data/payeeParty.json +0 -18
  95. package/test/unit/lib/model/data/putQuotesResponse.json +0 -33
  96. package/test/unit/lib/model/data/putTransfersResponse.json +0 -5
  97. package/test/unit/lib/model/data/quoteResponse.json +0 -42
  98. package/test/unit/lib/model/data/requestToPayRequest.json +0 -20
  99. package/test/unit/lib/model/data/requestToPayTransferRequest.json +0 -27
  100. package/test/unit/lib/model/data/transactionRequestResponse.json +0 -18
  101. package/test/unit/lib/model/data/transferFulfil.json +0 -10
  102. package/test/unit/lib/model/data/transferRequest.json +0 -26
  103. package/test/unit/lib/model/mockedLibRequests.js +0 -74
  104. package/test/unit/mockLogger.js +0 -39
  105. package/test/unit/outboundApi/data/bulkQuoteRequest.json +0 -28
  106. package/test/unit/outboundApi/data/bulkTransferRequest.json +0 -28
  107. package/test/unit/outboundApi/data/mockBulkQuoteError.json +0 -45
  108. package/test/unit/outboundApi/data/mockBulkTransferError.json +0 -48
  109. package/test/unit/outboundApi/data/mockError.json +0 -41
  110. package/test/unit/outboundApi/data/mockGetPartiesError.json +0 -4
  111. package/test/unit/outboundApi/data/mockRequestToPayError.json +0 -32
  112. package/test/unit/outboundApi/data/mockRequestToPayTransferError.json +0 -39
  113. package/test/unit/outboundApi/data/requestToPay.json +0 -21
  114. package/test/unit/outboundApi/data/requestToPayTransferRequest.json +0 -20
  115. package/test/unit/outboundApi/data/transferRequest.json +0 -21
  116. 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
- });