@adobe/aio-cli-plugin-api-mesh 2.2.0 → 2.3.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.
Files changed (33) hide show
  1. package/oclif.manifest.json +1 -1
  2. package/package.json +2 -1
  3. package/src/commands/__fixtures__/files/requestParams.json +3 -0
  4. package/src/commands/__fixtures__/openapi-schema.json +4 -0
  5. package/src/commands/__fixtures__/requestParams.json +3 -0
  6. package/src/commands/__fixtures__/sample_fully_qualified_mesh.json +29 -0
  7. package/src/commands/__fixtures__/sample_invalid_mesh.txt +17 -0
  8. package/src/commands/__fixtures__/sample_mesh_files.json +23 -0
  9. package/src/commands/__fixtures__/sample_mesh_invalid_file_content.json +14 -0
  10. package/src/commands/__fixtures__/sample_mesh_invalid_file_name.json +27 -0
  11. package/src/commands/__fixtures__/sample_mesh_invalid_paths.json +23 -0
  12. package/src/commands/__fixtures__/sample_mesh_invalid_type.json +27 -0
  13. package/src/commands/__fixtures__/sample_mesh_mismatching_path.json +29 -0
  14. package/src/commands/__fixtures__/sample_mesh_outside_workspace_dir.json +23 -0
  15. package/src/commands/__fixtures__/sample_mesh_path_from_home.json +14 -0
  16. package/src/commands/__fixtures__/sample_mesh_subdirectory.json +23 -0
  17. package/src/commands/__fixtures__/sample_mesh_with_files_array.json +29 -0
  18. package/src/commands/api-mesh/__tests__/create.test.js +1000 -31
  19. package/src/commands/api-mesh/__tests__/get.test.js +8 -0
  20. package/src/commands/api-mesh/__tests__/init.test.js +390 -0
  21. package/src/commands/api-mesh/__tests__/update.test.js +419 -4
  22. package/src/commands/api-mesh/create.js +37 -68
  23. package/src/commands/api-mesh/get.js +7 -2
  24. package/src/commands/api-mesh/init.js +168 -0
  25. package/src/commands/api-mesh/source/__tests__/get.test.js +1 -1
  26. package/src/commands/api-mesh/source/__tests__/install.test.js +2 -2
  27. package/src/commands/api-mesh/update.js +35 -67
  28. package/src/helpers.js +249 -91
  29. package/src/lib/devConsole.js +1 -2
  30. package/src/templates/gitignore +1 -0
  31. package/src/templates/package.json +38 -0
  32. package/src/utils.js +329 -31
  33. package/src/meshInterpolation.js +0 -120
@@ -14,15 +14,19 @@ const mockConsoleCLIInstance = {};
14
14
 
15
15
  const CreateCommand = require('../create');
16
16
  const sampleCreateMeshConfig = require('../../__fixtures__/sample_mesh.json');
17
- const { initSdk, initRequestId, promptConfirm } = require('../../../helpers');
17
+ const {
18
+ initSdk,
19
+ initRequestId,
20
+ promptConfirm,
21
+ interpolateMesh,
22
+ importFiles,
23
+ } = require('../../../helpers');
18
24
  const {
19
25
  createMesh,
20
26
  createAPIMeshCredentials,
21
27
  subscribeCredentialToMeshService,
22
28
  } = require('../../../lib/devConsole');
23
29
 
24
- const meshInterpolation = require('../../../meshInterpolation');
25
-
26
30
  const selectedOrg = { id: '1234', code: 'CODE1234@AdobeOrg', name: 'ORG01', type: 'entp' };
27
31
 
28
32
  const selectedProject = { id: '5678', title: 'Project01' };
@@ -42,7 +46,8 @@ jest.mock('../../../helpers', () => ({
42
46
  initSdk: jest.fn().mockResolvedValue({}),
43
47
  initRequestId: jest.fn().mockResolvedValue({}),
44
48
  promptConfirm: jest.fn().mockResolvedValue(true),
45
- getname: jest.fn().mockResolvedValue({}),
49
+ interpolateMesh: jest.fn().mockResolvedValue({}),
50
+ importFiles: jest.fn().mockResolvedValue(),
46
51
  }));
47
52
  jest.mock('../../../lib/devConsole');
48
53
 
