@@ -63,6 +63,20 @@ async function comboboxSelectItem(
63
63
} ) ;
64
64
}
65
65
66
+ async function multiComboboxToggleItem (
67
+ label : string ,
68
+ value : string ,
69
+ visibleLabel = value
70
+ ) {
71
+ userEvent . click ( screen . getByRole ( 'textbox' , { name : label } ) ) ;
72
+ await waitFor ( ( ) => {
73
+ const listbox = screen . getByRole ( 'listbox' ) ;
74
+ expect ( listbox ) . to . be . visible ;
75
+ const option = within ( listbox ) . getByRole ( 'option' , { name : visibleLabel } ) ;
76
+ userEvent . click ( option ) ;
77
+ } ) ;
78
+ }
79
+
66
80
function getMultiComboboxValues ( testId : string ) {
67
81
const combobox = screen . getByTestId ( testId ) ;
68
82
expect ( combobox ) . to . be . visible ;
@@ -166,15 +180,15 @@ describe('DiagramEditorSidePanel', function () {
166
180
it ( 'should render a nested field context drawer' , async function ( ) {
167
181
const result = renderDrawer ( ) ;
168
182
result . plugin . store . dispatch (
169
- selectField ( 'flights.routes' , [ 'airline' , 'id ' ] )
183
+ selectField ( 'flights.routes' , [ 'airline' , '_id ' ] )
170
184
) ;
171
185
172
186
await waitForDrawerToOpen ( ) ;
173
- expect ( screen . getByTitle ( 'routes.airline.id ' ) ) . to . be . visible ;
187
+ expect ( screen . getByTitle ( 'routes.airline._id ' ) ) . to . be . visible ;
174
188
175
189
const nameInput = screen . getByLabelText ( 'Field name' ) ;
176
190
expect ( nameInput ) . to . be . visible ;
177
- expect ( nameInput ) . to . have . value ( 'id ' ) ;
191
+ expect ( nameInput ) . to . have . value ( '_id ' ) ;
178
192
179
193
const selectedTypes = getMultiComboboxValues ( 'lg-combobox-datatype' ) ;
180
194
expect ( selectedTypes ) . to . have . lengthOf ( 1 ) ;
@@ -184,16 +198,16 @@ describe('DiagramEditorSidePanel', function () {
184
198
it ( 'should delete a field' , async function ( ) {
185
199
const result = renderDrawer ( ) ;
186
200
result . plugin . store . dispatch (
187
- selectField ( 'flights.routes' , [ 'airline' , 'id ' ] )
201
+ selectField ( 'flights.routes' , [ 'airline' , '_id ' ] )
188
202
) ;
189
203
190
204
await waitForDrawerToOpen ( ) ;
191
- expect ( screen . getByTitle ( 'routes.airline.id ' ) ) . to . be . visible ;
205
+ expect ( screen . getByTitle ( 'routes.airline._id ' ) ) . to . be . visible ;
192
206
193
207
userEvent . click ( screen . getByLabelText ( / d e l e t e f i e l d / i) ) ;
194
208
195
209
await waitFor ( ( ) => {
196
- expect ( screen . queryByText ( 'routes.airline.id ' ) ) . not . to . exist ;
210
+ expect ( screen . queryByText ( 'routes.airline._id ' ) ) . not . to . exist ;
197
211
} ) ;
198
212
expect ( screen . queryByLabelText ( 'Name' ) ) . to . not . exist ;
199
213
@@ -205,7 +219,7 @@ describe('DiagramEditorSidePanel', function () {
205
219
206
220
expect (
207
221
modifiedCollection ?. jsonSchema . properties ?. airline . properties
208
- ) . to . not . have . property ( 'id ' ) ; // deleted field
222
+ ) . to . not . have . property ( '_id ' ) ; // deleted field
209
223
expect (
210
224
modifiedCollection ?. jsonSchema . properties ?. airline . properties
211
225
) . to . have . property ( 'name' ) ; // sibling field remains
@@ -254,13 +268,139 @@ describe('DiagramEditorSidePanel', function () {
254
268
await waitForDrawerToOpen ( ) ;
255
269
expect ( screen . getByTitle ( 'routes.airline.name' ) ) . to . be . visible ;
256
270
257
- updateInputWithBlur ( 'Field name' , 'id ' ) ;
271
+ updateInputWithBlur ( 'Field name' , '_id ' ) ;
258
272
259
273
await waitFor ( ( ) => {
260
274
expect ( screen . queryByText ( 'Field already exists.' ) ) . to . exist ;
261
275
expect ( screen . queryByText ( 'routes.airline.name' ) ) . to . exist ;
262
276
} ) ;
263
277
} ) ;
278
+
279
+ it ( 'should change the field type' , async function ( ) {
280
+ const result = renderDrawer ( ) ;
281
+ result . plugin . store . dispatch (
282
+ selectField ( 'flights.routes' , [ 'airline' , 'name' ] )
283
+ ) ;
284
+
285
+ await waitForDrawerToOpen ( ) ;
286
+ expect ( screen . getByTitle ( 'routes.airline.name' ) ) . to . be . visible ;
287
+
288
+ // before - string
289
+ const selectedTypesBefore = getMultiComboboxValues (
290
+ 'lg-combobox-datatype'
291
+ ) ;
292
+ expect ( selectedTypesBefore ) . to . have . members ( [ 'string' ] ) ;
293
+
294
+ // add int and bool and remove string
295
+ await multiComboboxToggleItem ( 'Datatype' , 'int' ) ;
296
+ await multiComboboxToggleItem ( 'Datatype' , 'bool' ) ;
297
+ await multiComboboxToggleItem ( 'Datatype' , 'string' ) ;
298
+
299
+ const modifiedCollection = selectCurrentModelFromState (
300
+ result . plugin . store . getState ( )
301
+ ) . collections . find ( ( coll ) => {
302
+ return coll . ns === 'flights.routes' ;
303
+ } ) ;
304
+ expect (
305
+ modifiedCollection ?. jsonSchema . properties ?. airline ?. properties ?. name
306
+ . bsonType
307
+ ) . to . have . members ( [ 'int' , 'bool' ] ) ;
308
+ } ) ;
309
+
310
+ it ( 'should not completely remove the type' , async function ( ) {
311
+ const result = renderDrawer ( ) ;
312
+ result . plugin . store . dispatch (
313
+ selectField ( 'flights.routes' , [ 'airline' , 'name' ] )
314
+ ) ;
315
+
316
+ await waitForDrawerToOpen ( ) ;
317
+ expect ( screen . getByTitle ( 'routes.airline.name' ) ) . to . be . visible ;
318
+
319
+ // before - string
320
+ const selectedTypesBefore = getMultiComboboxValues (
321
+ 'lg-combobox-datatype'
322
+ ) ;
323
+ expect ( selectedTypesBefore ) . to . have . members ( [ 'string' ] ) ;
324
+
325
+ // remove string without adding anything else
326
+ await multiComboboxToggleItem ( 'Datatype' , 'string' ) ;
327
+
328
+ await waitFor ( ( ) => {
329
+ // error message shown
330
+ expect ( screen . queryByText ( 'Field must have a type.' ) ) . to . exist ;
331
+ const modifiedCollection = selectCurrentModelFromState (
332
+ result . plugin . store . getState ( )
333
+ ) . collections . find ( ( coll ) => {
334
+ return coll . ns === 'flights.routes' ;
335
+ } ) ;
336
+ // type remains unchanged
337
+ expect (
338
+ modifiedCollection ?. jsonSchema . properties ?. airline ?. properties ?. name
339
+ . bsonType
340
+ ) . to . equal ( 'string' ) ;
341
+ } ) ;
342
+
343
+ // finally, add some types
344
+ await multiComboboxToggleItem ( 'Datatype' , 'bool' ) ;
345
+ await multiComboboxToggleItem ( 'Datatype' , 'int' ) ;
346
+
347
+ await waitFor ( ( ) => {
348
+ // error goes away
349
+ expect ( screen . queryByText ( 'Field must have a type.' ) ) . not . to . exist ;
350
+ const modifiedCollection = selectCurrentModelFromState (
351
+ result . plugin . store . getState ( )
352
+ ) . collections . find ( ( coll ) => {
353
+ return coll . ns === 'flights.routes' ;
354
+ } ) ;
355
+ // new type applied
356
+ expect (
357
+ modifiedCollection ?. jsonSchema . properties ?. airline ?. properties ?. name
358
+ . bsonType
359
+ ) . to . have . members ( [ 'bool' , 'int' ] ) ;
360
+ } ) ;
361
+ } ) ;
362
+
363
+ it ( 'top level _id field is treated as readonly' , async function ( ) {
364
+ const result = renderDrawer ( ) ;
365
+ result . plugin . store . dispatch ( selectField ( 'flights.routes' , [ '_id' ] ) ) ;
366
+
367
+ await waitForDrawerToOpen ( ) ;
368
+ expect ( screen . getByTitle ( 'routes._id' ) ) . to . be . visible ;
369
+
370
+ expect ( screen . queryByLabelText ( / d e l e t e f i e l d / i) ) . not . to . exist ;
371
+ expect ( screen . getByLabelText ( 'Field name' ) ) . to . have . attribute (
372
+ 'aria-disabled' ,
373
+ 'true'
374
+ ) ;
375
+ expect ( screen . getByLabelText ( 'Datatype' ) ) . to . have . attribute (
376
+ 'aria-disabled' ,
377
+ 'true'
378
+ ) ;
379
+ } ) ;
380
+
381
+ it ( 'nested _id field is not treated as readonly' , async function ( ) {
382
+ const result = renderDrawer ( ) ;
383
+ result . plugin . store . dispatch (
384
+ selectField ( 'flights.routes' , [ 'airline' , '_id' ] )
385
+ ) ;
386
+
387
+ await waitForDrawerToOpen ( ) ;
388
+ expect ( screen . getByTitle ( 'routes.airline._id' ) ) . to . be . visible ;
389
+
390
+ expect ( screen . queryByLabelText ( / d e l e t e f i e l d / i) ) . to . exist ;
391
+ expect ( screen . queryByLabelText ( / d e l e t e f i e l d / i) ) . to . have . attribute (
392
+ 'aria-disabled' ,
393
+ 'false'
394
+ ) ;
395
+ expect ( screen . getByLabelText ( 'Field name' ) ) . to . have . attribute (
396
+ 'aria-disabled' ,
397
+ 'false'
398
+ ) ;
399
+ expect ( screen . getByLabelText ( 'Datatype' ) ) . to . have . attribute (
400
+ 'aria-disabled' ,
401
+ 'false'
402
+ ) ;
403
+ } ) ;
264
404
} ) ;
265
405
266
406
it ( 'should change the content of the drawer when selecting different items' , async function ( ) {
0 commit comments