@@ -371,80 +371,116 @@ describe('buildViewConfigSchema', () => {
371371 // ── Page Config Section ─────────────────────────────────────────────
372372
373373 describe ( 'pageConfig section' , ( ) => {
374- it ( 'contains expected field keys' , ( ) => {
374+ it ( 'contains expected field keys in spec order' , ( ) => {
375+ const schema = buildSchema ( ) ;
376+ const section = schema . sections . find ( s => s . key === 'pageConfig' ) ! ;
377+ const fieldKeys = section . fields . map ( f => f . key ) ;
378+ // Spec order: label, type, showSearch, showSort, showFilters, showHideFields, showGroup, showColor, showDensity,
379+ // allowExport(_export), navigation, selection, addRecord, showRecordCount, allowPrinting
380+ // description is UI extension (after label)
381+ expect ( fieldKeys ) . toEqual ( [
382+ 'label' , 'description' , 'type' ,
383+ 'showSearch' , 'showSort' , 'showFilters' , 'showHideFields' , 'showGroup' , 'showColor' , 'showDensity' ,
384+ '_export' ,
385+ '_navigationMode' , '_navigationWidth' , '_navigationOpenNewTab' ,
386+ '_selectionType' ,
387+ '_addRecord' ,
388+ 'showRecordCount' , 'allowPrinting' ,
389+ ] ) ;
390+ } ) ;
391+
392+ it ( 'showSort comes before showFilters per spec' , ( ) => {
393+ const schema = buildSchema ( ) ;
394+ const section = schema . sections . find ( s => s . key === 'pageConfig' ) ! ;
395+ const fieldKeys = section . fields . map ( f => f . key ) ;
396+ expect ( fieldKeys . indexOf ( 'showSort' ) ) . toBeLessThan ( fieldKeys . indexOf ( 'showFilters' ) ) ;
397+ } ) ;
398+
399+ it ( '_export comes before _navigationMode per spec' , ( ) => {
375400 const schema = buildSchema ( ) ;
376401 const section = schema . sections . find ( s => s . key === 'pageConfig' ) ! ;
377402 const fieldKeys = section . fields . map ( f => f . key ) ;
378- expect ( fieldKeys ) . toContain ( 'label' ) ;
379- expect ( fieldKeys ) . toContain ( 'description' ) ;
380- expect ( fieldKeys ) . toContain ( 'type' ) ;
381- expect ( fieldKeys ) . toContain ( 'showSearch' ) ;
382- expect ( fieldKeys ) . toContain ( 'showFilters' ) ;
383- expect ( fieldKeys ) . toContain ( 'showSort' ) ;
384- expect ( fieldKeys ) . toContain ( '_navigationMode' ) ;
385- expect ( fieldKeys ) . toContain ( '_selectionType' ) ;
386- expect ( fieldKeys ) . toContain ( '_addRecord' ) ;
387- expect ( fieldKeys ) . toContain ( '_export' ) ;
403+ expect ( fieldKeys . indexOf ( '_export' ) ) . toBeLessThan ( fieldKeys . indexOf ( '_navigationMode' ) ) ;
388404 } ) ;
389405 } ) ;
390406
391407 // ── Data Section ────────────────────────────────────────────────────
392408
393409 describe ( 'data section' , ( ) => {
394- it ( 'contains expected field keys' , ( ) => {
410+ it ( 'contains expected field keys in spec order ' , ( ) => {
395411 const schema = buildSchema ( ) ;
396412 const section = schema . sections . find ( s => s . key === 'data' ) ! ;
397413 const fieldKeys = section . fields . map ( f => f . key ) ;
398- expect ( fieldKeys ) . toContain ( '_source' ) ;
399- expect ( fieldKeys ) . toContain ( '_sortBy' ) ;
400- expect ( fieldKeys ) . toContain ( '_groupBy' ) ;
401- expect ( fieldKeys ) . toContain ( 'prefixField' ) ;
402- expect ( fieldKeys ) . toContain ( '_columns' ) ;
403- expect ( fieldKeys ) . toContain ( '_filterBy' ) ;
404- expect ( fieldKeys ) . toContain ( '_pageSize' ) ;
405- expect ( fieldKeys ) . toContain ( '_pageSizeOptions' ) ;
406- expect ( fieldKeys ) . toContain ( '_searchableFields' ) ;
407- expect ( fieldKeys ) . toContain ( '_filterableFields' ) ;
408- expect ( fieldKeys ) . toContain ( '_hiddenFields' ) ;
409- expect ( fieldKeys ) . toContain ( '_quickFilters' ) ;
410- expect ( fieldKeys ) . toContain ( 'virtualScroll' ) ;
411- expect ( fieldKeys ) . toContain ( '_typeOptions' ) ;
414+ // Spec order: columns, filter, sort, prefixField, pagination, searchableFields, filterableFields,
415+ // hiddenFields, quickFilters, virtualScroll
416+ // _source is UI extension (first), _groupBy is UI extension (after prefixField), _typeOptions is UI extension (last)
417+ expect ( fieldKeys ) . toEqual ( [
418+ '_source' ,
419+ '_columns' , '_filterBy' , '_sortBy' ,
420+ 'prefixField' , '_groupBy' ,
421+ '_pageSize' , '_pageSizeOptions' ,
422+ '_searchableFields' , '_filterableFields' , '_hiddenFields' ,
423+ '_quickFilters' ,
424+ 'virtualScroll' ,
425+ '_typeOptions' ,
426+ ] ) ;
427+ } ) ;
428+
429+ it ( '_columns comes before _filterBy and _sortBy per spec' , ( ) => {
430+ const schema = buildSchema ( ) ;
431+ const section = schema . sections . find ( s => s . key === 'data' ) ! ;
432+ const fieldKeys = section . fields . map ( f => f . key ) ;
433+ expect ( fieldKeys . indexOf ( '_columns' ) ) . toBeLessThan ( fieldKeys . indexOf ( '_filterBy' ) ) ;
434+ expect ( fieldKeys . indexOf ( '_filterBy' ) ) . toBeLessThan ( fieldKeys . indexOf ( '_sortBy' ) ) ;
412435 } ) ;
413436 } ) ;
414437
415438 // ── Appearance Section ──────────────────────────────────────────────
416439
417440 describe ( 'appearance section' , ( ) => {
418- it ( 'contains expected field keys' , ( ) => {
441+ it ( 'contains expected field keys in spec order' , ( ) => {
442+ const schema = buildSchema ( ) ;
443+ const section = schema . sections . find ( s => s . key === 'appearance' ) ! ;
444+ const fieldKeys = section . fields . map ( f => f . key ) ;
445+ // Spec order: striped, bordered, color, wrapHeaders, collapseAllByDefault, fieldTextColor,
446+ // showDescription, resizable, densityMode, rowHeight, conditionalFormatting, emptyState
447+ expect ( fieldKeys ) . toEqual ( [
448+ 'striped' , 'bordered' , 'color' ,
449+ 'wrapHeaders' , 'collapseAllByDefault' ,
450+ 'fieldTextColor' , 'showDescription' ,
451+ 'resizable' , 'densityMode' , 'rowHeight' ,
452+ '_conditionalFormatting' , '_emptyState' ,
453+ ] ) ;
454+ } ) ;
455+
456+ it ( 'striped and bordered come before color per spec' , ( ) => {
419457 const schema = buildSchema ( ) ;
420458 const section = schema . sections . find ( s => s . key === 'appearance' ) ! ;
421459 const fieldKeys = section . fields . map ( f => f . key ) ;
422- expect ( fieldKeys ) . toContain ( 'color' ) ;
423- expect ( fieldKeys ) . toContain ( 'fieldTextColor' ) ;
424- expect ( fieldKeys ) . toContain ( 'rowHeight' ) ;
425- expect ( fieldKeys ) . toContain ( 'wrapHeaders' ) ;
426- expect ( fieldKeys ) . toContain ( 'showDescription' ) ;
427- expect ( fieldKeys ) . toContain ( 'striped' ) ;
428- expect ( fieldKeys ) . toContain ( 'bordered' ) ;
429- expect ( fieldKeys ) . toContain ( 'resizable' ) ;
430- expect ( fieldKeys ) . toContain ( 'densityMode' ) ;
431- expect ( fieldKeys ) . toContain ( '_conditionalFormatting' ) ;
432- expect ( fieldKeys ) . toContain ( '_emptyState' ) ;
460+ expect ( fieldKeys . indexOf ( 'striped' ) ) . toBeLessThan ( fieldKeys . indexOf ( 'color' ) ) ;
461+ expect ( fieldKeys . indexOf ( 'bordered' ) ) . toBeLessThan ( fieldKeys . indexOf ( 'color' ) ) ;
433462 } ) ;
434463 } ) ;
435464
436465 // ── User Actions Section ────────────────────────────────────────────
437466
438467 describe ( 'userActions section' , ( ) => {
439- it ( 'contains expected field keys' , ( ) => {
468+ it ( 'contains expected field keys in spec order' , ( ) => {
469+ const schema = buildSchema ( ) ;
470+ const section = schema . sections . find ( s => s . key === 'userActions' ) ! ;
471+ const fieldKeys = section . fields . map ( f => f . key ) ;
472+ // Spec order: inlineEdit, clickIntoRecordDetails, addDeleteRecordsInline, rowActions, bulkActions
473+ expect ( fieldKeys ) . toEqual ( [
474+ 'inlineEdit' , 'clickIntoRecordDetails' , 'addDeleteRecordsInline' ,
475+ '_rowActions' , '_bulkActions' ,
476+ ] ) ;
477+ } ) ;
478+
479+ it ( 'inlineEdit comes before clickIntoRecordDetails per spec' , ( ) => {
440480 const schema = buildSchema ( ) ;
441481 const section = schema . sections . find ( s => s . key === 'userActions' ) ! ;
442482 const fieldKeys = section . fields . map ( f => f . key ) ;
443- expect ( fieldKeys ) . toContain ( 'clickIntoRecordDetails' ) ;
444- expect ( fieldKeys ) . toContain ( 'inlineEdit' ) ;
445- expect ( fieldKeys ) . toContain ( 'addDeleteRecordsInline' ) ;
446- expect ( fieldKeys ) . toContain ( '_rowActions' ) ;
447- expect ( fieldKeys ) . toContain ( '_bulkActions' ) ;
483+ expect ( fieldKeys . indexOf ( 'inlineEdit' ) ) . toBeLessThan ( fieldKeys . indexOf ( 'clickIntoRecordDetails' ) ) ;
448484 } ) ;
449485 } ) ;
450486
@@ -566,28 +602,98 @@ describe('spec alignment', () => {
566602 return schema . sections . flatMap ( s => s . fields . map ( f => f . key ) ) ;
567603 }
568604
569- it ( 'covers clickIntoRecordDetails from NamedListView spec' , ( ) => {
570- expect ( allFieldKeys ( ) ) . toContain ( 'clickIntoRecordDetails' ) ;
605+ // Comprehensive: every NamedListView spec property must map to a UI field
606+ it ( 'covers ALL NamedListView spec properties' , ( ) => {
607+ const keys = allFieldKeys ( ) ;
608+ // NamedListView properties → UI field keys mapping
609+ const specPropertyToFieldKey : Record < string , string > = {
610+ label : 'label' ,
611+ type : 'type' ,
612+ columns : '_columns' ,
613+ filter : '_filterBy' ,
614+ sort : '_sortBy' ,
615+ showSearch : 'showSearch' ,
616+ showSort : 'showSort' ,
617+ showFilters : 'showFilters' ,
618+ showHideFields : 'showHideFields' ,
619+ showGroup : 'showGroup' ,
620+ showColor : 'showColor' ,
621+ showDensity : 'showDensity' ,
622+ allowExport : '_export' ,
623+ striped : 'striped' ,
624+ bordered : 'bordered' ,
625+ color : 'color' ,
626+ inlineEdit : 'inlineEdit' ,
627+ wrapHeaders : 'wrapHeaders' ,
628+ clickIntoRecordDetails : 'clickIntoRecordDetails' ,
629+ addRecordViaForm : '_addRecord' , // compound field
630+ addDeleteRecordsInline : 'addDeleteRecordsInline' ,
631+ collapseAllByDefault : 'collapseAllByDefault' ,
632+ fieldTextColor : 'fieldTextColor' ,
633+ prefixField : 'prefixField' ,
634+ showDescription : 'showDescription' ,
635+ navigation : '_navigationMode' , // compound: mode/width/openNewTab
636+ selection : '_selectionType' ,
637+ pagination : '_pageSize' , // compound: pageSize/pageSizeOptions
638+ searchableFields : '_searchableFields' ,
639+ filterableFields : '_filterableFields' ,
640+ resizable : 'resizable' ,
641+ densityMode : 'densityMode' ,
642+ rowHeight : 'rowHeight' ,
643+ hiddenFields : '_hiddenFields' ,
644+ exportOptions : '_export' , // compound with allowExport
645+ rowActions : '_rowActions' ,
646+ bulkActions : '_bulkActions' ,
647+ sharing : '_sharingEnabled' , // compound: enabled/visibility
648+ addRecord : '_addRecord' , // compound with addRecordViaForm
649+ conditionalFormatting : '_conditionalFormatting' ,
650+ quickFilters : '_quickFilters' ,
651+ showRecordCount : 'showRecordCount' ,
652+ allowPrinting : 'allowPrinting' ,
653+ virtualScroll : 'virtualScroll' ,
654+ emptyState : '_emptyState' ,
655+ aria : '_ariaLabel' , // compound: label/describedBy/live
656+ } ;
657+ for ( const [ specProp , fieldKey ] of Object . entries ( specPropertyToFieldKey ) ) {
658+ expect ( keys ) . toContain ( fieldKey ) ;
659+ }
571660 } ) ;
572661
573- it ( 'covers all NamedListView toolbar toggles' , ( ) => {
574- const keys = allFieldKeys ( ) ;
662+ it ( 'covers all NamedListView toolbar toggles in order' , ( ) => {
663+ const schema = buildSchema ( ) ;
664+ const section = schema . sections . find ( s => s . key === 'pageConfig' ) ! ;
665+ const keys = section . fields . map ( f => f . key ) ;
575666 const toolbarFields = [
576- 'showSearch' , 'showFilters ' , 'showSort ' ,
667+ 'showSearch' , 'showSort ' , 'showFilters ' ,
577668 'showHideFields' , 'showGroup' , 'showColor' , 'showDensity' ,
578669 ] ;
670+ // All present
579671 for ( const field of toolbarFields ) {
580672 expect ( keys ) . toContain ( field ) ;
581673 }
674+ // Order matches spec
675+ for ( let i = 0 ; i < toolbarFields . length - 1 ; i ++ ) {
676+ expect ( keys . indexOf ( toolbarFields [ i ] ) ) . toBeLessThan ( keys . indexOf ( toolbarFields [ i + 1 ] ) ) ;
677+ }
582678 } ) ;
583679
584- it ( 'covers all NamedListView boolean toggles in userActions' , ( ) => {
680+ it ( 'covers all NamedListView boolean toggles in userActions in spec order ' , ( ) => {
585681 const schema = buildSchema ( ) ;
586682 const section = schema . sections . find ( s => s . key === 'userActions' ) ! ;
587683 const keys = section . fields . map ( f => f . key ) ;
588- expect ( keys ) . toContain ( 'clickIntoRecordDetails' ) ;
589- expect ( keys ) . toContain ( 'inlineEdit' ) ;
590- expect ( keys ) . toContain ( 'addDeleteRecordsInline' ) ;
684+ // Spec order: inlineEdit → clickIntoRecordDetails → addDeleteRecordsInline
685+ expect ( keys . indexOf ( 'inlineEdit' ) ) . toBeLessThan ( keys . indexOf ( 'clickIntoRecordDetails' ) ) ;
686+ expect ( keys . indexOf ( 'clickIntoRecordDetails' ) ) . toBeLessThan ( keys . indexOf ( 'addDeleteRecordsInline' ) ) ;
687+ } ) ;
688+
689+ // Protocol suggestions: UI fields not in NamedListView spec
690+ it ( 'documents UI extension fields not in NamedListView spec' , ( ) => {
691+ const keys = allFieldKeys ( ) ;
692+ // These fields are UI extensions — documented as protocol suggestions
693+ const uiExtensions = [ 'description' , '_source' , '_groupBy' , '_typeOptions' ] ;
694+ for ( const ext of uiExtensions ) {
695+ expect ( keys ) . toContain ( ext ) ;
696+ }
591697 } ) ;
592698 } ) ;
593699} ) ;
0 commit comments