@@ -127,6 +132,7 @@ describe('create command tests', () => {
127
132
  },
128
133
  "env": {
129
134
  "char": "e",
135
+ "default": ".env",
130
136
  "description": "Path to env file",
131
137
  "input": [],
132
138
  "multiple": false,
@@ -310,19 +316,14 @@ describe('create command tests', () => {
310
316
  },
311
317
  });
312
318
  const runResult = CreateCommand.run();
319
+ const expected = [expect.stringMatching(/ENOENT: no such file or directory/)];
313
320
 
314
321
  await expect(runResult).rejects.toEqual(
315
322
  new Error(
316
323
  'Unable to read the mesh configuration file provided. Please check the file and try again.',
317
324
  ),
318
325
  );
319
- expect(logSpy.mock.calls).toMatchInlineSnapshot(`
320
- [
321
- [
322
- "ENOENT: no such file or directory, open 'dummy_file_path'",
323
- ],
324
- ]
325
- `);
326
+ expect(logSpy.mock.calls[0]).toEqual(expect.arrayContaining(expected));
326
327
  expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
327
328
  [
328
329
  [
@@ -510,9 +511,9 @@ describe('create command tests', () => {
510
511
  );
511
512
  });
512
513
 
513
- test('should return error if the env file provided using --env flag is not found', async () => {
514
+ test('should return error if the mesh has placeholders and env file provided using --env flag is not found', async () => {
514
515
  parseSpy.mockResolvedValueOnce({
515
- args: { file: 'src/commands/__fixtures__/sample_mesh.json' },
516
+ args: { file: 'src/commands/__fixtures__/sample_mesh_with_placeholder' },
516
517
  flags: {
517
518
  ignoreCache: mockIgnoreCacheFlag,
518
519
  autoConfirmAction: Promise.resolve(true),
@@ -522,11 +523,16 @@ describe('create command tests', () => {
522
523
  const runResult = CreateCommand.run();
523
524
 
524
525
  await expect(runResult).rejects.toEqual(
525
- new Error('Unable to read the env file provided. Please check the file and try again.'),
526
+ new Error(
527
+ 'Unable to read the file src/commands/__fixtures__/.env_nonExisting. Please check the file and try again.',
528
+ ),
526
529
  );
527
530
 
528
531
  expect(logSpy.mock.calls).toMatchInlineSnapshot(`
529
532
  [
533
+ [
534
+ "The provided mesh contains placeholders. Starting mesh interpolation process.",
535
+ ],
530
536
  [
531
537
  "ENOENT: no such file or directory, open 'src/commands/__fixtures__/.env_nonExisting'",
532
538
  ],
@@ -535,15 +541,15 @@ describe('create command tests', () => {
535
541
  expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
536
542
  [
537
543
  [
538
- "Unable to read the env file provided. Please check the file and try again.",
544
+ "Unable to read the file src/commands/__fixtures__/.env_nonExisting. Please check the file and try again.",
539
545
  ],
540
546
  ]
541
547
  `);
542
548
  });
543
549
 
544
- test('should return error if the provided env file is invalid', async () => {
550
+ test('should return error if mesh has placeholders and the provided env file is invalid', async () => {
545
551
  parseSpy.mockResolvedValueOnce({
546
- args: { file: 'src/commands/__fixtures__/sample_mesh.json' },
552
+ args: { file: 'src/commands/__fixtures__/sample_mesh_with_placeholder' },
547
553
  flags: {
548
554
  ignoreCache: mockIgnoreCacheFlag,
549
555
  autoConfirmAction: Promise.resolve(true),
@@ -568,9 +574,9 @@ describe('create command tests', () => {
568
574
  `);
569
575
  });
570
576
 
571
- test('should return error if the provided env file is valid but there are missing keys found in mesh interpolation', async () => {
577
+ test('should return error if the mesh has placeholders and the provided env file is valid but there are missing keys found in mesh interpolation', async () => {
572
578
  parseSpy.mockResolvedValueOnce({
573
- args: { file: 'src/commands/__fixtures__/sample_mesh.json' },
579
+ args: { file: 'src/commands/__fixtures__/sample_mesh_with_placeholder' },
574
580
  flags: {
575
581
  ignoreCache: mockIgnoreCacheFlag,
576
582
  autoConfirmAction: Promise.resolve(true),
@@ -578,22 +584,21 @@ describe('create command tests', () => {
578
584
  },
579
585
  });
580
586
 
581
- const interpolateMeshFunc = jest.spyOn(meshInterpolation, 'interpolateMesh');
582
- interpolateMeshFunc.mockResolvedValueOnce({
587
+ interpolateMesh.mockResolvedValueOnce({
583
588
  interpolationStatus: 'failed',
584
- missingKeys: ['newKey1', 'newKey2', 'newKey1'],
589
+ missingKeys: ['newKey1', 'newKey2'],
585
590
  interpolatedMesh: '',
586
591
  });
587
592
 
588
593
  const runResult = CreateCommand.run();
589
594
  await expect(runResult).rejects.toEqual(
590
- new Error('The mesh file cannot be interpolated due to missing keys : newKey1,newKey2'),
595
+ new Error('The mesh file cannot be interpolated due to missing keys : newKey1 , newKey2'),
591
596
  );
592
597
 
593
598
  await expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
594
599
  [
595
600
  [
596
- "The mesh file cannot be interpolated due to missing keys : newKey1,newKey2",
601
+ "The mesh file cannot be interpolated due to missing keys : newKey1 , newKey2",
597
602
  ],
598
603
  ]
599
604
  `);
@@ -601,7 +606,7 @@ describe('create command tests', () => {
601
606
 
602
607
  test('should return error if the provided env file is valid and mesh interpolation is successful but interpolated mesh is not a valid JSON', async () => {
603
608
  parseSpy.mockResolvedValueOnce({
604
- args: { file: 'src/commands/__fixtures__/sample_mesh.json' },
609
+ args: { file: 'src/commands/__fixtures__/sample_mesh_with_placeholder' },
605
610
  flags: {
606
611
  ignoreCache: mockIgnoreCacheFlag,
607
612
  autoConfirmAction: Promise.resolve(true),
@@ -613,8 +618,7 @@ describe('create command tests', () => {
613
618
  const sampleInterpolatedMesh =
614
619
  '{"meshConfig":{"sources":[{"name":"<api-name>","handler":{"graphql":{"endpoint":"<api-url>"}}}],"responseConfig":{"includeHTTPDetails":sample}}}';
615
620
 
616
- const interpolateMeshFunc = jest.spyOn(meshInterpolation, 'interpolateMesh');
617
- interpolateMeshFunc.mockResolvedValueOnce({
621
+ interpolateMesh.mockResolvedValueOnce({
618
622
  interpolationStatus: 'success',
619
623
  missingKeys: [],
620
624
  interpolatedMeshData: sampleInterpolatedMesh,
@@ -636,7 +640,7 @@ describe('create command tests', () => {
636
640
 
637
641
  test('should successfully create a mesh if provided env file is valid, mesh interpolation is successful and interpolated mesh is a valid JSON', async () => {
638
642
  parseSpy.mockResolvedValue({
639
- args: { file: 'src/commands/__fixtures__/sample_mesh.json' },
643
+ args: { file: 'src/commands/__fixtures__/sample_mesh_with_placeholder' },
640
644
  flags: {
641
645
  ignoreCache: mockIgnoreCacheFlag,
642
646
  autoConfirmAction: mockAutoApproveAction,
@@ -648,8 +652,7 @@ describe('create command tests', () => {
648
652
  const sampleInterpolatedMesh =
649
653
  '{"meshConfig":{"sources":[{"name":"<api-name>","handler":{"graphql":{"endpoint":"<api-url>"}}}],"responseConfig":{"includeHTTPDetails":true}}}';
650
654
 
651
- const interpolateMeshFunc = jest.spyOn(meshInterpolation, 'interpolateMesh');
652
- interpolateMeshFunc.mockResolvedValueOnce({
655
+ interpolateMesh.mockResolvedValueOnce({
653
656
  interpolationStatus: 'success',
654
657
  missingKeys: [],
655
658
  interpolatedMeshData: sampleInterpolatedMesh,
@@ -688,7 +691,7 @@ describe('create command tests', () => {
688
691
 
689
692
  test('should return error if inputMesh is not a valid JSON', async () => {
690
693
  parseSpy.mockResolvedValue({
691
- args: { file: 'src/commands/__fixtures__/sample_mesh_with_placeholder' },
694
+ args: { file: 'src/commands/__fixtures__/sample_invalid_mesh.txt' },
692
695
  flags: {
693
696
  ignoreCache: mockIgnoreCacheFlag,
694
697
  autoConfirmAction: mockAutoApproveAction,
@@ -708,4 +711,970 @@ describe('create command tests', () => {
708
711
  ]
709
712
  `);
710
713
  });
714
+
715
+ test('should pass if there are local files in meshConfig i.e., the file is appended in files array', async () => {
716
+ let meshConfig = {
717
+ sources: [
718
+ {
719
+ name: '<json_source_name>',
720
+ handler: {
721
+ JsonSchema: {
722
+ baseUrl: '<json_source__baseurl>',
723
+ operations: [
724
+ {
725
+ type: 'Query',
726
+ field: '<query>',
727
+ path: '<query_path>',
728
+ method: 'POST',
729
+ requestSchema: './requestParams.json',
730
+ },
731
+ ],
732
+ },
733
+ },
734
+ },
735
+ ],
736
+ files: [
737
+ {
738
+ path: './requestParams.json',
739
+ content: '{"type":"updatedContent"}',
740
+ },
741
+ ],
742
+ };
743
+
744
+ createMesh.mockResolvedValue({
745
+ meshId: 'dummy_mesh_id',
746
+ meshConfig: meshConfig,
747
+ });
748
+
749
+ parseSpy.mockResolvedValue({
750
+ args: { file: 'src/commands/__fixtures__/sample_mesh_files.json' },
751
+ flags: {
752
+ autoConfirmAction: Promise.resolve(false),
753
+ },
754
+ });
755
+
756
+ importFiles.mockResolvedValueOnce({
757
+ meshConfig,
758
+ });
759
+
760
+ const output = await CreateCommand.run();
761
+
762
+ expect(initRequestId).toHaveBeenCalled();
763
+ expect(createMesh.mock.calls[0]).toMatchInlineSnapshot(`
764
+ [
765
+ "1234",
766
+ "5678",
767
+ "123456789",
768
+ {
769
+ "meshConfig": {
770
+ "files": [
771
+ {
772
+ "content": "{"type":"updatedContent"}",
773
+ "path": "./requestParams.json",
774
+ },
775
+ ],
776
+ "sources": [
777
+ {
778
+ "handler": {
779
+ "JsonSchema": {
780
+ "baseUrl": "<json_source__baseurl>",
781
+ "operations": [
782
+ {
783
+ "field": "<query>",
784
+ "method": "POST",
785
+ "path": "<query_path>",
786
+ "requestSchema": "./requestParams.json",
787
+ "type": "Query",
788
+ },
789
+ ],
790
+ },
791
+ },
792
+ "name": "<json_source_name>",
793
+ },
794
+ ],
795
+ },
796
+ },
797
+ ]
798
+ `);
799
+ expect(createAPIMeshCredentials.mock.calls[0]).toMatchInlineSnapshot(`
800
+ [
801
+ "1234",
802
+ "5678",
803
+ "123456789",
804
+ ]
805
+ `);
806
+
807
+ expect(subscribeCredentialToMeshService.mock.calls[0]).toMatchInlineSnapshot(`
808
+ [
809
+ "1234",
810
+ "5678",
811
+ "123456789",
812
+ "dummy_id",
813
+ ]
814
+ `);
815
+ expect(output).toMatchInlineSnapshot(`
816
+ {
817
+ "adobeIdIntegrationsForWorkspace": {
818
+ "apiKey": "dummy_api_key",
819
+ "id": "dummy_id",
820
+ },
821
+ "mesh": {
822
+ "meshConfig": {
823
+ "files": [
824
+ {
825
+ "content": "{"type":"updatedContent"}",
826
+ "path": "./requestParams.json",
827
+ },
828
+ ],
829
+ "sources": [
830
+ {
831
+ "handler": {
832
+ "JsonSchema": {
833
+ "baseUrl": "<json_source__baseurl>",
834
+ "operations": [
835
+ {
836
+ "field": "<query>",
837
+ "method": "POST",
838
+ "path": "<query_path>",
839
+ "requestSchema": "./requestParams.json",
840
+ "type": "Query",
841
+ },
842
+ ],
843
+ },
844
+ },
845
+ "name": "<json_source_name>",
846
+ },
847
+ ],
848
+ },
849
+ "meshId": "dummy_mesh_id",
850
+ },
851
+ "sdkList": [
852
+ "dummy_service",
853
+ ],
854
+ }
855
+ `);
856
+ });
857
+
858
+ test('should fail if the file name is more than 25 characters', async () => {
859
+ parseSpy.mockResolvedValue({
860
+ args: { file: 'src/commands/__fixtures__/sample_mesh_invalid_file_name.json' },
861
+ flags: {
862
+ autoConfirmAction: Promise.resolve(false),
863
+ },
864
+ });
865
+
866
+ const output = CreateCommand.run();
867
+
868
+ await expect(output).rejects.toEqual(new Error('Input mesh config is not valid.'));
869
+
870
+ expect(logSpy.mock.calls).toMatchInlineSnapshot(`
871
+ [
872
+ [
873
+ "Mesh file names must be less than 25 characters. The following file(s) are invalid: requestJSONParameters.json.",
874
+ ],
875
+ ]
876
+ `);
877
+
878
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
879
+ [
880
+ [
881
+ "Input mesh config is not valid.",
882
+ ],
883
+ ]
884
+ `);
885
+ });
886
+
887
+ test('should fail if the file paths in files array and filenames in sources, transforms, additionalResolvers do not match in mesh config', async () => {
888
+ parseSpy.mockResolvedValue({
889
+ args: { file: 'src/commands/__fixtures__/sample_mesh_mismatching_path.json' },
890
+ flags: {
891
+ autoConfirmAction: Promise.resolve(false),
892
+ },
893
+ });
894
+
895
+ const output = CreateCommand.run();
896
+
897
+ await expect(output).rejects.toEqual(new Error('Input mesh config is not valid.'));
898
+
899
+ expect(logSpy.mock.calls).toMatchInlineSnapshot(`
900
+ [
901
+ [
902
+ "Please make sure the file names are matching in meshConfig.",
903
+ ],
904
+ ]
905
+ `);
906
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
907
+ [
908
+ [
909
+ "Input mesh config is not valid.",
910
+ ],
911
+ ]
912
+ `);
913
+ });
914
+
915
+ test('should fail if the file is of type other than js, json extension', async () => {
916
+ parseSpy.mockResolvedValue({
917
+ args: { file: 'src/commands/__fixtures__/sample_mesh_invalid_type.json' },
918
+ flags: {
919
+ autoConfirmAction: Promise.resolve(false),
920
+ },
921
+ });
922
+
923
+ const output = CreateCommand.run();
924
+
925
+ await expect(output).rejects.toEqual(new Error('Input mesh config is not valid.'));
926
+
927
+ expect(logSpy.mock.calls).toMatchInlineSnapshot(`
928
+ [
929
+ [
930
+ "Mesh files must be JavaScript or JSON. Other file types are not supported. The following file(s) are invalid: requestParams.txt.",
931
+ ],
932
+ ]
933
+ `);
934
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
935
+ [
936
+ [
937
+ "Input mesh config is not valid.",
938
+ ],
939
+ ]
940
+ `);
941
+ });
942
+
943
+ test('should fail if the files do not exist in the mesh directory or subdirectory', async () => {
944
+ parseSpy.mockResolvedValue({
945
+ args: { file: 'src/commands/__fixtures__/sample_mesh_invalid_paths.json' },
946
+ flags: {
947
+ autoConfirmAction: Promise.resolve(false),
948
+ },
949
+ });
950
+
951
+ importFiles.mockImplementation(() => {
952
+ throw new Error(
953
+ 'Please make sure the files: schemaBody.json and sample_mesh_invalid_paths.json are in the same directory/subdirectory.',
954
+ );
955
+ });
956
+
957
+ const output = CreateCommand.run();
958
+ await expect(output).rejects.toEqual(
959
+ new Error(
960
+ 'Unable to import the files in the mesh config. Please check the file and try again.',
961
+ ),
962
+ );
963
+
964
+ expect(logSpy.mock.calls).toMatchInlineSnapshot(`
965
+ [
966
+ [
967
+ "Please make sure the files: schemaBody.json and sample_mesh_invalid_paths.json are in the same directory/subdirectory.",
968
+ ],
969
+ ]
970
+ `);
971
+
972
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
973
+ [
974
+ [
975
+ "Unable to import the files in the mesh config. Please check the file and try again.",
976
+ ],
977
+ ]
978
+ `);
979
+ });
980
+
981
+ test('should fail if import files function fails', async () => {
982
+ parseSpy.mockResolvedValue({
983
+ args: { file: 'src/commands/__fixtures__/sample_mesh_files.json' },
984
+ flags: {
985
+ autoConfirmAction: Promise.resolve(false),
986
+ },
987
+ });
988
+
989
+ importFiles.mockImplementation(() => {
990
+ throw new Error('Error reading the file');
991
+ });
992
+
993
+ const output = CreateCommand.run();
994
+
995
+ await expect(output).rejects.toEqual(
996
+ new Error(
997
+ 'Unable to import the files in the mesh config. Please check the file and try again.',
998
+ ),
999
+ );
1000
+
1001
+ expect(logSpy.mock.calls).toMatchInlineSnapshot(`
1002
+ [
1003
+ [
1004
+ "Error reading the file",
1005
+ ],
1006
+ ]
1007
+ `);
1008
+
1009
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
1010
+ [
1011
+ [
1012
+ "Unable to import the files in the mesh config. Please check the file and try again.",
1013
+ ],
1014
+ ]
1015
+ `);
1016
+ });
1017
+
1018
+ test('should not override if prompt returns No, if there is files array', async () => {
1019
+ let meshConfig = {
1020
+ sources: [
1021
+ {
1022
+ name: '<json_source_name>',
1023
+ handler: {
1024
+ JsonSchema: {
1025
+ baseUrl: '<json_source__baseurl>',
1026
+ operations: [
1027
+ {
1028
+ type: 'Query',
1029
+ field: '<query>',
1030
+ path: '<query_path>',
1031
+ method: 'POST',
1032
+ requestSchema: './requestParams.json',
1033
+ },
1034
+ ],
1035
+ },
1036
+ },
1037
+ },
1038
+ ],
1039
+ files: [
1040
+ {
1041
+ path: './requestParams.json',
1042
+ content: '{"type":"dummyContent"}',
1043
+ },
1044
+ ],
1045
+ };
1046
+
1047
+ promptConfirm.mockResolvedValue(false).mockResolvedValue(true);
1048
+
1049
+ importFiles.mockResolvedValue(meshConfig);
1050
+
1051
+ createMesh.mockResolvedValue({
1052
+ meshId: 'dummy_mesh_id',
1053
+ meshConfig: meshConfig,
1054
+ });
1055
+
1056
+ parseSpy.mockResolvedValue({
1057
+ args: { file: 'src/commands/__fixtures__/sample_mesh_with_files_array.json' },
1058
+ flags: {
1059
+ autoConfirmAction: Promise.resolve(false),
1060
+ },
1061
+ });
1062
+
1063
+ const output = await CreateCommand.run();
1064
+
1065
+ expect(initRequestId).toHaveBeenCalled();
1066
+ expect(createMesh.mock.calls[0]).toMatchInlineSnapshot(`
1067
+ [
1068
+ "1234",
1069
+ "5678",
1070
+ "123456789",
1071
+ {
1072
+ "files": [
1073
+ {
1074
+ "content": "{"type":"dummyContent"}",
1075
+ "path": "./requestParams.json",
1076
+ },
1077
+ ],
1078
+ "sources": [
1079
+ {
1080
+ "handler": {
1081
+ "JsonSchema": {
1082
+ "baseUrl": "<json_source__baseurl>",
1083
+ "operations": [
1084
+ {
1085
+ "field": "<query>",
1086
+ "method": "POST",
1087
+ "path": "<query_path>",
1088
+ "requestSchema": "./requestParams.json",
1089
+ "type": "Query",
1090
+ },
1091
+ ],
1092
+ },
1093
+ },
1094
+ "name": "<json_source_name>",
1095
+ },
1096
+ ],
1097
+ },
1098
+ ]
1099
+ `);
1100
+ expect(createAPIMeshCredentials.mock.calls[0]).toMatchInlineSnapshot(`
1101
+ [
1102
+ "1234",
1103
+ "5678",
1104
+ "123456789",
1105
+ ]
1106
+ `);
1107
+ expect(subscribeCredentialToMeshService.mock.calls[0]).toMatchInlineSnapshot(`
1108
+ [
1109
+ "1234",
1110
+ "5678",
1111
+ "123456789",
1112
+ "dummy_id",
1113
+ ]
1114
+ `);
1115
+ expect(output).toMatchInlineSnapshot(`
1116
+ {
1117
+ "adobeIdIntegrationsForWorkspace": {
1118
+ "apiKey": "dummy_api_key",
1119
+ "id": "dummy_id",
1120
+ },
1121
+ "mesh": {
1122
+ "meshConfig": {
1123
+ "files": [
1124
+ {
1125
+ "content": "{"type":"dummyContent"}",
1126
+ "path": "./requestParams.json",
1127
+ },
1128
+ ],
1129
+ "sources": [
1130
+ {
1131
+ "handler": {
1132
+ "JsonSchema": {
1133
+ "baseUrl": "<json_source__baseurl>",
1134
+ "operations": [
1135
+ {
1136
+ "field": "<query>",
1137
+ "method": "POST",
1138
+ "path": "<query_path>",
1139
+ "requestSchema": "./requestParams.json",
1140
+ "type": "Query",
1141
+ },
1142
+ ],
1143
+ },
1144
+ },
1145
+ "name": "<json_source_name>",
1146
+ },
1147
+ ],
1148
+ },
1149
+ "meshId": "dummy_mesh_id",
1150
+ },
1151
+ "sdkList": [
1152
+ "dummy_service",
1153
+ ],
1154
+ }
1155
+ `);
1156
+ });
1157
+
1158
+ test('should override if prompt returns Yes, if there is files array', async () => {
1159
+ let meshConfig = {
1160
+ sources: [
1161
+ {
1162
+ name: '<json_source_name>',
1163
+ handler: {
1164
+ JsonSchema: {
1165
+ baseUrl: '<json_source__baseurl>',
1166
+ operations: [
1167
+ {
1168
+ type: 'Query',
1169
+ field: '<query>',
1170
+ path: '<query_path>',
1171
+ method: 'POST',
1172
+ requestSchema: './requestParams.json',
1173
+ },
1174
+ ],
1175
+ },
1176
+ },
1177
+ },
1178
+ ],
1179
+ files: [
1180
+ {
1181
+ path: './requestParams.json',
1182
+ content: '{"type":"updatedContent"}',
1183
+ },
1184
+ ],
1185
+ };
1186
+
1187
+ promptConfirm.mockResolvedValue(true).mockResolvedValue(true);
1188
+
1189
+ parseSpy.mockResolvedValue({
1190
+ args: { file: 'src/commands/__fixtures__/sample_mesh_with_files_array.json' },
1191
+ flags: {
1192
+ autoConfirmAction: Promise.resolve(false),
1193
+ },
1194
+ });
1195
+
1196
+ importFiles.mockResolvedValueOnce({
1197
+ meshConfig,
1198
+ });
1199
+
1200
+ createMesh.mockResolvedValue({
1201
+ meshId: 'dummy_mesh_id',
1202
+ meshConfig: meshConfig,
1203
+ });
1204
+
1205
+ const output = await CreateCommand.run();
1206
+
1207
+ expect(initRequestId).toHaveBeenCalled();
1208
+ expect(createMesh.mock.calls[0]).toMatchInlineSnapshot(`
1209
+ [
1210
+ "1234",
1211
+ "5678",
1212
+ "123456789",
1213
+ {
1214
+ "meshConfig": {
1215
+ "files": [
1216
+ {
1217
+ "content": "{"type":"updatedContent"}",
1218
+ "path": "./requestParams.json",
1219
+ },
1220
+ ],
1221
+ "sources": [
1222
+ {
1223
+ "handler": {
1224
+ "JsonSchema": {
1225
+ "baseUrl": "<json_source__baseurl>",
1226
+ "operations": [
1227
+ {
1228
+ "field": "<query>",
1229
+ "method": "POST",
1230
+ "path": "<query_path>",
1231
+ "requestSchema": "./requestParams.json",
1232
+ "type": "Query",
1233
+ },
1234
+ ],
1235
+ },
1236
+ },
1237
+ "name": "<json_source_name>",
1238
+ },
1239
+ ],
1240
+ },
1241
+ },
1242
+ ]
1243
+ `);
1244
+ expect(createAPIMeshCredentials.mock.calls[0]).toMatchInlineSnapshot(`
1245
+ [
1246
+ "1234",
1247
+ "5678",
1248
+ "123456789",
1249
+ ]
1250
+ `);
1251
+
1252
+ expect(subscribeCredentialToMeshService.mock.calls[0]).toMatchInlineSnapshot(`
1253
+ [
1254
+ "1234",
1255
+ "5678",
1256
+ "123456789",
1257
+ "dummy_id",
1258
+ ]
1259
+ `);
1260
+ expect(output).toMatchInlineSnapshot(`
1261
+ {
1262
+ "adobeIdIntegrationsForWorkspace": {
1263
+ "apiKey": "dummy_api_key",
1264
+ "id": "dummy_id",
1265
+ },
1266
+ "mesh": {
1267
+ "meshConfig": {
1268
+ "files": [
1269
+ {
1270
+ "content": "{"type":"updatedContent"}",
1271
+ "path": "./requestParams.json",
1272
+ },
1273
+ ],
1274
+ "sources": [
1275
+ {
1276
+ "handler": {
1277
+ "JsonSchema": {
1278
+ "baseUrl": "<json_source__baseurl>",
1279
+ "operations": [
1280
+ {
1281
+ "field": "<query>",
1282
+ "method": "POST",
1283
+ "path": "<query_path>",
1284
+ "requestSchema": "./requestParams.json",
1285
+ "type": "Query",
1286
+ },
1287
+ ],
1288
+ },
1289
+ },
1290
+ "name": "<json_source_name>",
1291
+ },
1292
+ ],
1293
+ },
1294
+ "meshId": "dummy_mesh_id",
1295
+ },
1296
+ "sdkList": [
1297
+ "dummy_service",
1298
+ ],
1299
+ }
1300
+ `);
1301
+ });
1302
+
1303
+ test('should pass for a fully-qualified meshConfig even if the file does not exist in fileSystem', async () => {
1304
+ let meshConfig = {
1305
+ sources: [
1306
+ {
1307
+ name: '<json_source_name>',
1308
+ handler: {
1309
+ JsonSchema: {
1310
+ baseUrl: '<json_source__baseurl>',
1311
+ operations: [
1312
+ {
1313
+ type: 'Query',
1314
+ field: '<query>',
1315
+ path: '<query_path>',
1316
+ method: 'POST',
1317
+ requestSchema: './schemaBody.json',
1318
+ },
1319
+ ],
1320
+ },
1321
+ },
1322
+ },
1323
+ ],
1324
+ files: [
1325
+ {
1326
+ path: './schemaBody.json',
1327
+ content: '{"type":"dummyContent"}',
1328
+ },
1329
+ ],
1330
+ };
1331
+
1332
+ parseSpy.mockResolvedValue({
1333
+ args: { file: 'src/commands/__fixtures__/sample_fully_qualified_mesh.json' },
1334
+ flags: {
1335
+ autoConfirmAction: Promise.resolve(false),
1336
+ },
1337
+ });
1338
+
1339
+ promptConfirm.mockResolvedValue(true);
1340
+
1341
+ importFiles.mockResolvedValueOnce({
1342
+ meshConfig,
1343
+ });
1344
+
1345
+ createMesh.mockResolvedValue({
1346
+ meshId: 'dummy_mesh_id',
1347
+ meshConfig: meshConfig,
1348
+ });
1349
+
1350
+ const output = await CreateCommand.run();
1351
+
1352
+ expect(initRequestId).toHaveBeenCalled();
1353
+ expect(createMesh.mock.calls[0]).toMatchInlineSnapshot(`
1354
+ [
1355
+ "1234",
1356
+ "5678",
1357
+ "123456789",
1358
+ {
1359
+ "meshConfig": {
1360
+ "files": [
1361
+ {
1362
+ "content": "{"type":"dummyContent"}",
1363
+ "path": "./schemaBody.json",
1364
+ },
1365
+ ],
1366
+ "sources": [
1367
+ {
1368
+ "handler": {
1369
+ "JsonSchema": {
1370
+ "baseUrl": "<json_source__baseurl>",
1371
+ "operations": [
1372
+ {
1373
+ "field": "<query>",
1374
+ "method": "POST",
1375
+ "path": "<query_path>",
1376
+ "requestSchema": "./schemaBody.json",
1377
+ "type": "Query",
1378
+ },
1379
+ ],
1380
+ },
1381
+ },
1382
+ "name": "<json_source_name>",
1383
+ },
1384
+ ],
1385
+ },
1386
+ },
1387
+ ]
1388
+ `);
1389
+ expect(createAPIMeshCredentials.mock.calls[0]).toMatchInlineSnapshot(`
1390
+ [
1391
+ "1234",
1392
+ "5678",
1393
+ "123456789",
1394
+ ]
1395
+ `);
1396
+ expect(subscribeCredentialToMeshService.mock.calls[0]).toMatchInlineSnapshot(`
1397
+ [
1398
+ "1234",
1399
+ "5678",
1400
+ "123456789",
1401
+ "dummy_id",
1402
+ ]
1403
+ `);
1404
+ expect(output).toMatchInlineSnapshot(`
1405
+ {
1406
+ "adobeIdIntegrationsForWorkspace": {
1407
+ "apiKey": "dummy_api_key",
1408
+ "id": "dummy_id",
1409
+ },
1410
+ "mesh": {
1411
+ "meshConfig": {
1412
+ "files": [
1413
+ {
1414
+ "content": "{"type":"dummyContent"}",
1415
+ "path": "./schemaBody.json",
1416
+ },
1417
+ ],
1418
+ "sources": [
1419
+ {
1420
+ "handler": {
1421
+ "JsonSchema": {
1422
+ "baseUrl": "<json_source__baseurl>",
1423
+ "operations": [
1424
+ {
1425
+ "field": "<query>",
1426
+ "method": "POST",
1427
+ "path": "<query_path>",
1428
+ "requestSchema": "./schemaBody.json",
1429
+ "type": "Query",
1430
+ },
1431
+ ],
1432
+ },
1433
+ },
1434
+ "name": "<json_source_name>",
1435
+ },
1436
+ ],
1437
+ },
1438
+ "meshId": "dummy_mesh_id",
1439
+ },
1440
+ "sdkList": [
1441
+ "dummy_service",
1442
+ ],
1443
+ }
1444
+ `);
1445
+ });
1446
+
1447
+ test('should pass if the file is located in subdirectory of mesh directory', async () => {
1448
+ let meshConfig = {
1449
+ sources: [
1450
+ {
1451
+ name: '<json_source_name>',
1452
+ handler: {
1453
+ JsonSchema: {
1454
+ baseUrl: '<json_source__baseurl>',
1455
+ operations: [
1456
+ {
1457
+ type: 'Query',
1458
+ field: '<query>',
1459
+ path: '<query_path>',
1460
+ method: 'POST',
1461
+ requestSchema: './files/requestParams.json',
1462
+ },
1463
+ ],
1464
+ },
1465
+ },
1466
+ },
1467
+ ],
1468
+ files: [
1469
+ {
1470
+ path: './files/requestParams.json',
1471
+ content: '{"type":"updatedContent"}',
1472
+ },
1473
+ ],
1474
+ };
1475
+
1476
+ createMesh.mockResolvedValue({
1477
+ meshId: 'dummy_mesh_id',
1478
+ meshConfig: meshConfig,
1479
+ });
1480
+
1481
+ parseSpy.mockResolvedValue({
1482
+ args: { file: 'src/commands/__fixtures__/sample_mesh_subdirectory.json' },
1483
+ flags: {
1484
+ autoConfirmAction: Promise.resolve(false),
1485
+ },
1486
+ });
1487
+
1488
+ importFiles.mockResolvedValueOnce({
1489
+ meshConfig,
1490
+ });
1491
+
1492
+ const output = await CreateCommand.run();
1493
+
1494
+ expect(initRequestId).toHaveBeenCalled();
1495
+ expect(createMesh.mock.calls[0]).toMatchInlineSnapshot(`
1496
+ [
1497
+ "1234",
1498
+ "5678",
1499
+ "123456789",
1500
+ {
1501
+ "meshConfig": {
1502
+ "files": [
1503
+ {
1504
+ "content": "{"type":"updatedContent"}",
1505
+ "path": "./files/requestParams.json",
1506
+ },
1507
+ ],
1508
+ "sources": [
1509
+ {
1510
+ "handler": {
1511
+ "JsonSchema": {
1512
+ "baseUrl": "<json_source__baseurl>",
1513
+ "operations": [
1514
+ {
1515
+ "field": "<query>",
1516
+ "method": "POST",
1517
+ "path": "<query_path>",
1518
+ "requestSchema": "./files/requestParams.json",
1519
+ "type": "Query",
1520
+ },
1521
+ ],
1522
+ },
1523
+ },
1524
+ "name": "<json_source_name>",
1525
+ },
1526
+ ],
1527
+ },
1528
+ },
1529
+ ]
1530
+ `);
1531
+ expect(createAPIMeshCredentials.mock.calls[0]).toMatchInlineSnapshot(`
1532
+ [
1533
+ "1234",
1534
+ "5678",
1535
+ "123456789",
1536
+ ]
1537
+ `);
1538
+
1539
+ expect(subscribeCredentialToMeshService.mock.calls[0]).toMatchInlineSnapshot(`
1540
+ [
1541
+ "1234",
1542
+ "5678",
1543
+ "123456789",
1544
+ "dummy_id",
1545
+ ]
1546
+ `);
1547
+ expect(output).toMatchInlineSnapshot(`
1548
+ {
1549
+ "adobeIdIntegrationsForWorkspace": {
1550
+ "apiKey": "dummy_api_key",
1551
+ "id": "dummy_id",
1552
+ },
1553
+ "mesh": {
1554
+ "meshConfig": {
1555
+ "files": [
1556
+ {
1557
+ "content": "{"type":"updatedContent"}",
1558
+ "path": "./files/requestParams.json",
1559
+ },
1560
+ ],
1561
+ "sources": [
1562
+ {
1563
+ "handler": {
1564
+ "JsonSchema": {
1565
+ "baseUrl": "<json_source__baseurl>",
1566
+ "operations": [
1567
+ {
1568
+ "field": "<query>",
1569
+ "method": "POST",
1570
+ "path": "<query_path>",
1571
+ "requestSchema": "./files/requestParams.json",
1572
+ "type": "Query",
1573
+ },
1574
+ ],
1575
+ },
1576
+ },
1577
+ "name": "<json_source_name>",
1578
+ },
1579
+ ],
1580
+ },
1581
+ "meshId": "dummy_mesh_id",
1582
+ },
1583
+ "sdkList": [
1584
+ "dummy_service",
1585
+ ],
1586
+ }
1587
+ `);
1588
+ });
1589
+
1590
+ test('should fail if the file is outside the workspace directory', async () => {
1591
+ parseSpy.mockResolvedValue({
1592
+ args: { file: 'src/commands/__fixtures__/sample_mesh_outside_workspace_dir.json' },
1593
+ flags: {
1594
+ autoConfirmAction: Promise.resolve(false),
1595
+ },
1596
+ });
1597
+
1598
+ const output = CreateCommand.run();
1599
+
1600
+ await expect(output).rejects.toEqual(new Error('Input mesh config is not valid.'));
1601
+ expect(logSpy.mock.calls).toMatchInlineSnapshot(`
1602
+ [
1603
+ [
1604
+ "File(s): requestParams.json is outside the mesh directory.",
1605
+ ],
1606
+ ]
1607
+ `);
1608
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
1609
+ [
1610
+ [
1611
+ "Input mesh config is not valid.",
1612
+ ],
1613
+ ]
1614
+ `);
1615
+ });
1616
+
1617
+ test('should fail if the file has invalid JSON content', async () => {
1618
+ parseSpy.mockResolvedValue({
1619
+ args: { file: 'src/commands/__fixtures__/sample_mesh_invalid_file_content.json' },
1620
+ flags: {
1621
+ autoConfirmAction: Promise.resolve(false),
1622
+ },
1623
+ });
1624
+
1625
+ importFiles.mockImplementation(() => {
1626
+ throw new Error('Invalid JSON content in openapi-schema.json');
1627
+ });
1628
+
1629
+ const output = CreateCommand.run();
1630
+
1631
+ await expect(output).rejects.toEqual(
1632
+ new Error(
1633
+ 'Unable to import the files in the mesh config. Please check the file and try again.',
1634
+ ),
1635
+ );
1636
+
1637
+ expect(logSpy.mock.calls).toMatchInlineSnapshot(`
1638
+ [
1639
+ [
1640
+ "Invalid JSON content in openapi-schema.json",
1641
+ ],
1642
+ ]
1643
+ `);
1644
+
1645
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
1646
+ [
1647
+ [
1648
+ "Unable to import the files in the mesh config. Please check the file and try again.",
1649
+ ],
1650
+ ]
1651
+ `);
1652
+ });
1653
+
1654
+ test('should fail if the file path starts from home directory i.e., path starts with ~/', async () => {
1655
+ parseSpy.mockResolvedValue({
1656
+ args: { file: 'src/commands/__fixtures__/sample_mesh_path_from_home.json' },
1657
+ flags: {
1658
+ autoConfirmAction: Promise.resolve(false),
1659
+ },
1660
+ });
1661
+
1662
+ const output = CreateCommand.run();
1663
+
1664
+ await expect(output).rejects.toEqual(new Error('Input mesh config is not valid.'));
1665
+ expect(logSpy.mock.calls).toMatchInlineSnapshot(`
1666
+ [
1667
+ [
1668
+ "File(s): venia-openapi-schema.json is outside the mesh directory.",
1669
+ ],
1670
+ ]
1671
+ `);
1672
+ expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
1673
+ [
1674
+ [
1675
+ "Input mesh config is not valid.",
1676
+ ],
1677
+ ]
1678
+ `);
1679
+ });
711
1680
  });