1
+ import { jest } from '@jest/globals' ;
2
+ import axios from 'axios' ;
3
+ import { loggerInit } from '../logger.js' ;
4
+
5
+ describe ( 'Neptune Schema discovery tests' , ( ) => {
6
+ beforeAll ( ( ) => {
7
+ loggerInit ( './src/test/output' , true , 'fatal' ) ;
8
+ } ) ;
9
+
10
+ afterEach ( ( ) => {
11
+ jest . restoreAllMocks ( ) ;
12
+ } ) ;
13
+
14
+ test ( 'should handle nodes with multiple labels when querying edge to and from labels' , async ( ) => {
15
+ // Mock successful summary API response
16
+ jest . spyOn ( axios , "get" ) . mockResolvedValue ( {
17
+ data : {
18
+ payload : {
19
+ graphSummary : {
20
+ nodeLabels : [ 'Person' , 'Employee' , 'Manager' , 'Company' , 'Developer' ] ,
21
+ edgeLabels : [ 'WORKS_FOR' , 'REPORTS_TO' ]
22
+ }
23
+ }
24
+ }
25
+ } ) ;
26
+
27
+ // Mock HTTP responses for neptune queries
28
+ const mockResponses = [
29
+ { data : { results : [ { properties : { name : 'John' } } ] } } ,
30
+ { data : { results : [ { properties : { employeeId : 'E123' } } ] } } ,
31
+ { data : { results : [ { properties : { level : 'Senior' } } ] } } ,
32
+ { data : { results : [ { properties : { companyName : 'TechCorp' } } ] } } ,
33
+ { data : { results : [ { properties : { programmingLanguages : 'JavaScript' } } ] } } ,
34
+ { data : { results : [ { properties : { startDate : '2020-01-01' } } ] } } ,
35
+ { data : { results : [ { properties : { since : '2022-01-01' } } ] } } ,
36
+ {
37
+ data : {
38
+ results : [
39
+ { fromLabel : [ 'Employee' , 'Person' ] , toLabel : [ 'Company' ] } ,
40
+ { fromLabel : [ 'Manager' , 'Employee' ] , toLabel : [ 'Company' ] } ,
41
+ { fromLabel : [ 'Developer' , 'Employee' ] , toLabel : [ 'Company' ] }
42
+ ]
43
+ }
44
+ } ,
45
+ {
46
+ data : {
47
+ results : [
48
+ { fromLabel : [ 'Employee' ] , toLabel : [ 'Manager' , 'Person' ] } ,
49
+ { fromLabel : [ 'Developer' ] , toLabel : [ 'Manager' ] }
50
+ ]
51
+ }
52
+ } ,
53
+ { data : { results : [ ] } } ,
54
+ { data : { results : [ ] } } ,
55
+ { data : { results : [ ] } } ,
56
+ { data : { results : [ { rels : 3 } ] } }
57
+ ] ;
58
+ mockAxiosResponses ( mockResponses ) ;
59
+
60
+ // Import the module fresh for each test to avoid state sharing
61
+ const schema = await runGetNeptuneSchema ( ) ;
62
+
63
+ // Validate that no duplicate node or edge structures created
64
+ expect ( schema . nodeStructures ) . toHaveLength ( 5 ) ;
65
+ const nodeLabels = schema . nodeStructures . map ( node => node . label ) . toSorted ( ) ;
66
+ expect ( nodeLabels ) . toEqual ( [ 'Company' , 'Developer' , 'Employee' , 'Manager' , 'Person' ] ) ;
67
+
68
+ expect ( schema . edgeStructures ) . toHaveLength ( 2 ) ;
69
+ const edgeLabels = schema . edgeStructures . map ( edge => edge . label ) . sort ( ) ;
70
+ expect ( edgeLabels ) . toEqual ( [ 'REPORTS_TO' , 'WORKS_FOR' ] ) ;
71
+ } ) ;
72
+
73
+ test ( 'should handle multi-label nodes from getNodesNames query without creating duplicates' , async ( ) => {
74
+ // Mock console.error to suppress expected error output
75
+ const consoleSpy = jest . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { } ) ;
76
+
77
+ // Mock summary API to fail so we use direct getNodesNames queries
78
+ jest . spyOn ( axios , "get" ) . mockRejectedValue ( new Error ( 'Summary API not available' ) ) ;
79
+
80
+ // Mock HTTP responses for the multi-label scenario using getNodesNames
81
+ const mockResponses = [
82
+ {
83
+ data : {
84
+ results : [
85
+ { 'labels(a)' : [ 'Person' , 'Employee' ] } ,
86
+ { 'labels(a)' : [ 'Person' , 'Manager' ] } ,
87
+ { 'labels(a)' : [ 'Company' ] } ,
88
+ { 'labels(a)' : [ 'Employee' , 'Developer' ] } ,
89
+ { 'labels(a)' : [ 'Person' ] } ,
90
+ { 'labels(a)' : [ 'Manager' , 'TeamLead' ] }
91
+ ]
92
+ }
93
+ } ,
94
+ {
95
+ data : {
96
+ results : [
97
+ { 'type(e)' : 'WORKS_FOR' } ,
98
+ { 'type(e)' : 'REPORTS_TO' }
99
+ ]
100
+ }
101
+ } ,
102
+ { data : { results : [ { properties : { name : 'John' , age : 30 } } ] } } ,
103
+ { data : { results : [ { properties : { employeeId : 'E123' , department : 'IT' } } ] } } ,
104
+ { data : { results : [ { properties : { level : 'Senior' , yearsExperience : 5 } } ] } } ,
105
+ { data : { results : [ { properties : { companyName : 'TechCorp' , founded : 2010 } } ] } } ,
106
+ { data : { results : [ { properties : { programmingLanguages : 'JavaScript' , seniority : 'Mid' } } ] } } ,
107
+ { data : { results : [ { properties : { teamSize : 8 , responsibilities : 'Team coordination' } } ] } } ,
108
+ { data : { results : [ { properties : { startDate : '2020-01-01' , position : 'Software Engineer' } } ] } } ,
109
+ { data : { results : [ { properties : { since : '2022-01-01' , directReport : true } } ] } } ,
110
+ {
111
+ data : {
112
+ results : [
113
+ { fromLabel : [ 'Employee' , 'Person' ] , toLabel : [ 'Company' ] }
114
+ ]
115
+ }
116
+ } ,
117
+ {
118
+ data : {
119
+ results : [
120
+ { fromLabel : [ 'Employee' ] , toLabel : [ 'Manager' , 'TeamLead' ] }
121
+ ]
122
+ }
123
+ } ,
124
+ { data : { results : [ ] } } ,
125
+ { data : { results : [ ] } } ,
126
+ { data : { results : [ ] } } ,
127
+ { data : { results : [ { rels : 3 } ] } }
128
+ ] ;
129
+ mockAxiosResponses ( mockResponses ) ;
130
+
131
+ // Import the module fresh for each test to avoid state sharing
132
+ const schema = await runGetNeptuneSchema ( ) ;
133
+
134
+ // Validate that no duplicate node or edge structures created
135
+ expect ( schema . nodeStructures ) . toHaveLength ( 6 ) ;
136
+ const nodeLabels = schema . nodeStructures . map ( node => node . label ) . sort ( ) ;
137
+ expect ( nodeLabels ) . toEqual ( [ 'Company' , 'Developer' , 'Employee' , 'Manager' , 'Person' , 'TeamLead' ] ) ;
138
+
139
+ expect ( schema . edgeStructures ) . toHaveLength ( 2 ) ;
140
+ const edgeLabels = schema . edgeStructures . map ( edge => edge . label ) . sort ( ) ;
141
+ expect ( edgeLabels ) . toEqual ( [ 'REPORTS_TO' , 'WORKS_FOR' ] ) ;
142
+ } ) ;
143
+ } ) ;
144
+
145
+ async function runGetNeptuneSchema ( ) {
146
+ const { getNeptuneSchema, setGetNeptuneSchemaParameters} = await import ( `../NeptuneSchema.js?t=${ Date . now ( ) } ` ) ;
147
+ setNeptuneSchemaParameters ( setGetNeptuneSchemaParameters ) ;
148
+ const result = await getNeptuneSchema ( ) ;
149
+ return JSON . parse ( result ) ;
150
+ }
151
+
152
+ function setNeptuneSchemaParameters ( setGetNeptuneSchemaParameters ) {
153
+ setGetNeptuneSchemaParameters ( {
154
+ host : 'test-neptune.cluster-abc.us-west-2.neptune.amazonaws.com' ,
155
+ port : '8182' ,
156
+ region : 'us-west-2' ,
157
+ neptuneType : 'neptune-db' ,
158
+ graphName : 'test-graph' ,
159
+ domain : 'neptune.amazonaws.com'
160
+ } ) ;
161
+ }
162
+
163
+ function mockAxiosResponses ( mockResponses = [ ] ) {
164
+ let responseIndex = 0 ;
165
+ jest . spyOn ( axios , 'post' ) . mockImplementation ( ( ) => {
166
+ if ( responseIndex < mockResponses . length ) {
167
+ return Promise . resolve ( mockResponses [ responseIndex ++ ] ) ;
168
+ }
169
+ return Promise . resolve ( { data : { results : [ ] } } ) ;
170
+ } ) ;
171
+ }
0 commit comments