@@ -14,6 +14,7 @@ import {
1414 selectCollection ,
1515 selectCurrentModelFromState ,
1616 selectRelationship ,
17+ selectField ,
1718} from '../../store/diagram' ;
1819import dataModel from '../../../test/fixtures/data-model-with-relationships.json' ;
1920import type {
@@ -41,6 +42,14 @@ async function comboboxSelectItem(
4142 } ) ;
4243}
4344
45+ function getMultiComboboxValues ( testId : string ) {
46+ const combobox = screen . getByTestId ( testId ) ;
47+ expect ( combobox ) . to . be . visible ;
48+ return within ( combobox )
49+ . getAllByRole ( 'option' )
50+ . map ( ( option ) => option . textContent ) ;
51+ }
52+
4453describe ( 'DiagramEditorSidePanel' , function ( ) {
4554 before ( function ( ) {
4655 // TODO(COMPASS-9618): skip in electron runtime for now, drawer has issues rendering
@@ -144,6 +153,45 @@ describe('DiagramEditorSidePanel', function () {
144153 ) . to . be . visible ;
145154 } ) ;
146155
156+ describe ( 'Field context drawer' , function ( ) {
157+ it ( 'should render a field context drawer when field is clicked' , async function ( ) {
158+ const result = renderDrawer ( ) ;
159+ result . plugin . store . dispatch ( selectField ( 'flights.airlines' , [ 'alias' ] ) ) ;
160+
161+ await waitFor ( ( ) => {
162+ expect ( screen . getByTitle ( 'airlines.alias' ) ) . to . be . visible ;
163+ } ) ;
164+
165+ const nameInput = screen . getByLabelText ( 'Field name' ) ;
166+ expect ( nameInput ) . to . be . visible ;
167+ expect ( nameInput ) . to . have . value ( 'alias' ) ;
168+
169+ const selectedTypes = getMultiComboboxValues ( 'lg-combobox-datatype' ) ;
170+ expect ( selectedTypes ) . to . have . lengthOf ( 2 ) ;
171+ expect ( selectedTypes ) . to . include ( 'string' ) ;
172+ expect ( selectedTypes ) . to . include ( 'int' ) ;
173+ } ) ;
174+
175+ it ( 'should render a nested field context drawer when field is clicked' , async function ( ) {
176+ const result = renderDrawer ( ) ;
177+ result . plugin . store . dispatch (
178+ selectField ( 'flights.routes' , [ 'airline' , 'id' ] )
179+ ) ;
180+
181+ await waitFor ( ( ) => {
182+ expect ( screen . getByTitle ( 'routes.airline.id' ) ) . to . be . visible ;
183+ } ) ;
184+
185+ const nameInput = screen . getByLabelText ( 'Field name' ) ;
186+ expect ( nameInput ) . to . be . visible ;
187+ expect ( nameInput ) . to . have . value ( 'id' ) ;
188+
189+ const selectedTypes = getMultiComboboxValues ( 'lg-combobox-datatype' ) ;
190+ expect ( selectedTypes ) . to . have . lengthOf ( 1 ) ;
191+ expect ( selectedTypes ) . to . include ( 'string' ) ;
192+ } ) ;
193+ } ) ;
194+
147195 it ( 'should change the content of the drawer when selecting different items' , async function ( ) {
148196 const result = renderDrawer ( ) ;
149197
@@ -182,93 +230,185 @@ describe('DiagramEditorSidePanel', function () {
182230 expect ( screen . getByLabelText ( 'Name' ) ) . to . have . value ( 'planes' ) ;
183231 } ) ;
184232
185- it ( 'should open and edit relationship starting from collection' , async function ( ) {
186- const result = renderDrawer ( ) ;
187- result . plugin . store . dispatch ( selectCollection ( 'flights.countries' ) ) ;
188-
189- await waitFor ( ( ) => {
190- expect ( screen . getByLabelText ( 'Name' ) ) . to . have . value ( 'countries' ) ;
191- } ) ;
233+ describe ( 'Collection -> Relationships' , function ( ) {
234+ it ( 'should add a relationship starting from a collection' , async function ( ) {
235+ const result = renderDrawer ( ) ;
236+ result . plugin . store . dispatch ( selectCollection ( 'flights.countries' ) ) ;
192237
193- // Open relationshipt editing form
194- const relationshipItem = screen
195- . getByText ( 'countries.name → airports.Country' )
196- . closest ( 'li' ) ;
197- expect ( relationshipItem ) . to . be . visible ;
198- userEvent . click (
199- within ( relationshipItem ! ) . getByRole ( 'button' , {
200- name : 'Edit relationship' ,
201- } )
202- ) ;
203- expect ( screen . getByLabelText ( 'Local field' ) ) . to . be . visible ;
238+ await waitFor ( ( ) => {
239+ expect ( screen . getByLabelText ( 'Name' ) ) . to . have . value ( 'countries' ) ;
240+ } ) ;
204241
205- // Select new values
206- await comboboxSelectItem ( 'Local collection' , 'planes' ) ;
207- await comboboxSelectItem ( 'Local field' , 'name' ) ;
208- await comboboxSelectItem ( 'Foreign collection' , 'countries' ) ;
209- await comboboxSelectItem ( 'Foreign field' , 'iso_code' ) ;
242+ // Click on add relationship button
243+ userEvent . click ( screen . getByRole ( 'button' , { name : 'Add relationship' } ) ) ;
210244
211- userEvent . click ( screen . getByRole ( 'textbox' , { name : 'Notes' } ) ) ;
212- userEvent . type (
213- screen . getByRole ( 'textbox' , { name : 'Notes' } ) ,
214- 'Note about the relationship '
215- ) ;
216- userEvent . tab ( ) ;
245+ // Collection is pre-selected
246+ expect ( screen . getByLabelText ( 'Local collection' ) ) . to . be . visible ;
247+ expect ( screen . getByLabelText ( 'Local collection' ) ) . to . have . value (
248+ 'countries '
249+ ) ;
250+ } ) ;
217251
218- // We should be testing through rendered UI but as it's really hard to make
219- // diagram rendering in tests property, we are just validating the final
220- // model here
221- const modifiedRelationship = selectCurrentModelFromState (
222- result . plugin . store . getState ( )
223- ) . relationships . find ( ( r : Relationship ) => {
224- return r . id === '204b1fc0-601f-4d62-bba3-38fade71e049' ;
252+ it ( 'should open and edit relationship starting from a collection' , async function ( ) {
253+ const result = renderDrawer ( ) ;
254+ result . plugin . store . dispatch ( selectCollection ( 'flights.countries' ) ) ;
255+
256+ await waitFor ( ( ) => {
257+ expect ( screen . getByLabelText ( 'Name' ) ) . to . have . value ( 'countries' ) ;
258+ } ) ;
259+
260+ // Open relationshipt editing form
261+ const relationshipItem = screen
262+ . getByText ( 'countries.name → airports.Country' )
263+ . closest ( 'li' ) ;
264+ expect ( relationshipItem ) . to . be . visible ;
265+ userEvent . click (
266+ within ( relationshipItem ! ) . getByRole ( 'button' , {
267+ name : 'Edit relationship' ,
268+ } )
269+ ) ;
270+ expect ( screen . getByLabelText ( 'Local field' ) ) . to . be . visible ;
271+
272+ // Select new values
273+ await comboboxSelectItem ( 'Local collection' , 'planes' ) ;
274+ await comboboxSelectItem ( 'Local field' , 'name' ) ;
275+ await comboboxSelectItem ( 'Foreign collection' , 'countries' ) ;
276+ await comboboxSelectItem ( 'Foreign field' , 'iso_code' ) ;
277+
278+ userEvent . click ( screen . getByRole ( 'textbox' , { name : 'Notes' } ) ) ;
279+ userEvent . type (
280+ screen . getByRole ( 'textbox' , { name : 'Notes' } ) ,
281+ 'Note about the relationship'
282+ ) ;
283+ userEvent . tab ( ) ;
284+
285+ // We should be testing through rendered UI but as it's really hard to make
286+ // diagram rendering in tests property, we are just validating the final
287+ // model here
288+ const modifiedRelationship = selectCurrentModelFromState (
289+ result . plugin . store . getState ( )
290+ ) . relationships . find ( ( r : Relationship ) => {
291+ return r . id === '204b1fc0-601f-4d62-bba3-38fade71e049' ;
292+ } ) ;
293+
294+ expect ( modifiedRelationship )
295+ . to . have . property ( 'relationship' )
296+ . deep . eq ( [
297+ {
298+ ns : 'flights.planes' ,
299+ fields : [ 'name' ] ,
300+ cardinality : 1 ,
301+ } ,
302+ {
303+ ns : 'flights.countries' ,
304+ fields : [ 'iso_code' ] ,
305+ cardinality : 100 ,
306+ } ,
307+ ] ) ;
308+
309+ expect ( modifiedRelationship ) . to . have . property (
310+ 'note' ,
311+ 'Note about the relationship'
312+ ) ;
225313 } ) ;
226314
227- expect ( modifiedRelationship )
228- . to . have . property ( 'relationship' )
229- . deep . eq ( [
230- {
231- ns : 'flights.planes' ,
232- fields : [ 'name' ] ,
233- cardinality : 1 ,
234- } ,
235- {
236- ns : 'flights.countries' ,
237- fields : [ 'iso_code' ] ,
238- cardinality : 100 ,
239- } ,
240- ] ) ;
241-
242- expect ( modifiedRelationship ) . to . have . property (
243- 'note' ,
244- 'Note about the relationship'
245- ) ;
315+ it ( 'should delete a relationship from a collection' , async function ( ) {
316+ const result = renderDrawer ( ) ;
317+ result . plugin . store . dispatch ( selectCollection ( 'flights.countries' ) ) ;
318+
319+ await waitFor ( ( ) => {
320+ expect ( screen . getByLabelText ( 'Name' ) ) . to . have . value ( 'countries' ) ;
321+ } ) ;
322+
323+ // Find the relationhip item
324+ const relationshipItem = screen
325+ . getByText ( 'countries.name → airports.Country' )
326+ . closest ( 'li' ) ;
327+ expect ( relationshipItem ) . to . be . visible ;
328+
329+ // Delete relationship
330+ userEvent . click (
331+ within ( relationshipItem ! ) . getByRole ( 'button' , {
332+ name : 'Delete relationship' ,
333+ } )
334+ ) ;
335+
336+ await waitFor ( ( ) => {
337+ expect ( screen . queryByText ( 'countries.name → airports.Country' ) ) . not . to
338+ . exist ;
339+ } ) ;
340+ } ) ;
246341 } ) ;
247342
248- it ( 'should delete a relationship from collection' , async function ( ) {
249- const result = renderDrawer ( ) ;
250- result . plugin . store . dispatch ( selectCollection ( 'flights.countries' ) ) ;
343+ describe ( 'Field -> Relationships' , function ( ) {
344+ it ( 'should add a relationship starting from a field' , async function ( ) {
345+ const result = renderDrawer ( ) ;
346+ result . plugin . store . dispatch ( selectField ( 'flights.countries' , [ 'name' ] ) ) ;
251347
252- await waitFor ( ( ) => {
253- expect ( screen . getByLabelText ( 'Name' ) ) . to . have . value ( 'countries' ) ;
348+ await waitFor ( ( ) => {
349+ expect ( screen . getByLabelText ( 'Field name' ) ) . to . have . value ( 'name' ) ;
350+ } ) ;
351+
352+ // Click on add relationship button
353+ userEvent . click ( screen . getByRole ( 'button' , { name : 'Add relationship' } ) ) ;
354+
355+ // Collection and field are pre-selected
356+ expect ( screen . getByLabelText ( 'Local collection' ) ) . to . be . visible ;
357+ expect ( screen . getByLabelText ( 'Local collection' ) ) . to . have . value (
358+ 'countries'
359+ ) ;
360+ expect ( screen . getByLabelText ( 'Local field' ) ) . to . be . visible ;
361+ expect ( screen . getByLabelText ( 'Local field' ) ) . to . have . value ( 'name' ) ;
254362 } ) ;
255363
256- // Find the relationhip item
257- const relationshipItem = screen
258- . getByText ( 'countries.name → airports.Country' )
259- . closest ( 'li' ) ;
260- expect ( relationshipItem ) . to . be . visible ;
261-
262- // Delete relationship
263- userEvent . click (
264- within ( relationshipItem ! ) . getByRole ( 'button' , {
265- name : 'Delete relationship' ,
266- } )
267- ) ;
364+ it ( 'should open a relationship starting from a field' , async function ( ) {
365+ const result = renderDrawer ( ) ;
366+ result . plugin . store . dispatch ( selectField ( 'flights.countries' , [ 'name' ] ) ) ;
367+
368+ await waitFor ( ( ) => {
369+ expect ( screen . getByLabelText ( 'Field name' ) ) . to . have . value ( 'name' ) ;
370+ } ) ;
371+
372+ // Open relationshipt editing form
373+ const relationshipItem = screen
374+ . getByText ( 'airports.Country' )
375+ . closest ( 'li' ) ;
376+ expect ( relationshipItem ) . to . be . visible ;
377+ userEvent . click (
378+ within ( relationshipItem ! ) . getByRole ( 'button' , {
379+ name : 'Edit relationship' ,
380+ } )
381+ ) ;
382+ expect ( screen . getByLabelText ( 'Local field' ) ) . to . be . visible ;
383+ expect ( screen . getByLabelText ( 'Local field' ) ) . to . have . value ( 'name' ) ;
384+ expect ( screen . getByLabelText ( 'Foreign field' ) ) . to . be . visible ;
385+ expect ( screen . getByLabelText ( 'Foreign field' ) ) . to . have . value ( 'Country' ) ;
386+ } ) ;
268387
269- await waitFor ( ( ) => {
270- expect ( screen . queryByText ( 'countries.name → airports.Country' ) ) . not . to
271- . exist ;
388+ it ( 'should delete a relationship from a field' , async function ( ) {
389+ const result = renderDrawer ( ) ;
390+ result . plugin . store . dispatch ( selectField ( 'flights.countries' , [ 'name' ] ) ) ;
391+
392+ await waitFor ( ( ) => {
393+ expect ( screen . getByLabelText ( 'Field name' ) ) . to . have . value ( 'name' ) ;
394+ } ) ;
395+
396+ // Find the relationhip item
397+ const relationshipItem = screen
398+ . getByText ( 'airports.Country' )
399+ . closest ( 'li' ) ;
400+ expect ( relationshipItem ) . to . be . visible ;
401+
402+ // Delete relationship
403+ userEvent . click (
404+ within ( relationshipItem ! ) . getByRole ( 'button' , {
405+ name : 'Delete relationship' ,
406+ } )
407+ ) ;
408+
409+ await waitFor ( ( ) => {
410+ expect ( screen . queryByText ( 'airports.Country' ) ) . not . to . exist ;
411+ } ) ;
272412 } ) ;
273413 } ) ;
274414
0 commit comments