ti2 1.0.59 → 1.0.60
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.
- package/controllers/__tests__/allotments.js +38 -8
- package/index.js +18 -30
- package/lib/get-error-message.js +21 -0
- package/package.json +2 -1
- package/test/plugin.js +40 -2
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/* globals beforeAll describe it expect */
|
|
2
|
-
|
|
2
|
+
const axios = require('axios');
|
|
3
|
+
const MockAdapter = require('axios-mock-adapter');
|
|
3
4
|
const chance = require('chance').Chance();
|
|
5
|
+
|
|
6
|
+
|
|
4
7
|
const testUtils = require('../../test/utils');
|
|
5
8
|
|
|
6
9
|
const { env: { adminKey } } = process;
|
|
@@ -26,6 +29,7 @@ describe('allotment', () => {
|
|
|
26
29
|
let doApiGet;
|
|
27
30
|
let doApiPost;
|
|
28
31
|
let plugins;
|
|
32
|
+
let userToken;
|
|
29
33
|
beforeAll(async () => {
|
|
30
34
|
({
|
|
31
35
|
doApiDelete,
|
|
@@ -35,10 +39,8 @@ describe('allotment', () => {
|
|
|
35
39
|
} = await testUtils({
|
|
36
40
|
plugins: [appKey],
|
|
37
41
|
}));
|
|
38
|
-
});
|
|
39
42
|
|
|
40
|
-
|
|
41
|
-
it('drop any existing user integration', async () => {
|
|
43
|
+
// drop any existing user integrations
|
|
42
44
|
try {
|
|
43
45
|
await doApiDelete({
|
|
44
46
|
url: `/${appKey}/${userId}`,
|
|
@@ -48,16 +50,16 @@ describe('allotment', () => {
|
|
|
48
50
|
} catch (err) {
|
|
49
51
|
// console.debug(err);
|
|
50
52
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
|
|
54
|
+
// create the user
|
|
53
55
|
({ value: userToken } = await doApiPost({
|
|
54
56
|
url: '/user',
|
|
55
57
|
token: adminKey,
|
|
56
58
|
payload: { userId },
|
|
57
59
|
}));
|
|
58
60
|
expect(userToken).toBeTruthy();
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
|
|
62
|
+
// create the App+User setup
|
|
61
63
|
const { userAppKeys } = await doApiGet({
|
|
62
64
|
url: `/user/${userId}/apps`,
|
|
63
65
|
token: userToken,
|
|
@@ -103,4 +105,32 @@ describe('allotment', () => {
|
|
|
103
105
|
expect(call.payload).toEqual(payload);
|
|
104
106
|
expect(call.token).toEqual(token);
|
|
105
107
|
});
|
|
108
|
+
it('should be able to receive an axios error', async () => {
|
|
109
|
+
let urlParamsError = new URLSearchParams({
|
|
110
|
+
...payload,
|
|
111
|
+
keyPath: 'errorAxios',
|
|
112
|
+
}).toString();
|
|
113
|
+
const returnValue = await doApiGet({
|
|
114
|
+
url: `/allotment/${appKey}/${newIntegration.tokenHint}/${userId}?${urlParamsError}`,
|
|
115
|
+
token: userToken,
|
|
116
|
+
expectStatusCode: 500,
|
|
117
|
+
});
|
|
118
|
+
expect(returnValue.allotments).toBeFalsy();
|
|
119
|
+
expect(returnValue.message).toBe('ECONNREFUSED');
|
|
120
|
+
});
|
|
121
|
+
it('should be able to receive an error from a regular response', async () => {
|
|
122
|
+
const mock = new MockAdapter(axios);
|
|
123
|
+
mock.onGet('http://www.example.com').reply(200, { error: 'something went wrong' });
|
|
124
|
+
let urlParamsError = new URLSearchParams({
|
|
125
|
+
...payload,
|
|
126
|
+
keyPath: 'errorGeneral',
|
|
127
|
+
}).toString();
|
|
128
|
+
const returnValue = await doApiGet({
|
|
129
|
+
url: `/allotment/${appKey}/${newIntegration.tokenHint}/${userId}?${urlParamsError}`,
|
|
130
|
+
token: userToken,
|
|
131
|
+
expectStatusCode: 500,
|
|
132
|
+
});
|
|
133
|
+
expect(returnValue.allotments).toBeFalsy();
|
|
134
|
+
expect(returnValue.message).toBe('something went wrong');
|
|
135
|
+
});
|
|
106
136
|
});
|
package/index.js
CHANGED
|
@@ -40,6 +40,7 @@ const bookingsController = require('./controllers/bookings');
|
|
|
40
40
|
const allotmentController = require('./controllers/allotment');
|
|
41
41
|
const { Integration } = require('./models');
|
|
42
42
|
const cache = require('./cache');
|
|
43
|
+
const getErrorMessage = require('./lib/get-error-message.js');
|
|
43
44
|
|
|
44
45
|
// src : https://github.com/ramda/ramda/issues/3137#issuecomment-1016012904
|
|
45
46
|
const rebuild = fn => obj =>
|
|
@@ -217,36 +218,20 @@ module.exports = async ({
|
|
|
217
218
|
});
|
|
218
219
|
axiosPlugin.interceptors.response.use(response => {
|
|
219
220
|
ti2Events.emit(`${pluginName}.axios.response`, { ...axiosSafeResponse(response), userId });
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
if (
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
err: errMsg,
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
throw new Eror(errMsg);
|
|
221
|
+
const errMsg = getErrorMessage({ err: response, handlers: errorPathsAxiosAny, force: false });
|
|
222
|
+
if (errMsg) {
|
|
223
|
+
if (process.env.debug) console.error(`error in ${pluginName}`, errMsg);
|
|
224
|
+
if (ti2Events.events) {
|
|
225
|
+
ti2Events.events.emit(`${pluginName}.axios.error`, {
|
|
226
|
+
response: axiosSafeResponse(response),
|
|
227
|
+
err: errMsg,
|
|
228
|
+
});
|
|
232
229
|
}
|
|
230
|
+
throw new Error(errMsg);
|
|
233
231
|
}
|
|
234
232
|
return response;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
curlirize(axiosPlugin);
|
|
238
|
-
}
|
|
239
|
-
req.axios = async (...args) => axiosPlugin(...args).catch(err => {
|
|
240
|
-
const errMsg = (() => {
|
|
241
|
-
const defaultErr = R.omit(['config'], err.toJSON()); // default error
|
|
242
|
-
if (errorPathsAxiosErrors.length > 0) {
|
|
243
|
-
const pathMatch = errorPathsAxiosErrors.find(errorPath => R.path(errorPath, err));
|
|
244
|
-
if (pathMatch) {
|
|
245
|
-
return R.path(pathMatch, err);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
return defaultErr;
|
|
249
|
-
})();
|
|
233
|
+
}, err => {
|
|
234
|
+
const errMsg = getErrorMessage({ err, handlers: errorPathsAxiosErrors });
|
|
250
235
|
if (process.env.debug) console.error(`error in ${pluginName}`, args[0], errMsg);
|
|
251
236
|
if (ti2Events.events) {
|
|
252
237
|
ti2Events.events.emit(`${pluginName}.axios.error`, {
|
|
@@ -254,9 +239,12 @@ module.exports = async ({
|
|
|
254
239
|
err: errMsg,
|
|
255
240
|
});
|
|
256
241
|
}
|
|
257
|
-
|
|
242
|
+
return Promise.reject(errMsg);
|
|
258
243
|
});
|
|
259
|
-
|
|
244
|
+
if (process.env.debug) {
|
|
245
|
+
curlirize(axiosPlugin);
|
|
246
|
+
}
|
|
247
|
+
req.axios = axiosPlugin;
|
|
260
248
|
next();
|
|
261
249
|
});
|
|
262
250
|
|
|
@@ -309,7 +297,7 @@ module.exports = async ({
|
|
|
309
297
|
return next(err);
|
|
310
298
|
}
|
|
311
299
|
if (process.env.CONSOLE_ERRORS || process.env.JEST_WORKER_ID) {
|
|
312
|
-
console.error(R.
|
|
300
|
+
console.error(R.pathOr(err, ['response', 'data'], err));
|
|
313
301
|
}
|
|
314
302
|
return res.status((() => {
|
|
315
303
|
if (!isNumber(err.status)) return 500;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const R = require('ramda');
|
|
2
|
+
|
|
3
|
+
const getErrorMessage = ({ err, handlers = [], force = true }) => {
|
|
4
|
+
for (const handler of handlers) {
|
|
5
|
+
let errorMessage;
|
|
6
|
+
if (Array.isArray(handler)) {
|
|
7
|
+
errorMessage = R.path(handler, err);
|
|
8
|
+
} else if (typeof handler === 'function') {
|
|
9
|
+
errorMessage = handler(err);
|
|
10
|
+
}
|
|
11
|
+
if (errorMessage) {
|
|
12
|
+
return errorMessage;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
if (force) return R.pathOr(
|
|
16
|
+
err,
|
|
17
|
+
['message'],
|
|
18
|
+
err
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
module.exports = getErrorMessage;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ti2",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.60",
|
|
4
4
|
"description": "Tourist Industry Exchange (TI2)",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@salvador/minami": "^1.2.3",
|
|
55
|
+
"axios-mock-adapter": "^1.21.4",
|
|
55
56
|
"chance": "^1.1.8",
|
|
56
57
|
"eslint": "^8.7.0",
|
|
57
58
|
"eslint-config-airbnb-base": "^15.0.0",
|
package/test/plugin.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* global jest, expect */
|
|
2
2
|
/* eslint class-methods-use-this: "off", max-len: "off" */
|
|
3
|
+
const R = require('ramda');
|
|
3
4
|
|
|
4
5
|
const jestPlugin = (() => {
|
|
5
6
|
if (typeof jest === 'undefined') {
|
|
@@ -53,7 +54,19 @@ class Plugin {
|
|
|
53
54
|
});
|
|
54
55
|
this.searchQuote = jestPlugin.fn(() => ({ quote: [{ id: chance.guid() }] }));
|
|
55
56
|
this.createBooking = jestPlugin.fn(() => {});
|
|
56
|
-
this.queryAllotment = jestPlugin.fn(() =>
|
|
57
|
+
this.queryAllotment = jestPlugin.fn(async (args) => {
|
|
58
|
+
const {
|
|
59
|
+
axios,
|
|
60
|
+
payload,
|
|
61
|
+
} = args;
|
|
62
|
+
if (payload.keyPath === 'errorAxios') {
|
|
63
|
+
await axios.get('http://localhost:1235/');
|
|
64
|
+
}
|
|
65
|
+
if (payload.keyPath === 'errorGeneral') {
|
|
66
|
+
await axios.get('http://www.example.com');
|
|
67
|
+
}
|
|
68
|
+
return { allotments: [] }
|
|
69
|
+
});
|
|
57
70
|
this.tokenTemplate = jestPlugin.fn(() => ({
|
|
58
71
|
apiKey: {
|
|
59
72
|
type: 'text',
|
|
@@ -61,6 +74,14 @@ class Plugin {
|
|
|
61
74
|
description: 'Api Key',
|
|
62
75
|
},
|
|
63
76
|
}));
|
|
77
|
+
this.errorPathsAxiosErrors = jestPlugin.fn(() => ([
|
|
78
|
+
['code'],
|
|
79
|
+
]));
|
|
80
|
+
this.errorPathsAxiosAny = jestPlugin.fn(() => ([
|
|
81
|
+
err => {
|
|
82
|
+
return R.path(['data', 'error'], err);
|
|
83
|
+
}
|
|
84
|
+
]));
|
|
64
85
|
|
|
65
86
|
/**
|
|
66
87
|
* Background and schedule Jos
|
|
@@ -458,6 +479,23 @@ class Plugin {
|
|
|
458
479
|
*/
|
|
459
480
|
createBooking() {}
|
|
460
481
|
|
|
482
|
+
/**
|
|
483
|
+
* Allotment Object
|
|
484
|
+
/**
|
|
485
|
+
* @typedef {Object} Allotment
|
|
486
|
+
* @property {string} name - The name of the allotment.
|
|
487
|
+
* @property {string} description - A description of the allotment.
|
|
488
|
+
* @property {string} appliesTo - Specifies what the allotment applies to.
|
|
489
|
+
* @property {string} splitCode - The code used to split the allotment.
|
|
490
|
+
* @property {string} unitType - The type of unit used for the allotment.
|
|
491
|
+
* @property {Date} date - The date associated with the allotment using the input format.
|
|
492
|
+
* @property {string} release - The release period of the allotment as specified in the day inventory.
|
|
493
|
+
* @property {number} max - The maximum quantity allowed for the allotment as specified in the day inventory.
|
|
494
|
+
* @property {number} booked - The booked quantity of the allotment as specified in the day inventory.
|
|
495
|
+
* @property {boolean} request - Indicates whether requests are allowed for the allotment, based on the day inventory.
|
|
496
|
+
* @property {string[]} keyPaths - An array of key paths generated by combining supplier code and product codes.
|
|
497
|
+
*/
|
|
498
|
+
|
|
461
499
|
/**
|
|
462
500
|
* Query Allotment
|
|
463
501
|
* @async
|
|
@@ -473,7 +511,7 @@ class Plugin {
|
|
|
473
511
|
* @param {string} args.payload.endDate - End date for the query of allotment objects
|
|
474
512
|
* @param {string} args.payload.keyPath - End date for the query of allotment objects
|
|
475
513
|
* @returns {object} retVal - the return object.
|
|
476
|
-
* @returns {
|
|
514
|
+
* @returns {Allotment[]} retVal.allotment - An array of allotment spec objects.
|
|
477
515
|
*/
|
|
478
516
|
queryAllotment() {}
|
|
479
517
|
}
|