ti2 1.0.0

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.
@@ -0,0 +1,87 @@
1
+ const jsonwebtoken = require('jsonwebtoken');
2
+ const Promise = require('bluebird');
3
+ const assert = require('assert');
4
+
5
+ const sqldb = require('../models');
6
+
7
+ const {
8
+ env: {
9
+ frontendKey,
10
+ adminKey,
11
+ jwtSecret,
12
+ },
13
+ } = process;
14
+
15
+ const invalid = next => next({ status: 401, message: 'Unauthorized' });
16
+ const getToken = ({ req }) => {
17
+ if (
18
+ !req.header('Authorization')
19
+ || req.header('Authorization').substring(0, 7) !== 'Bearer '
20
+ ) return null;
21
+ return req.header('Authorization').split(' ')[1];
22
+ };
23
+ // the authentication middleware
24
+ const app = async (req, res, next) => {
25
+ if (!req.pathParams || !req.pathParams.app) return invalid(next);
26
+ const token = getToken({ req });
27
+ if (!token) return invalid(next);
28
+ // try {
29
+ const appRecord = await sqldb.Integration.findOne({
30
+ where: {
31
+ name: req.pathParams.app,
32
+ },
33
+ });
34
+ if (!appRecord) return invalid(next);
35
+ if (appRecord.apiKey !== token) {
36
+ return invalid(next);
37
+ }
38
+ req.appRecord = appRecord.dataValues;
39
+ return next();
40
+ };
41
+
42
+ // The requester is an admin; createApps and other admin tasks
43
+ const admin = async (req, res, next) => {
44
+ const token = getToken({ req });
45
+ if (token !== adminKey) return invalid(next);
46
+ return next();
47
+ };
48
+
49
+ // the request is from a user, checke the userId agains the url param
50
+ const user = async (req, res, next) => {
51
+ const token = getToken({ req });
52
+ if (!token) return invalid(next);
53
+ try {
54
+ const { userId } = jsonwebtoken.verify(token, jwtSecret);
55
+ assert(userId);
56
+ if (req.params.userId && userId !== req.params.userId) return invalid(next);
57
+ } catch (err) {
58
+ return invalid(next);
59
+ }
60
+ return next();
61
+ };
62
+
63
+ // The requester comes from frontend; frontend driven tasks
64
+ const frontend = async (req, res, next) => {
65
+ const token = getToken({ req });
66
+ if (token !== frontendKey) return invalid(next);
67
+ return next();
68
+ };
69
+
70
+ const adminOrUser = levels => async (req, res, next) => {
71
+ result = await Promise.all(levels.map(
72
+ level => level(req, res, err => err),
73
+ ));
74
+ if (result.some(val => (!Boolean(val)))) {
75
+ return next();
76
+ }
77
+ return next(result[0]);
78
+ };
79
+
80
+ module.exports = {
81
+ app,
82
+ frontend,
83
+ admin,
84
+ user,
85
+ 'admin,user': adminOrUser([admin, user]),
86
+ 'admin,app,user': adminOrUser([admin, app, user]),
87
+ };
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ [process.env.NODE_ENV || 'development']: {
3
+ use_env_variable: 'DB_URL',
4
+ },
5
+ };
@@ -0,0 +1 @@
1
+ Place your controllers in this directory.
@@ -0,0 +1,330 @@
1
+ module.exports = {
2
+ leftSide: {
3
+ name: 'TourConnect',
4
+ entityImage:
5
+ 'https://s3.amazonaws.com/tourconnect_staging/images/images/536830b6ed19afa44a000002/profile?1501741129917',
6
+ },
7
+ rightSide: {
8
+ name: 'Didgigo',
9
+ },
10
+ fieldSets: {
11
+ profile: {
12
+ caption: 'Company Details',
13
+ mappingType: 'fields',
14
+ leftSide: {
15
+ entityType: 'Profile',
16
+ entityName: 'Luxury Island Suites',
17
+ entity: 'Profile',
18
+ fields: [
19
+ {
20
+ id: 'name',
21
+ title: 'Company Name',
22
+ content: 'Luxury Island Suites',
23
+ },
24
+ {
25
+ id: 'address',
26
+ title: 'Address',
27
+ content: {
28
+ country: 'Australia',
29
+ state: 'QLD',
30
+ city: 'Arlie Beach',
31
+ postalCode: '4802',
32
+ address1: '30 Golden Orchad Drive',
33
+ address2: null,
34
+ gps: {
35
+ lat: '1.3644202',
36
+ lng: '103.9915308',
37
+ },
38
+ },
39
+ },
40
+ {
41
+ id: 'description',
42
+ title: 'Description',
43
+ content:
44
+ 'Luxury Island Suites stands as the stylish, forward thinking leader of island hospitality. With over 60 years of experience, LIS continues to be synonymous with luxury because of our innovative approach to products, amenities and service. We help make traveling easier with our smart design, innovative restaurant concepts, authentic hospitality and commitment to the global community.',
45
+ },
46
+ {
47
+ id: 'website',
48
+ title: 'Website',
49
+ content: 'www.luxuryislandsuites.com.au',
50
+ },
51
+ {
52
+ id: 'telephone',
53
+ title: 'Telephone Number',
54
+ content: '1800 700 600',
55
+ },
56
+ ],
57
+ },
58
+ rightSide: {
59
+ entityType: 'Public Profile',
60
+ entityName: 'Luxury Suites of Australia',
61
+ fields: [
62
+ {
63
+ id: 'name',
64
+ title: 'Company Name',
65
+ content: 'Luxury Suites of Australia',
66
+ },
67
+ {
68
+ id: 'address',
69
+ title: 'Address',
70
+ content: '',
71
+ },
72
+ {
73
+ id: 'description',
74
+ title: 'Welcome Paragraph',
75
+ content:
76
+ 'Actually try-hard vape marfa wayfarers. Woke live-edge dreamcatcher copper mug selvage kinfolk pork belly normcore tumeric ennui crucifix squid four loko. Pitchfork ugh cray, blog succulents blue bottle small batch fixie scenester sustainable. Cred fingerstache art party pop-up coloring book ugh. Woke raclette kombucha narwhal kickstarter, meh ugh roof party banjo meggings copper mug. Ugh air plant tattooed pitchfork cold-pressed, hashtag mumblecore gentrify tumeric succulents knausgaard lumbersexual. Hexagon shaman mixtape cornhole plaid cliche whatever celiac kickstarter distillery microdosing.',
77
+ },
78
+ ],
79
+ },
80
+ mappings: [],
81
+ },
82
+ locations: {
83
+ caption: 'Properties / Locations',
84
+ mappingType: 'locations',
85
+ leftSide: {
86
+ entity: 'Locations',
87
+ entityName: 'Location',
88
+ entityType: 'Locations',
89
+ locations: [
90
+ {
91
+ locationId: '5368655d97417de435000001',
92
+ locationName: 'Arlie Beach Luxury Island Suites',
93
+ description:
94
+ "Luxury Island Suites in Airlie Beach offers a pampering vacation experience that is truly unique among Airlie Beach hotels. Situated on a cliff rising above the sea, all of Island's suites enjoy full panoramic views.",
95
+ media: {
96
+ images: [
97
+ {
98
+ url:
99
+ 'https://s3.amazonaws.com/tourconnect_staging/7624471190451/d6fd2cc1-dc54-11e8-b9ed-eb2f0d66c310',
100
+ },
101
+ {
102
+ url:
103
+ 'https://s3.amazonaws.com/tourconnect_staging/5035112190451/b428be21-dc55-11e8-b85e-59746f3f59b6',
104
+ },
105
+ ],
106
+ },
107
+ location: {
108
+ country: 'Australia',
109
+ state: 'QLD',
110
+ city: 'Arlie Beach',
111
+ postalCode: '4802',
112
+ address1: '30 Golden Orchad Drive',
113
+ address2: null,
114
+ gps: {
115
+ lat: '1.3644202',
116
+ lng: '103.9915308',
117
+ },
118
+ },
119
+ },
120
+ {
121
+ locationId: '5f2d3bdea7ea49524000001',
122
+ locationName: 'Isla Mujeres Island Suites',
123
+ description:
124
+ 'Relax into island time in the comfort and easy elegance of Orcas Island’s premier specialty lodging. Water view suites are located in the heart of Eastsound Village, just steps away from shops & galleries, world-renowned dining, beach strolling, outdoor adventures and more. Eastsound Suites are a popular alternative accommodation to hotels, motels or B&B’s. Much more special!',
125
+ media: {
126
+ images: [
127
+ {
128
+ url:
129
+ 'https://s3.amazonaws.com/tourconnect_staging/5035112190451/b428be21-dc55-11e8-b85e-59746f3f59b6',
130
+ },
131
+ ],
132
+ },
133
+ location: {
134
+ country: 'Mexico',
135
+ state: 'Quintana Roo',
136
+ city: 'Isla Mujeres',
137
+ postalCode: '00',
138
+ address1: 'tbc',
139
+ },
140
+ },
141
+ ],
142
+ },
143
+ rightSide: {
144
+ entity: 'Products',
145
+ entityName: 'Product',
146
+ entityType: 'Product',
147
+ locations: [
148
+ {
149
+ locationId: '332233',
150
+ locationName: 'Hilton',
151
+ description:
152
+ 'Hampton Inn by Hilton Cancun Cumbres is a modern business hotel that is located in a recently developed area of Cancun. The hotel is just steps away from various shops, supermarkets and malls, and also offers easy access to the highway which takes you to the downtown area and airport.',
153
+ media: {
154
+ images: [
155
+ {
156
+ url:
157
+ 'https://cdn.bestday.net/_lib/vimages/Cancun/Hotels/hotel-hampton-inn-hilton-cancun-cumbres/fachada_g.jpg',
158
+ },
159
+ ],
160
+ },
161
+ location: {
162
+ country: 'Mexico',
163
+ state: 'Quintana Roo',
164
+ city: 'Cancun',
165
+ postalcode: '7500',
166
+ address1: 'SM 310 MZ 01 L-4-02',
167
+ address2: 'Blvd. Luis Donaldo Colosio',
168
+ },
169
+ },
170
+ {
171
+ locationId: '332234',
172
+ locationName: 'Hilton Lagoon',
173
+ description:
174
+ 'Simple rooms in an unpretentious hotel featuring lagoon views, a restaurant/bar & an outdoor pool.',
175
+ media: {
176
+ images: [
177
+ {
178
+ url:
179
+ 'http://www.iceportal.com/data/2813-55900-f7541089_XXLejpg/Mexico/Cancun/Hotel/Grand-Royal-Lagoon/Photo/Grand-Royal-Lagoon-Cancun-Exterior-view-Exterior.jpg',
180
+ },
181
+ ],
182
+ },
183
+ location: {
184
+ country: 'Mexico',
185
+ state: 'Quintana Roo',
186
+ city: 'Cancun',
187
+ postalCode: '77500',
188
+ address1: 'Blvd. Kukulcan Km 7.5, Punta Cancun, Zona Hotelera',
189
+ },
190
+ },
191
+ ],
192
+ },
193
+ mappings: [],
194
+ },
195
+ products: {
196
+ caption: 'Products',
197
+ mappingType: 'products',
198
+ leftSide: {
199
+ entity: 'Products',
200
+ entityName: 'Location/Product',
201
+ entityType: 'Products',
202
+ products: [
203
+ {
204
+ locationId: '5368655d97417de435000001',
205
+ locationName: 'Arlie Beach Luxury Island Suites',
206
+ productId: '536868d097417d07e0000003',
207
+ productName: 'King Suite',
208
+ description:
209
+ 'There’s plenty of room for work and play in our Executive King Suite with its comfortable, modern design. Its elegant, modern design features a media hub for all your gadgets, plenty of space to get work done, and plush furnishings to ensure your comfort all the while.',
210
+ media: {
211
+ images: [
212
+ {
213
+ url:
214
+ 'https://static.mgmresorts.com/content/dam/MGM/mgm-grand/hotel/mgm-grand/graphic-elements/mgm-grand-hotel-rooms-details-bedroom-bed-close-up-@2x.jpg.image.744.418.high.jpg',
215
+ },
216
+ {
217
+ url:
218
+ 'https://static.mgmresorts.com/content/dam/MGM/mgm-grand/hotel/mgm-grand/executive-king-suite/architecture/mgm_grand_room_executive_king_suite.png.image.1488.836.high.jpg',
219
+ },
220
+ ],
221
+ },
222
+ },
223
+ {
224
+ locationId: '5368655d97417de435000001',
225
+ locationName: 'Arlie Beach Luxury Island Suites',
226
+ productId: '5368698c97417de435000013',
227
+ productName: 'Master King Suite',
228
+ description:
229
+ "Knausgaard hell of bitters 90's pickled tote bag narwhal farm-to-table paleo lyft taxidermy man braid meditation vinyl glossier. Live-edge tousled disrupt, pug meh keffiyeh venmo tofu organic occupy swag chicharrones ethical humblebrag. Dreamcatcher keytar biodiesel, banjo cronut vaporware marfa heirloom. Meh coloring book chartreuse, synth taiyaki etsy kinfolk succulents raclette lomo humblebrag lo-fi taxidermy edison bulb slow-carb. Neutra occupy thundercats sustainable fingerstache hot chicken next level forage. Godard coloring book iceland photo booth waistcoat next level 3 wolf moon, vice mumblecore wolf poutine paleo four dollar toast seitan authentic.",
230
+ media: {
231
+ images: [
232
+ {
233
+ url:
234
+ 'https://photos.hotelbeds.com/giata/bigger/45/457081/457081a_hb_ro_002.jpg',
235
+ },
236
+ {
237
+ url:
238
+ 'https://photos.hotelbeds.com/giata/bigger/45/457081/457081a_hb_ro_016.jpg',
239
+ },
240
+ ],
241
+ },
242
+ },
243
+ {
244
+ locationId: '5368655d97417de435000001',
245
+ locationName: 'Arlie Beach Luxury Island Suites',
246
+ productId: '55b189b682c2b00300c9dd41',
247
+ productName: '1 Bedroom Apartment/Suite',
248
+ },
249
+ {
250
+ locationId: '5368655d97417de435000001',
251
+ locationName: 'Arlie Beach Luxury Island Suites',
252
+ productId: '536867a697417de43500000f',
253
+ productName: 'King Deluxe Guest Room',
254
+ },
255
+ {
256
+ locationId: '5f2d3bdea7ea49524000001',
257
+ locationName: 'Isla Mujeres Island Suites',
258
+ productId: ':5407d059707f0fe2900001f1',
259
+ productName: 'Deluxe Island Suite',
260
+ },
261
+ {
262
+ locationId: '5f2d3bdea7ea49524000001',
263
+ locationName: 'Isla Mujeres Island Suites',
264
+ productId: '5407cc9d707f0fe2900000cc',
265
+ productName: 'Island Suite',
266
+ },
267
+ {
268
+ locationId: '5f2d3bdea7ea49524000001',
269
+ locationName: 'Isla Mujeres Island Suites',
270
+ productId: '55b5b51a8f58920300a115cc',
271
+ productName: 'Garden Sunset Suite',
272
+ },
273
+ ],
274
+ },
275
+ rightSide: {
276
+ entity: 'Options',
277
+ entityType: 'Options',
278
+ entityName: 'Products/Options',
279
+ products: [
280
+ {
281
+ locationId: '332233',
282
+ locationName: 'Hilton Beach',
283
+ productId: '009992',
284
+ productName: 'Queen Suite',
285
+ },
286
+ {
287
+ locationId: '332234',
288
+ locationName: 'Hilton Lagoon',
289
+ productId: '009993',
290
+ productName: 'King Suite',
291
+ },
292
+ ],
293
+ },
294
+ mappings: [
295
+ {
296
+ leftSide: {
297
+ locationId: '5368655d97417de435000001',
298
+ productId: '536868d097417d07e0000003',
299
+ },
300
+ action: 'left',
301
+ },
302
+ {
303
+ rightSide: {
304
+ locationId: '332233',
305
+ productId: '009992',
306
+ },
307
+ action: 'right',
308
+ },
309
+ {
310
+ leftSide: {
311
+ locationId: '5368655d97417de435000001',
312
+ productId: '5368698c97417de435000013',
313
+ },
314
+ rightSide: {
315
+ locationId: '332234',
316
+ productId: '009993',
317
+ },
318
+ action: 'left',
319
+ },
320
+ {
321
+ leftSide: {
322
+ locationId: '5368655d97417de435000001',
323
+ productId: '55b189b682c2b00300c9dd41',
324
+ },
325
+ action: 'ignore',
326
+ },
327
+ ],
328
+ },
329
+ },
330
+ };
@@ -0,0 +1,17 @@
1
+ /* globals jest */
2
+ const faker = require('faker');
3
+ const { fieldSets } = require('../__fixtures__/fieldData');
4
+
5
+ module.exports = () => ({
6
+ validateToken: jest.fn(() => true),
7
+ getProfile: jest.fn(() => fieldSets.profile.leftSide),
8
+ updateProfile: jest.fn(() => true),
9
+ getLocations: jest.fn(() => fieldSets.locations.leftSide.locations),
10
+ getLocation: jest.fn(() => fieldSets.locations.leftSide.locations[0]),
11
+ createLocation: jest.fn(() => ({ locationId: faker.random.uuid() })),
12
+ updateLocation: jest.fn(() => true),
13
+ getProducts: jest.fn(),
14
+ getProduct: jest.fn(),
15
+ createProduct: jest.fn(() => (({ productId: faker.random.uuid() }))),
16
+ updateProduct: jest.fn(() => true),
17
+ });
@@ -0,0 +1,61 @@
1
+ /* globals describe it expect afterAll */
2
+
3
+ const faker = require('faker');
4
+ const request = require('supertest');
5
+ const app = require('../../../app');
6
+ const sqldb = require('../../../models');
7
+
8
+ const { env: { adminKey } } = process;
9
+
10
+ describe('admin', () => {
11
+ const appName = faker.helpers.slugify(
12
+ faker.company.companyName(),
13
+ );
14
+ const newApp = {
15
+ name: appName,
16
+ packageName: `ti2-${appName}`,
17
+ adminEmail: faker.internet.email(),
18
+ };
19
+ let appKey;
20
+ const userId = '536830b6ed19afa44a000002';
21
+ afterAll(async () => {
22
+ await sqldb.sequelize.connectionManager.close();
23
+ });
24
+ it('should be able to create an app', async () => {
25
+ const resp = await request(app)
26
+ .post('/app')
27
+ .set('Authorization', `Bearer ${adminKey}`)
28
+ .send(newApp);
29
+ expect(resp.statusCode).toBe(200);
30
+ expect(resp.body.value).toBeTruthy();
31
+ appKey = resp.body.value;
32
+ });
33
+ it('the created app should be on the list of apps', async () => {
34
+ const resp = await request(app)
35
+ .get('/apps')
36
+ .set('Authorization', `Bearer ${adminKey}`);
37
+ expect(resp.statusCode).toBe(200);
38
+ const { body: { integrations } } = resp;
39
+ expect(integrations).toEqual(
40
+ expect.arrayContaining([
41
+ expect.objectContaining(newApp),
42
+ ]),
43
+ );
44
+ });
45
+ it('should be able to reset an app\'s key', async () => {
46
+ const url = `/app/resetAppKey/${newApp.name}`;
47
+ const resp = await request(app)
48
+ .get(url)
49
+ .set('Authorization', `Bearer ${adminKey}`);
50
+ expect(resp.statusCode).toBe(200);
51
+ const { body: { value } } = resp;
52
+ expect(value).toBeTruthy();
53
+ expect(value).not.toBe(appKey);
54
+ });
55
+ it.skip('should be able to create a new user authentication token', async () => {
56
+ const resp = await request(app).post('/user')
57
+ .set('Authorization', `Bearer ${adminKey}`)
58
+ .send({ userId });
59
+ expect(resp.statusCode).toBe(200);
60
+ });
61
+ });
@@ -0,0 +1,82 @@
1
+ /* globals describe it expect beforeAll, afterAll */
2
+
3
+ const faker = require('faker');
4
+ const request = require('supertest');
5
+ const jwt = require('jwt-promise');
6
+ const app = require('../../../app');
7
+ const sqldb = require('../../../models');
8
+
9
+ const { env: { adminKey, jwtSecret } } = process;
10
+
11
+ describe('app', () => {
12
+ const appName = faker.helpers.slugify(
13
+ faker.company.companyName(),
14
+ ).toLowerCase();
15
+ const newApp = {
16
+ name: appName,
17
+ packageName: `ti2-${appName}`,
18
+ adminEmail: faker.internet.email(),
19
+ };
20
+ let appKey;
21
+ const userId = faker.random.uuid();
22
+ const apiKey = faker.random.uuid();
23
+ // this token can be as long needed
24
+ const token = {
25
+ endpoint: faker.internet.url(),
26
+ apiKey,
27
+ };
28
+ const encodePayload = {
29
+ payload: { lorem: faker.lorem.paragraph() },
30
+ };
31
+ let encodedKey;
32
+ beforeAll(async () => {
33
+ const resp = await request(app)
34
+ .post('/app')
35
+ .set('Authorization', `Bearer ${adminKey}`)
36
+ .send(newApp);
37
+ expect(resp.statusCode).toBe(200);
38
+ expect(resp.body.value).toBeTruthy();
39
+ appKey = resp.body.value;
40
+ });
41
+ afterAll(async () => {
42
+ await sqldb.sequelize.connectionManager.close();
43
+ });
44
+ it('should encode an airbitrary object', async () => {
45
+ const resp = await request(app)
46
+ .put(`/app/encode/${appName}`)
47
+ .set('Authorization', `Bearer ${appKey}`)
48
+ .send({ payload: encodePayload });
49
+ expect(resp.statusCode).toBe(200);
50
+ expect(resp.body.value).toBeTruthy();
51
+ encodedKey = resp.body.value;
52
+ });
53
+ it('the encoded key should be decodable', async () => {
54
+ const decoded = await jwt.verify(encodedKey, `${appName}.${jwtSecret}`);
55
+ expect(decoded.payload).toEqual(expect.objectContaining(encodePayload));
56
+ });
57
+ it('should be able to create a user token for the app', async () => {
58
+ const resp = await request(app)
59
+ .post(`/${appName}/${userId}`)
60
+ .set('Authorization', `Bearer ${appKey}`)
61
+ .send({
62
+ tokenHint: apiKey.split('-')[0],
63
+ token,
64
+ });
65
+ expect(resp.statusCode).toBe(200);
66
+ });
67
+ it('should be able to get a list of all tokens related to the app', async () => {
68
+ const resp = await request(app)
69
+ .get(`/app/tokens/${appName}`)
70
+ .set('Authorization', `Bearer ${appKey}`);
71
+ expect(resp.statusCode).toBe(200);
72
+ expect(resp.body.userAppKeys).toEqual(
73
+ expect.arrayContaining([
74
+ expect.objectContaining({
75
+ hint: apiKey.split('-')[0],
76
+ userId,
77
+ integrationId: appName,
78
+ }),
79
+ ]),
80
+ );
81
+ });
82
+ });
@@ -0,0 +1,76 @@
1
+ /* globals describe it expect beforeAll, afterAll, afterEach, jest */
2
+
3
+ const { doApiGet, doApiPost } = require('../../../test/utils');
4
+
5
+ const { env: { adminKey } } = process;
6
+
7
+
8
+ const newApp = {
9
+ name: 'travelgate',
10
+ packageName: 'ti2-travelgate',
11
+ adminEmail: 'engineering+travelgate@tourconnect.com',
12
+ };
13
+ const appKey = newApp.name;
14
+ const userId = '551394be5ac58e5c76000019';
15
+ const newIntegration = {
16
+ tokenHint: 'testingToken',
17
+ token: {
18
+ endpoint: 'https://api.travelgatex.com',
19
+ apiKey: '8ca687f8-7968-4331-7b1a-dfcb276e5e44',
20
+ client: 'tourconnect',
21
+ },
22
+ };
23
+
24
+ describe('user: booking search', () => {
25
+ let userToken;
26
+ it('create the travelgate app', async () => {
27
+ // create the travelgate app
28
+ // get the list of existing
29
+ const { integrations } = await doApiGet({
30
+ url: '/apps',
31
+ token: adminKey,
32
+ });
33
+ if (!integrations.map(e => e.name).includes(newApp.name)) {
34
+ // creating the app
35
+ const { value: appKey } = await doApiPost({
36
+ url: '/app',
37
+ token: adminKey,
38
+ payload: newApp,
39
+ });
40
+ expect(appKey).toBeTruthy();
41
+ }
42
+ // create the user token
43
+ ({ value: userToken } = await doApiPost({
44
+ url: '/user',
45
+ token: adminKey,
46
+ payload: { userId },
47
+ }));
48
+ expect(userToken).toBeTruthy();
49
+ });
50
+ it('create the travelGage+User setup', async () => {
51
+ const { userAppKeys } = await doApiGet({
52
+ url: `/user/${userId}/apps`,
53
+ token: userToken,
54
+ });
55
+ if (!userAppKeys.map(e => e.integrationId).includes(newApp.name)) {
56
+ // relation does not exits
57
+ const { value } = await doApiPost({
58
+ url: `/${appKey}/${userId}`,
59
+ token: userToken,
60
+ payload: newIntegration,
61
+ });
62
+ expect(value).toBeTruthy();
63
+ }
64
+ });
65
+ it('should be able to search a travel gate for a booking', async () => {
66
+ const retVal = await doApiPost({
67
+ url: `/bookings/${appKey}/${userId}/search`,
68
+ token: userToken,
69
+ payload: {
70
+ bookingId: '', supplierId: '', name: '',
71
+ },
72
+ });
73
+ expect(Array.isArray(retVal.bookings)).toBeTruthy();
74
+ expect(retVal.bookings.length > 0).toBeTruthy();
75
+ });
76
+ });
@@ -0,0 +1,23 @@
1
+ /* global describe, it, expect */
2
+
3
+ // const should = require('should');
4
+ const request = require('supertest');
5
+ const server = require('../../../app');
6
+
7
+ describe('ping', () => {
8
+ it('should get a server pong', async () => {
9
+ const response = await request(server)
10
+ .get('/ping')
11
+ .set('Accept', 'application/json');
12
+ expect(response.headers['content-type']).toMatch(/json/);
13
+ expect(response.statusCode).toBe(200);
14
+ expect(response.body.error).toBeUndefined();
15
+ expect(Object.keys(response.body))
16
+ .toEqual(expect.arrayContaining([
17
+ 'name',
18
+ 'description',
19
+ 'version',
20
+ 'uptime',
21
+ ]));
22
+ });
23
+ });