@adobe/aio-cli-plugin-api-mesh 3.0.1 → 3.1.0-beta.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.
@@ -0,0 +1,783 @@
1
+ /*
2
+ Copyright 2021 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under
8
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ OF ANY KIND, either express or implied. See the License for the specific language
10
+ governing permissions and limitations under the License.
11
+ */
12
+
13
+ const RunCommand = require('../run');
14
+ const {
15
+ startGraphqlServer,
16
+ interpolateMesh,
17
+ importFiles,
18
+ promptConfirm,
19
+ } = require('../../../helpers');
20
+ require('@adobe-apimesh/mesh-builder');
21
+ jest.mock('../../../helpers', () => ({
22
+ initRequestId: jest.fn().mockResolvedValue({}),
23
+ startGraphqlServer: jest.fn().mockResolvedValue({}),
24
+ interpolateMesh: jest.fn().mockResolvedValue({}),
25
+ importFiles: jest.fn().mockResolvedValue(),
26
+ promptConfirm: jest.fn().mockResolvedValue(true),
27
+ }));
28
+
29
+ jest.mock('@adobe-apimesh/mesh-builder', () => {
30
+ return {
31
+ default: {
32
+ validateMesh: jest.fn().mockResolvedValue({}),
33
+ buildMesh: jest.fn().mockResolvedValue({}),
34
+ compileMesh: jest.fn().mockResolvedValue({}),
35
+ },
36
+ };
37
+ });
38
+
39
+ let logSpy = null;
40
+ let errorLogSpy = null;
41
+ let parseSpy = null;
42
+
43
+ const originalEnv = {
44
+ API_MESH_TIER: 'NON-TI',
45
+ };
46
+
47
+ const defaultPort = 5000;
48
+ describe('run command tests', () => {
49
+ beforeEach(() => {
50
+ global.requestId = 'dummy_request_id';
51
+
52
+ logSpy = jest.spyOn(RunCommand.prototype, 'log');
53
+ errorLogSpy = jest.spyOn(RunCommand.prototype, 'error');
54
+ parseSpy = jest.spyOn(RunCommand.prototype, 'parse');
55
+ process.env = {
56
+ ...originalEnv,
57
+ };
58
+ });
59
+
60
+ test('snapshot run command description', () => {
61
+ expect(RunCommand.description).toMatchInlineSnapshot(
62
+ `"Run a local development server that builds and compiles a mesh locally"`,
63
+ );
64
+ expect(RunCommand.summary).toMatchInlineSnapshot(`"Run local development server"`);
65
+ expect(RunCommand.args).toMatchInlineSnapshot(`
66
+ [
67
+ {
68
+ "description": "Mesh File",
69
+ "name": "file",
70
+ },
71
+ ]
72
+ `);
73
+
74
+ expect(RunCommand.flags).toMatchInlineSnapshot(`
75
+ {
76
+ "autoConfirmAction": {
77
+ "allowNo": false,
78
+ "char": "c",
79
+ "default": false,
80
+ "description": "Auto confirm action prompt. CLI will not check for user approval before executing the action.",
81
+ "parse": [Function],
82
+ "type": "boolean",
83
+ },
84
+ "debug": {
85
+ "allowNo": false,
86
+ "default": false,
87
+ "description": "Enable debugging mode",
88
+ "parse": [Function],
89
+ "type": "boolean",
90
+ },
91
+ "env": {
92
+ "char": "e",
93
+ "default": ".env",
94
+ "description": "Path to env file",
95
+ "input": [],
96
+ "multiple": false,
97
+ "parse": [Function],
98
+ "type": "option",
99
+ },
100
+ "port": {
101
+ "char": "p",
102
+ "description": "Port number for the local dev server",
103
+ "input": [],
104
+ "multiple": false,
105
+ "parse": [Function],
106
+ "type": "option",
107
+ },
108
+ }
109
+ `);
110
+ expect(RunCommand.aliases).toMatchInlineSnapshot(`[]`);
111
+ });
112
+
113
+ test('should fail if mesh file is not provided', async () => {
114
+ parseSpy.mockResolvedValue({
115
+ args: {},
116
+ flags: {},
117
+ });
118
+
119
+ const runResult = RunCommand.run();
120
+ await expect(runResult).rejects.toEqual(
121
+ new Error('Missing file path. Run aio api-mesh run --help for more info.'),
122
+ );
123
+ expect(logSpy.mock.calls).toMatchInlineSnapshot(`[]`);
124
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`[]`);
125
+ });
126
+
127
+ test('should use the port number provided in the flags for starting the server', async () => {
128
+ const parseOutput = {
129
+ args: { file: 'src/commands/__fixtures__/sample_mesh.json' },
130
+ flags: { port: 6000, debug: false },
131
+ };
132
+
133
+ parseSpy.mockResolvedValue(parseOutput);
134
+
135
+ await RunCommand.run();
136
+ expect(startGraphqlServer).toHaveBeenCalledWith(
137
+ expect.anything(),
138
+ parseOutput.flags.port,
139
+ false,
140
+ );
141
+ });
142
+
143
+ test('should use the port number provided in the .env file if there is no port', async () => {
144
+ process.env = {
145
+ ...originalEnv,
146
+ PORT: 7000,
147
+ };
148
+
149
+ const parseOutput = {
150
+ args: { file: 'src/commands/__fixtures__/sample_mesh.json' },
151
+ flags: { debug: false },
152
+ };
153
+
154
+ parseSpy.mockResolvedValue(parseOutput);
155
+
156
+ await RunCommand.run();
157
+ expect(startGraphqlServer).toHaveBeenCalledWith(expect.anything(), process.env.PORT, false);
158
+ });
159
+
160
+ test('should use the default port if port number is not provided explicitly', async () => {
161
+ process.env = {
162
+ ...originalEnv,
163
+ };
164
+
165
+ const parseOutput = {
166
+ args: { file: 'src/commands/__fixtures__/sample_mesh.json' },
167
+ flags: { debug: false },
168
+ };
169
+
170
+ parseSpy.mockResolvedValue(parseOutput);
171
+
172
+ await RunCommand.run();
173
+ expect(startGraphqlServer).toHaveBeenCalledWith(expect.anything(), defaultPort, false);
174
+ });
175
+
176
+ test('should return error for run command if the mesh has placeholders and env file provided using --env flag is not found', async () => {
177
+ parseSpy.mockResolvedValueOnce({
178
+ args: { file: 'src/commands/__fixtures__/sample_mesh_with_placeholder' },
179
+ flags: {
180
+ env: 'src/commands/__fixtures__/.env_nonExisting',
181
+ },
182
+ });
183
+ const runResult = RunCommand.run();
184
+
185
+ await expect(runResult).rejects.toEqual(
186
+ new Error(
187
+ 'Unable to read the file src/commands/__fixtures__/.env_nonExisting. Please check the file and try again.',
188
+ ),
189
+ );
190
+
191
+ expect(logSpy.mock.calls).toMatchInlineSnapshot(`
192
+ [
193
+ [
194
+ "The provided mesh contains placeholders. Starting mesh interpolation process.",
195
+ ],
196
+ [
197
+ "ENOENT: no such file or directory, open 'src/commands/__fixtures__/.env_nonExisting'",
198
+ ],
199
+ ]
200
+ `);
201
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
202
+ [
203
+ [
204
+ "Unable to read the file src/commands/__fixtures__/.env_nonExisting. Please check the file and try again.",
205
+ ],
206
+ [
207
+ "Unable to read the file src/commands/__fixtures__/.env_nonExisting. Please check the file and try again.",
208
+ ],
209
+ ]
210
+ `);
211
+ });
212
+
213
+ test('should return error for run command if mesh has placeholders and the provided env file is invalid', async () => {
214
+ parseSpy.mockResolvedValueOnce({
215
+ args: { file: 'src/commands/__fixtures__/sample_mesh_with_placeholder' },
216
+ flags: {
217
+ env: 'src/commands/__fixtures__/env_invalid',
218
+ },
219
+ });
220
+
221
+ const runResult = RunCommand.run();
222
+
223
+ await expect(runResult).rejects.toEqual(
224
+ new Error(
225
+ "Issue in src/commands/__fixtures__/env_invalid file - Duplicate key << key1 >> on line 3,Invalid format for key/value << key2=='value3' >> on line 5,Invalid format << key3 >> on line 6,Invalid format for key/value << key4='value4 >> on line 7",
226
+ ),
227
+ );
228
+
229
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
230
+ [
231
+ [
232
+ "Issue in src/commands/__fixtures__/env_invalid file - Duplicate key << key1 >> on line 3,Invalid format for key/value << key2=='value3' >> on line 5,Invalid format << key3 >> on line 6,Invalid format for key/value << key4='value4 >> on line 7",
233
+ ],
234
+ [
235
+ "Issue in src/commands/__fixtures__/env_invalid file - Duplicate key << key1 >> on line 3,Invalid format for key/value << key2=='value3' >> on line 5,Invalid format << key3 >> on line 6,Invalid format for key/value << key4='value4 >> on line 7",
236
+ ],
237
+ ]
238
+ `);
239
+ });
240
+
241
+ test('should return error for run command if the mesh has placeholders and the provided env file is valid but there are missing keys found in mesh interpolation', async () => {
242
+ parseSpy.mockResolvedValueOnce({
243
+ args: { file: 'src/commands/__fixtures__/sample_mesh_with_placeholder' },
244
+ flags: {
245
+ env: 'src/commands/__fixtures__/env_valid',
246
+ },
247
+ });
248
+
249
+ interpolateMesh.mockResolvedValueOnce({
250
+ interpolationStatus: 'failed',
251
+ missingKeys: ['newKey1', 'newKey2'],
252
+ interpolatedMesh: '',
253
+ });
254
+
255
+ const runResult = RunCommand.run();
256
+ await expect(runResult).rejects.toEqual(
257
+ new Error('The mesh file cannot be interpolated due to missing keys : newKey1 , newKey2'),
258
+ );
259
+
260
+ await expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
261
+ [
262
+ [
263
+ "The mesh file cannot be interpolated due to missing keys : newKey1 , newKey2",
264
+ ],
265
+ [
266
+ "The mesh file cannot be interpolated due to missing keys : newKey1 , newKey2",
267
+ ],
268
+ ]
269
+ `);
270
+ });
271
+
272
+ test('should return error for run command if the provided env file is valid and mesh interpolation is successful but interpolated mesh is not a valid JSON', async () => {
273
+ parseSpy.mockResolvedValueOnce({
274
+ args: { file: 'src/commands/__fixtures__/sample_mesh_with_placeholder' },
275
+ flags: {
276
+ env: 'src/commands/__fixtures__/env_valid',
277
+ },
278
+ });
279
+
280
+ //sampleInterpolated mesh where value of responseConfig.includeHTTPDetails is invalid i.e. non-boolean
281
+ const sampleInterpolatedMesh =
282
+ '{"meshConfig":{"sources":[{"name":"<api-name>","handler":{"graphql":{"endpoint":"<api-url>"}}}],"responseConfig":{"includeHTTPDetails":sample}}}';
283
+
284
+ interpolateMesh.mockResolvedValueOnce({
285
+ interpolationStatus: 'success',
286
+ missingKeys: [],
287
+ interpolatedMeshData: sampleInterpolatedMesh,
288
+ });
289
+
290
+ const runResult = RunCommand.run();
291
+ await expect(runResult).rejects.toEqual(
292
+ new Error('Interpolated mesh is not a valid JSON. Please check the generated json file.'),
293
+ );
294
+
295
+ await expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
296
+ [
297
+ [
298
+ "Interpolated mesh is not a valid JSON. Please check the generated json file.",
299
+ ],
300
+ [
301
+ "Interpolated mesh is not a valid JSON. Please check the generated json file.",
302
+ ],
303
+ ]
304
+ `);
305
+ });
306
+
307
+ test('should successfully run the mesh if provided env file is valid, mesh interpolation is successful and interpolated mesh is a valid JSON', async () => {
308
+ parseSpy.mockResolvedValueOnce({
309
+ args: { file: 'src/commands/__fixtures__/sample_mesh_with_placeholder' },
310
+ flags: {
311
+ env: 'src/commands/__fixtures__/env_valid',
312
+ debug: false,
313
+ },
314
+ });
315
+
316
+ //sampleInterpolated mesh where the mesh string is a valid JSON
317
+ const sampleInterpolatedMesh =
318
+ '{"meshConfig":{"sources":[{"name":"<api-name>","handler":{"graphql":{"endpoint":"<api-url>"}}}],"responseConfig":{"includeHTTPDetails":true}}}';
319
+
320
+ interpolateMesh.mockResolvedValueOnce({
321
+ interpolationStatus: 'success',
322
+ missingKeys: [],
323
+ interpolatedMeshData: sampleInterpolatedMesh,
324
+ });
325
+
326
+ await RunCommand.run();
327
+ expect(startGraphqlServer).toHaveBeenCalledWith(expect.anything(), defaultPort, false);
328
+ });
329
+
330
+ // file import tests
331
+ test('should pass if there are local files in meshConfig i.e., the file is appended in files array', async () => {
332
+ let meshConfig = {
333
+ sources: [
334
+ {
335
+ name: '<json_source_name>',
336
+ handler: {
337
+ JsonSchema: {
338
+ baseUrl: '<json_source__baseurl>',
339
+ operations: [
340
+ {
341
+ type: 'Query',
342
+ field: '<query>',
343
+ path: '<query_path>',
344
+ method: 'POST',
345
+ requestSchema: './requestParams.json',
346
+ },
347
+ ],
348
+ },
349
+ },
350
+ },
351
+ ],
352
+ files: [
353
+ {
354
+ path: './requestParams.json',
355
+ content: '{"type":"updatedContent"}',
356
+ },
357
+ ],
358
+ };
359
+
360
+ parseSpy.mockResolvedValueOnce({
361
+ args: { file: 'src/commands/__fixtures__/sample_mesh_files.json' },
362
+ flags: {
363
+ autoConfirmAction: Promise.resolve(true),
364
+ debug: false,
365
+ },
366
+ });
367
+
368
+ importFiles.mockResolvedValueOnce({
369
+ meshConfig,
370
+ });
371
+
372
+ await RunCommand.run();
373
+ expect(startGraphqlServer).toHaveBeenCalledWith(expect.anything(), defaultPort, false);
374
+ });
375
+
376
+ test('should fail if the file name is more than 25 characters', async () => {
377
+ parseSpy.mockResolvedValueOnce({
378
+ args: { file: 'src/commands/__fixtures__/sample_mesh_invalid_file_name.json' },
379
+ flags: {
380
+ autoConfirmAction: Promise.resolve(false),
381
+ },
382
+ });
383
+
384
+ const output = RunCommand.run();
385
+
386
+ await expect(output).rejects.toEqual(new Error('Input mesh config is not valid.'));
387
+
388
+ expect(logSpy.mock.calls).toMatchInlineSnapshot(`
389
+ [
390
+ [
391
+ "Mesh file names must be less than 25 characters. The following file(s) are invalid: requestJSONParameters.json.",
392
+ ],
393
+ ]
394
+ `);
395
+
396
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
397
+ [
398
+ [
399
+ "Input mesh config is not valid.",
400
+ ],
401
+ ]
402
+ `);
403
+ });
404
+
405
+ test('should fail if the file is of type other than js, json extension', async () => {
406
+ parseSpy.mockResolvedValueOnce({
407
+ args: { file: 'src/commands/__fixtures__/sample_mesh_invalid_type.json' },
408
+ flags: {
409
+ autoConfirmAction: Promise.resolve(false),
410
+ },
411
+ });
412
+
413
+ const output = RunCommand.run();
414
+
415
+ await expect(output).rejects.toEqual(new Error('Input mesh config is not valid.'));
416
+
417
+ expect(logSpy.mock.calls).toMatchInlineSnapshot(`
418
+ [
419
+ [
420
+ "Mesh files must be JavaScript or JSON. Other file types are not supported. The following file(s) are invalid: requestParams.txt.",
421
+ ],
422
+ ]
423
+ `);
424
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
425
+ [
426
+ [
427
+ "Input mesh config is not valid.",
428
+ ],
429
+ ]
430
+ `);
431
+ });
432
+
433
+ test('should fail if the files do not exist in the mesh directory or subdirectory', async () => {
434
+ parseSpy.mockResolvedValueOnce({
435
+ args: { file: 'src/commands/__fixtures__/sample_mesh_invalid_paths.json' },
436
+ flags: {
437
+ autoConfirmAction: Promise.resolve(false),
438
+ },
439
+ });
440
+
441
+ importFiles.mockImplementation(() => {
442
+ throw new Error(
443
+ 'Please make sure the files: schemaBody.json and sample_mesh_invalid_paths.json are in the same directory/subdirectory.',
444
+ );
445
+ });
446
+
447
+ const output = RunCommand.run();
448
+ await expect(output).rejects.toEqual(
449
+ new Error(
450
+ 'Unable to import the files in the mesh config. Please check the file and try again.',
451
+ ),
452
+ );
453
+
454
+ expect(logSpy.mock.calls).toMatchInlineSnapshot(`
455
+ [
456
+ [
457
+ "Please make sure the files: schemaBody.json and sample_mesh_invalid_paths.json are in the same directory/subdirectory.",
458
+ ],
459
+ ]
460
+ `);
461
+
462
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
463
+ [
464
+ [
465
+ "Unable to import the files in the mesh config. Please check the file and try again.",
466
+ ],
467
+ ]
468
+ `);
469
+ });
470
+
471
+ test('should fail if import files function fails', async () => {
472
+ parseSpy.mockResolvedValueOnce({
473
+ args: { file: 'src/commands/__fixtures__/sample_mesh_files.json' },
474
+ flags: {
475
+ autoConfirmAction: Promise.resolve(false),
476
+ },
477
+ });
478
+
479
+ importFiles.mockImplementation(() => {
480
+ throw new Error('Error reading the file');
481
+ });
482
+
483
+ const output = RunCommand.run();
484
+
485
+ await expect(output).rejects.toEqual(
486
+ new Error(
487
+ 'Unable to import the files in the mesh config. Please check the file and try again.',
488
+ ),
489
+ );
490
+
491
+ expect(logSpy.mock.calls).toMatchInlineSnapshot(`
492
+ [
493
+ [
494
+ "Error reading the file",
495
+ ],
496
+ ]
497
+ `);
498
+
499
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
500
+ [
501
+ [
502
+ "Unable to import the files in the mesh config. Please check the file and try again.",
503
+ ],
504
+ ]
505
+ `);
506
+ });
507
+
508
+ test('should not override if prompt returns No, if there is files array', async () => {
509
+ let meshConfig = {
510
+ sources: [
511
+ {
512
+ name: '<json_source_name>',
513
+ handler: {
514
+ JsonSchema: {
515
+ baseUrl: '<json_source__baseurl>',
516
+ operations: [
517
+ {
518
+ type: 'Query',
519
+ field: '<query>',
520
+ path: '<query_path>',
521
+ method: 'POST',
522
+ requestSchema: './requestParams.json',
523
+ },
524
+ ],
525
+ },
526
+ },
527
+ },
528
+ ],
529
+ files: [
530
+ {
531
+ path: './requestParams.json',
532
+ content: '{"type":"dummyContent"}',
533
+ },
534
+ ],
535
+ };
536
+
537
+ promptConfirm.mockResolvedValueOnce(false).mockResolvedValueOnce(true);
538
+
539
+ importFiles.mockResolvedValueOnce(meshConfig);
540
+
541
+ parseSpy.mockResolvedValueOnce({
542
+ args: { file: 'src/commands/__fixtures__/sample_mesh_with_files_array.json' },
543
+ flags: {
544
+ debug: false,
545
+ },
546
+ });
547
+
548
+ await RunCommand.run();
549
+ expect(startGraphqlServer).toHaveBeenCalledWith(expect.anything(), defaultPort, false);
550
+ });
551
+
552
+ test('should override if prompt returns Yes, if there is files array', async () => {
553
+ let meshConfig = {
554
+ sources: [
555
+ {
556
+ name: '<json_source_name>',
557
+ handler: {
558
+ JsonSchema: {
559
+ baseUrl: '<json_source__baseurl>',
560
+ operations: [
561
+ {
562
+ type: 'Query',
563
+ field: '<query>',
564
+ path: '<query_path>',
565
+ method: 'POST',
566
+ requestSchema: './requestParams.json',
567
+ },
568
+ ],
569
+ },
570
+ },
571
+ },
572
+ ],
573
+ files: [
574
+ {
575
+ path: './requestParams.json',
576
+ content: '{"type":"updatedContent"}',
577
+ },
578
+ ],
579
+ };
580
+
581
+ promptConfirm.mockResolvedValueOnce(true).mockResolvedValueOnce(true);
582
+
583
+ parseSpy.mockResolvedValueOnce({
584
+ args: { file: 'src/commands/__fixtures__/sample_mesh_with_files_array.json' },
585
+ flags: {
586
+ debug: false,
587
+ },
588
+ });
589
+
590
+ importFiles.mockResolvedValueOnce({
591
+ meshConfig,
592
+ });
593
+
594
+ await RunCommand.run();
595
+
596
+ expect(startGraphqlServer).toHaveBeenCalledWith(expect.anything(), defaultPort, false);
597
+ });
598
+
599
+ test('should pass for a fully-qualified meshConfig even if the file does not exist in fileSystem', async () => {
600
+ let meshConfig = {
601
+ sources: [
602
+ {
603
+ name: '<json_source_name>',
604
+ handler: {
605
+ JsonSchema: {
606
+ baseUrl: '<json_source__baseurl>',
607
+ operations: [
608
+ {
609
+ type: 'Query',
610
+ field: '<query>',
611
+ path: '<query_path>',
612
+ method: 'POST',
613
+ requestSchema: './schemaBody.json',
614
+ },
615
+ ],
616
+ },
617
+ },
618
+ },
619
+ ],
620
+ files: [
621
+ {
622
+ path: './schemaBody.json',
623
+ content: '{"type":"dummyContent"}',
624
+ },
625
+ ],
626
+ };
627
+
628
+ parseSpy.mockResolvedValueOnce({
629
+ args: { file: 'src/commands/__fixtures__/sample_fully_qualified_mesh.json' },
630
+ flags: {
631
+ autoConfirmAction: Promise.resolve(true),
632
+ debug: false,
633
+ },
634
+ });
635
+
636
+ promptConfirm.mockResolvedValueOnce(true);
637
+
638
+ importFiles.mockResolvedValueOnce({
639
+ meshConfig,
640
+ });
641
+
642
+ await RunCommand.run();
643
+ expect(startGraphqlServer).toHaveBeenCalledWith(expect.anything(), defaultPort, false);
644
+ });
645
+
646
+ test('should pass if the file is located in subdirectory of mesh directory', async () => {
647
+ let meshConfig = {
648
+ sources: [
649
+ {
650
+ name: '<json_source_name>',
651
+ handler: {
652
+ JsonSchema: {
653
+ baseUrl: '<json_source__baseurl>',
654
+ operations: [
655
+ {
656
+ type: 'Query',
657
+ field: '<query>',
658
+ path: '<query_path>',
659
+ method: 'POST',
660
+ requestSchema: './files/requestParams.json',
661
+ },
662
+ ],
663
+ },
664
+ },
665
+ },
666
+ ],
667
+ files: [
668
+ {
669
+ path: './files/requestParams.json',
670
+ content: '{"type":"updatedContent"}',
671
+ },
672
+ ],
673
+ };
674
+
675
+ parseSpy.mockResolvedValueOnce({
676
+ args: { file: 'src/commands/__fixtures__/sample_mesh_subdirectory.json' },
677
+ flags: {
678
+ autoConfirmAction: Promise.resolve(true),
679
+ debug: false,
680
+ },
681
+ });
682
+
683
+ importFiles.mockResolvedValueOnce({
684
+ meshConfig,
685
+ });
686
+
687
+ await RunCommand.run();
688
+
689
+ expect(startGraphqlServer).toHaveBeenCalledWith(expect.anything(), defaultPort, false);
690
+ });
691
+
692
+ test('should fail if the file is outside the workspace directory', async () => {
693
+ parseSpy.mockResolvedValueOnce({
694
+ args: { file: 'src/commands/__fixtures__/sample_mesh_outside_workspace_dir.json' },
695
+ flags: {
696
+ debug: false,
697
+ autoConfirmAction: Promise.resolve(false),
698
+ },
699
+ });
700
+
701
+ const output = RunCommand.run();
702
+
703
+ await expect(output).rejects.toEqual(new Error('Input mesh config is not valid.'));
704
+ expect(logSpy.mock.calls).toMatchInlineSnapshot(`
705
+ [
706
+ [
707
+ "File(s): requestParams.json is outside the mesh directory.",
708
+ ],
709
+ ]
710
+ `);
711
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
712
+ [
713
+ [
714
+ "Input mesh config is not valid.",
715
+ ],
716
+ ]
717
+ `);
718
+ });
719
+
720
+ test('should fail if the file has invalid JSON content', async () => {
721
+ parseSpy.mockResolvedValueOnce({
722
+ args: { file: 'src/commands/__fixtures__/sample_mesh_invalid_file_content.json' },
723
+ flags: {
724
+ autoConfirmAction: Promise.resolve(false),
725
+ },
726
+ });
727
+
728
+ importFiles.mockImplementation(() => {
729
+ throw new Error('Invalid JSON content in openapi-schema.json');
730
+ });
731
+
732
+ const output = RunCommand.run();
733
+
734
+ await expect(output).rejects.toEqual(
735
+ new Error(
736
+ 'Unable to import the files in the mesh config. Please check the file and try again.',
737
+ ),
738
+ );
739
+
740
+ expect(logSpy.mock.calls).toMatchInlineSnapshot(`
741
+ [
742
+ [
743
+ "Invalid JSON content in openapi-schema.json",
744
+ ],
745
+ ]
746
+ `);
747
+
748
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
749
+ [
750
+ [
751
+ "Unable to import the files in the mesh config. Please check the file and try again.",
752
+ ],
753
+ ]
754
+ `);
755
+ });
756
+
757
+ test('should fail if the file path starts from home directory i.e., path starts with ~/', async () => {
758
+ parseSpy.mockResolvedValueOnce({
759
+ args: { file: 'src/commands/__fixtures__/sample_mesh_path_from_home.json' },
760
+ flags: {
761
+ autoConfirmAction: Promise.resolve(false),
762
+ },
763
+ });
764
+
765
+ const output = RunCommand.run();
766
+
767
+ await expect(output).rejects.toEqual(new Error('Input mesh config is not valid.'));
768
+ expect(logSpy.mock.calls).toMatchInlineSnapshot(`
769
+ [
770
+ [
771
+ "File(s): venia-openapi-schema.json is outside the mesh directory.",
772
+ ],
773
+ ]
774
+ `);
775
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
776
+ [
777
+ [
778
+ "Input mesh config is not valid.",
779
+ ],
780
+ ]
781
+ `);
782
+ });
783
+ });