ti2-ventrata 1.0.10 → 1.0.12
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/index.js +73 -46
- package/index.test.js +31 -3
- package/jestEnvironment.js +81 -0
- package/package.json +7 -3
package/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const axios = require('axios');
|
|
2
|
+
const curlirize = require('axios-curlirize');
|
|
2
3
|
const R = require('ramda');
|
|
3
4
|
const Promise = require('bluebird');
|
|
4
5
|
const assert = require('assert');
|
|
@@ -7,6 +8,9 @@ const jwt = require('jsonwebtoken');
|
|
|
7
8
|
const wildcardMatch = require('./utils/wildcardMatch');
|
|
8
9
|
|
|
9
10
|
const CONCURRENCY = 3; // is this ok ?
|
|
11
|
+
if (process.env.debug) {
|
|
12
|
+
curlirize(axios);
|
|
13
|
+
}
|
|
10
14
|
|
|
11
15
|
const isNilOrEmpty = R.either(R.isNil, R.isEmpty);
|
|
12
16
|
const isNilOrEmptyArray = el => {
|
|
@@ -54,12 +58,26 @@ const rateMap = {
|
|
|
54
58
|
pricing: R.path(['pricingFrom']),
|
|
55
59
|
};
|
|
56
60
|
|
|
61
|
+
const unitPricingMap = {
|
|
62
|
+
unitId: R.prop('unitId'),
|
|
63
|
+
original: R.prop('original'),
|
|
64
|
+
retail: R.prop('retail'),
|
|
65
|
+
net: R.prop('net'),
|
|
66
|
+
currencyPrecision: R.prop('currencyPrecision'),
|
|
67
|
+
};
|
|
68
|
+
|
|
57
69
|
const availabilityMap = {
|
|
58
70
|
dateTimeStart: root => R.path(['localDateTimeStart'], root) || R.path(['localDate'], root),
|
|
59
|
-
dateTimeEnd: root => R.path(['localDateTimeEnd']) || R.path(['localDate'], root),
|
|
71
|
+
dateTimeEnd: root => R.path(['localDateTimeEnd'], root) || R.path(['localDate'], root),
|
|
60
72
|
allDay: R.path(['allDay']),
|
|
61
73
|
pricing: root => R.path(['pricing'], root) || R.path(['pricingFrom'], root),
|
|
62
|
-
unitPricing: root =>
|
|
74
|
+
unitPricing: root => {
|
|
75
|
+
let before = [];
|
|
76
|
+
if (R.path(['unitPricing'], root)) before = R.path(['unitPricing'], root);
|
|
77
|
+
else before = R.path(['unitPricingFrom'], root) || [];
|
|
78
|
+
return before.map(item => doMap(item, unitPricingMap));
|
|
79
|
+
},
|
|
80
|
+
vacancies: R.prop('vacancies'),
|
|
63
81
|
offer: avail => (avail.offerCode ? doMap(avail, {
|
|
64
82
|
offerId: R.path(['offerCode']),
|
|
65
83
|
title: R.pathOr(undefined, ['offerTitle']),
|
|
@@ -109,7 +127,7 @@ const unitItemMap = {
|
|
|
109
127
|
unitItemId: R.path(['uuid']),
|
|
110
128
|
unitId: R.path(['unitId']),
|
|
111
129
|
unitName: R.path(['unit', 'title']),
|
|
112
|
-
|
|
130
|
+
supplierBookingId: R.path(['supplierReference']),
|
|
113
131
|
status: e => capitalize(R.path(['status'], e)),
|
|
114
132
|
contact: R.path(['contact']),
|
|
115
133
|
pricing: R.path(['pricing']),
|
|
@@ -131,7 +149,7 @@ const bookingMap = {
|
|
|
131
149
|
id: R.path(['id']),
|
|
132
150
|
orderId: R.path(['orderReference']),
|
|
133
151
|
bookingId: R.path(['supplierReference']),
|
|
134
|
-
|
|
152
|
+
supplierBookingId: R.path(['supplierReference']),
|
|
135
153
|
status: e => capitalize(R.path(['status'], e)),
|
|
136
154
|
productId: R.path(['product', 'id']),
|
|
137
155
|
productName: R.path(['product', 'title']),
|
|
@@ -171,11 +189,17 @@ const contactMap = {
|
|
|
171
189
|
country: R.path(['country']),
|
|
172
190
|
};
|
|
173
191
|
|
|
174
|
-
const getHeaders = ({
|
|
192
|
+
const getHeaders = ({
|
|
193
|
+
apiKey,
|
|
194
|
+
acceptLanguage,
|
|
195
|
+
octoEnv,
|
|
196
|
+
referrer,
|
|
197
|
+
}) => ({
|
|
175
198
|
Authorization: `Bearer ${apiKey}`,
|
|
176
199
|
'Octo-Env': octoEnv,
|
|
177
200
|
...acceptLanguage ? { 'Accept-Language': acceptLanguage } : {},
|
|
178
201
|
'Content-Type': 'application/json',
|
|
202
|
+
...referrer ? { Referer: referrer } : {},
|
|
179
203
|
});
|
|
180
204
|
|
|
181
205
|
class Plugin {
|
|
@@ -454,48 +478,51 @@ class Plugin {
|
|
|
454
478
|
},
|
|
455
479
|
payload: {
|
|
456
480
|
availabilityKey,
|
|
481
|
+
holder,
|
|
457
482
|
notes,
|
|
458
483
|
reference,
|
|
459
|
-
|
|
484
|
+
referrer,
|
|
485
|
+
settlementMethod,
|
|
460
486
|
},
|
|
461
487
|
}) {
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
url = `${endpoint || this.endpoint}/bookings/${booking.uuid}/confirm`;
|
|
482
|
-
const contact = doMap(holder, contactMap);
|
|
483
|
-
data = {
|
|
488
|
+
assert(availabilityKey, 'an availability code is required !');
|
|
489
|
+
assert(R.path(['name'], holder), 'a holder\' first name is required');
|
|
490
|
+
assert(R.path(['surname'], holder), 'a holder\' surname is required');
|
|
491
|
+
assert(R.path(['emailAddress'], holder), 'a holder\' email address is required');
|
|
492
|
+
const headers = getHeaders({
|
|
493
|
+
apiKey,
|
|
494
|
+
endpoint,
|
|
495
|
+
octoEnv,
|
|
496
|
+
acceptLanguage,
|
|
497
|
+
referrer,
|
|
498
|
+
});
|
|
499
|
+
let url = `${endpoint || this.endpoint}/bookings`;
|
|
500
|
+
let data = await jwt.verify(availabilityKey, this.jwtKey);
|
|
501
|
+
let booking = R.path(['data'], await axios({
|
|
502
|
+
method: 'post',
|
|
503
|
+
url,
|
|
504
|
+
data: {
|
|
505
|
+
settlementMethod,
|
|
506
|
+
...data,
|
|
484
507
|
notes,
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
508
|
+
},
|
|
509
|
+
headers,
|
|
510
|
+
}));
|
|
511
|
+
url = `${endpoint || this.endpoint}/bookings/${booking.uuid}/confirm`;
|
|
512
|
+
const contact = doMap(holder, contactMap);
|
|
513
|
+
data = {
|
|
514
|
+
contact,
|
|
515
|
+
notes,
|
|
516
|
+
resellerReference: reference,
|
|
517
|
+
settlementMethod,
|
|
518
|
+
};
|
|
519
|
+
booking = R.path(['data'], await axios({
|
|
520
|
+
method: 'post',
|
|
521
|
+
url,
|
|
522
|
+
data,
|
|
523
|
+
headers,
|
|
524
|
+
}));
|
|
525
|
+
return ({ booking: doMap(booking, bookingMap) });
|
|
499
526
|
}
|
|
500
527
|
|
|
501
528
|
async cancelBooking({
|
|
@@ -538,7 +565,7 @@ class Plugin {
|
|
|
538
565
|
payload: {
|
|
539
566
|
bookingId,
|
|
540
567
|
resellerReference,
|
|
541
|
-
|
|
568
|
+
supplierBookingId,
|
|
542
569
|
travelDateStart,
|
|
543
570
|
travelDateEnd,
|
|
544
571
|
dateFormat,
|
|
@@ -547,7 +574,7 @@ class Plugin {
|
|
|
547
574
|
assert(
|
|
548
575
|
!isNilOrEmpty(bookingId)
|
|
549
576
|
|| !isNilOrEmpty(resellerReference)
|
|
550
|
-
|| !isNilOrEmpty(
|
|
577
|
+
|| !isNilOrEmpty(supplierBookingId)
|
|
551
578
|
|| !(
|
|
552
579
|
isNilOrEmpty(travelDateStart) && isNilOrEmpty(travelDateEnd) && isNilOrEmpty(dateFormat)
|
|
553
580
|
),
|
|
@@ -587,8 +614,8 @@ class Plugin {
|
|
|
587
614
|
headers,
|
|
588
615
|
}));
|
|
589
616
|
}
|
|
590
|
-
if (!isNilOrEmpty(
|
|
591
|
-
url = `${endpoint || this.endpoint}/bookings?supplierReference=${
|
|
617
|
+
if (!isNilOrEmpty(supplierBookingId)) {
|
|
618
|
+
url = `${endpoint || this.endpoint}/bookings?supplierReference=${supplierBookingId}`;
|
|
592
619
|
return R.path(['data'], await axios({
|
|
593
620
|
method: 'get',
|
|
594
621
|
url,
|
package/index.test.js
CHANGED
|
@@ -175,6 +175,7 @@ describe('search tests', () => {
|
|
|
175
175
|
payload: {
|
|
176
176
|
availabilityKey,
|
|
177
177
|
notes: faker.lorem.paragraph(),
|
|
178
|
+
settlementMethod: 'DEFERRED',
|
|
178
179
|
holder: {
|
|
179
180
|
name: fullName[0],
|
|
180
181
|
surname: fullName[1],
|
|
@@ -190,7 +191,7 @@ describe('search tests', () => {
|
|
|
190
191
|
({ booking } = retVal);
|
|
191
192
|
expect(booking).toBeTruthy();
|
|
192
193
|
expect(R.path(['id'], booking)).toBeTruthy();
|
|
193
|
-
expect(R.path(['
|
|
194
|
+
expect(R.path(['supplierBookingId'], booking)).toBeTruthy();
|
|
194
195
|
expect(R.path(['cancellable'], booking)).toBeTruthy();
|
|
195
196
|
// console.log({ booking });
|
|
196
197
|
});
|
|
@@ -231,11 +232,11 @@ describe('search tests', () => {
|
|
|
231
232
|
({ bookings } = retVal);
|
|
232
233
|
expect(R.path([0, 'id'], bookings)).toBeTruthy();
|
|
233
234
|
});
|
|
234
|
-
it('it should be able to search bookings by
|
|
235
|
+
it('it should be able to search bookings by supplierBookingId', async () => {
|
|
235
236
|
const retVal = await app.searchBooking({
|
|
236
237
|
token,
|
|
237
238
|
payload: {
|
|
238
|
-
bookingId: booking.
|
|
239
|
+
bookingId: booking.supplierBookingId,
|
|
239
240
|
},
|
|
240
241
|
});
|
|
241
242
|
expect(Array.isArray(retVal.bookings)).toBeTruthy();
|
|
@@ -255,5 +256,32 @@ describe('search tests', () => {
|
|
|
255
256
|
({ bookings } = retVal);
|
|
256
257
|
expect(R.path([0, 'id'], bookings)).toBeTruthy();
|
|
257
258
|
});
|
|
259
|
+
it('should be able to create a booking for a referrer', async () => {
|
|
260
|
+
const fullName = faker.name.findName().split(' ');
|
|
261
|
+
const retVal = await app.createBooking({
|
|
262
|
+
token,
|
|
263
|
+
payload: {
|
|
264
|
+
availabilityKey,
|
|
265
|
+
notes: faker.lorem.paragraph(),
|
|
266
|
+
holder: {
|
|
267
|
+
name: fullName[0],
|
|
268
|
+
surname: fullName[1],
|
|
269
|
+
phoneNumber: faker.phone.phoneNumber(),
|
|
270
|
+
emailAddress: `salvador+tests_${faker.lorem.slug()}@tourconnect.com`,
|
|
271
|
+
country: faker.address.countryCode(),
|
|
272
|
+
locales: ['en-US', 'en', 'es'],
|
|
273
|
+
},
|
|
274
|
+
reference,
|
|
275
|
+
referrer: 'referrerforapitest',
|
|
276
|
+
settlementMethod: 'DEFERRED',
|
|
277
|
+
},
|
|
278
|
+
});
|
|
279
|
+
expect(retVal.booking).toBeTruthy();
|
|
280
|
+
({ booking } = retVal);
|
|
281
|
+
expect(booking).toBeTruthy();
|
|
282
|
+
expect(R.path(['id'], booking)).toBeTruthy();
|
|
283
|
+
expect(R.path(['supplierBookingId'], booking)).toBeTruthy();
|
|
284
|
+
expect(R.path(['cancellable'], booking)).toBeTruthy();
|
|
285
|
+
});
|
|
258
286
|
});
|
|
259
287
|
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const NodeEnvironment = require('jest-environment-node');
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
|
|
4
|
+
const { debug } = process.env;
|
|
5
|
+
|
|
6
|
+
class NodeEnvironmentFailFast extends NodeEnvironment {
|
|
7
|
+
constructor(config, context) {
|
|
8
|
+
super(config, context);
|
|
9
|
+
this.failedDescribeMap = {};
|
|
10
|
+
this.registeredEventHandler = [];
|
|
11
|
+
this.lastParent = undefined;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async setup() {
|
|
15
|
+
await super.setup();
|
|
16
|
+
this.global.testEnvironment = this;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
registerTestEventHandler(registeredEventHandler) {
|
|
20
|
+
this.registeredEventHandler.push(registeredEventHandler);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async executeTestEventHandlers(event, state) {
|
|
24
|
+
for (const handler of this.registeredEventHandler) {
|
|
25
|
+
await handler(event, state);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async handleTestEvent(event, state) {
|
|
30
|
+
await this.executeTestEventHandlers(event, state);
|
|
31
|
+
|
|
32
|
+
switch (event.name) {
|
|
33
|
+
case 'hook_failure': {
|
|
34
|
+
const describeBlockName = event.hook.parent.name;
|
|
35
|
+
this.failedDescribeMap[describeBlockName] = true;
|
|
36
|
+
// hook errors are not displayed if tests are skipped, so display them manually
|
|
37
|
+
console.error(`ERROR: ${describeBlockName} > ${event.hook.type}\n\n`, event.error, '\n');
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
case 'test_fn_success': {
|
|
41
|
+
if (debug) {
|
|
42
|
+
if (this.lastParent !== event.test.parent.name) {
|
|
43
|
+
console.log(`${event.test.parent.name}\n ${chalk.green('\u2713')} ${event.test.name}`);
|
|
44
|
+
} else {
|
|
45
|
+
console.log(` ${chalk.green('\u2713')} ${event.test.name}`);
|
|
46
|
+
}
|
|
47
|
+
this.lastParent = event.test.parent.name;
|
|
48
|
+
}
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
case 'test_fn_failure': {
|
|
52
|
+
this.failedDescribeMap[event.test.parent.name] = true;
|
|
53
|
+
if (debug) {
|
|
54
|
+
if (this.lastParent !== event.test.parent.name) {
|
|
55
|
+
console.log(`${event.test.parent.name}\n ${chalk.red('\u2715')} ${event.test.name}`);
|
|
56
|
+
} else {
|
|
57
|
+
console.log(` ${chalk.red('\u2715')} ${event.test.name}`);
|
|
58
|
+
}
|
|
59
|
+
this.lastParent = event.test.parent.name;
|
|
60
|
+
console.error(event.error.message);
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
case 'test_start': {
|
|
65
|
+
if (this.failedDescribeMap[event.test.parent.name]) {
|
|
66
|
+
event.test.mode = 'skip';
|
|
67
|
+
}
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (super.handleTestEvent) {
|
|
73
|
+
super.handleTestEvent(event, state);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async teardown() {
|
|
78
|
+
await super.teardown();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
module.exports = NodeEnvironmentFailFast;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ti2-ventrata",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.12",
|
|
4
4
|
"description": "Ventrata's TI2 Plugin",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
},
|
|
18
18
|
"homepage": "https://github.com/TourConnect/ti2-ventrata#readme",
|
|
19
19
|
"jest": {
|
|
20
|
-
"testEnvironment": "
|
|
20
|
+
"testEnvironment": "<rootDir>/jestEnvironment.js",
|
|
21
21
|
"coveragePathIgnorePatterns": [
|
|
22
22
|
"/node_modules/"
|
|
23
23
|
],
|
|
@@ -28,18 +28,22 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"axios": "^0.24.0",
|
|
31
|
+
"axios-curlirize": "^1.3.7",
|
|
31
32
|
"bluebird": "^3.7.2",
|
|
32
33
|
"jsonwebtoken": "^8.5.1",
|
|
33
34
|
"moment": "^2.29.1",
|
|
34
35
|
"ramda": "^0.27.1"
|
|
35
36
|
},
|
|
36
37
|
"devDependencies": {
|
|
38
|
+
"chalk": "^4.1.2",
|
|
37
39
|
"eslint": "^8.4.1",
|
|
38
40
|
"eslint-config-airbnb": "^19.0.2",
|
|
39
41
|
"eslint-plugin-import": "^2.25.4",
|
|
40
42
|
"faker": "^5.5.3",
|
|
41
43
|
"jest": "^27.4.5",
|
|
42
44
|
"jest-cli": "^27.4.7",
|
|
43
|
-
"jest-diff": "^27.4.2"
|
|
45
|
+
"jest-diff": "^27.4.2",
|
|
46
|
+
"jest-environment-node": "27.4",
|
|
47
|
+
"jest-util": "27.4"
|
|
44
48
|
}
|
|
45
49
|
}
|