@@ -127,13 +127,13 @@ describe('ViewConfigPanel', () => {
127127
128128 expect ( screen . getByTestId ( 'view-config-panel' ) ) . toBeInTheDocument ( ) ;
129129
130- // Check section headers
131- expect ( screen . getByText ( 'console.objectView.page' ) ) . toBeInTheDocument ( ) ;
130+ // Check section headers (page appears in both breadcrumb and section)
131+ expect ( screen . getAllByText ( 'console.objectView.page' ) . length ) . toBeGreaterThanOrEqual ( 1 ) ;
132132 expect ( screen . getByText ( 'console.objectView.data' ) ) . toBeInTheDocument ( ) ;
133133 expect ( screen . getByText ( 'console.objectView.appearance' ) ) . toBeInTheDocument ( ) ;
134- expect ( screen . getByText ( 'console.objectView.userFilters' ) ) . toBeInTheDocument ( ) ;
135134 expect ( screen . getByText ( 'console.objectView.userActions' ) ) . toBeInTheDocument ( ) ;
136- expect ( screen . getByText ( 'console.objectView.advanced' ) ) . toBeInTheDocument ( ) ;
135+ // Breadcrumb shows view type label
136+ expect ( screen . getByTestId ( 'panel-breadcrumb' ) ) . toBeInTheDocument ( ) ;
137137 } ) ;
138138
139139 it ( 'displays view title in editable input' , ( ) => {
@@ -186,6 +186,10 @@ describe('ViewConfigPanel', () => {
186186 />
187187 ) ;
188188
189+ // Expand the Fields sub-section by clicking the summary row
190+ const fieldsRow = screen . getByText ( 'console.objectView.fields' ) ;
191+ fireEvent . click ( fieldsRow ) ;
192+
189193 // 3 fields → 3 checkboxes
190194 expect ( screen . getByTestId ( 'column-selector' ) ) . toBeInTheDocument ( ) ;
191195 expect ( screen . getByTestId ( 'col-checkbox-name' ) ) . toBeInTheDocument ( ) ;
@@ -278,6 +282,10 @@ describe('ViewConfigPanel', () => {
278282 />
279283 ) ;
280284
285+ // Expand sort and filter sub-sections
286+ fireEvent . click ( screen . getByText ( 'console.objectView.sortBy' ) ) ;
287+ fireEvent . click ( screen . getByText ( 'console.objectView.filterBy' ) ) ;
288+
281289 // FilterBuilder should have 0 conditions
282290 expect ( screen . getByTestId ( 'mock-filter-builder' ) ) . toHaveAttribute ( 'data-condition-count' , '0' ) ;
283291 // SortBuilder should have 0 items
@@ -457,6 +465,9 @@ describe('ViewConfigPanel', () => {
457465 />
458466 ) ;
459467
468+ // Expand filter sub-section
469+ fireEvent . click ( screen . getByText ( 'console.objectView.filterBy' ) ) ;
470+
460471 const fb = screen . getByTestId ( 'mock-filter-builder' ) ;
461472 expect ( fb ) . toHaveAttribute ( 'data-condition-count' , '1' ) ;
462473 expect ( fb ) . toHaveAttribute ( 'data-field-count' , '3' ) ;
@@ -473,6 +484,9 @@ describe('ViewConfigPanel', () => {
473484 />
474485 ) ;
475486
487+ // Expand sort sub-section
488+ fireEvent . click ( screen . getByText ( 'console.objectView.sortBy' ) ) ;
489+
476490 const sb = screen . getByTestId ( 'mock-sort-builder' ) ;
477491 expect ( sb ) . toHaveAttribute ( 'data-sort-count' , '1' ) ;
478492 expect ( sb ) . toHaveAttribute ( 'data-field-count' , '3' ) ;
@@ -491,6 +505,9 @@ describe('ViewConfigPanel', () => {
491505 />
492506 ) ;
493507
508+ // Expand filter sub-section
509+ fireEvent . click ( screen . getByText ( 'console.objectView.filterBy' ) ) ;
510+
494511 fireEvent . click ( screen . getByTestId ( 'filter-builder-add' ) ) ;
495512 expect ( onViewUpdate ) . toHaveBeenCalledWith ( 'filter' , expect . any ( Array ) ) ;
496513 } ) ;
@@ -507,6 +524,9 @@ describe('ViewConfigPanel', () => {
507524 />
508525 ) ;
509526
527+ // Expand sort sub-section
528+ fireEvent . click ( screen . getByText ( 'console.objectView.sortBy' ) ) ;
529+
510530 fireEvent . click ( screen . getByTestId ( 'sort-builder-add' ) ) ;
511531 expect ( onViewUpdate ) . toHaveBeenCalledWith ( 'sort' , expect . any ( Array ) ) ;
512532 } ) ;
@@ -523,6 +543,9 @@ describe('ViewConfigPanel', () => {
523543 />
524544 ) ;
525545
546+ // Expand the Fields sub-section
547+ fireEvent . click ( screen . getByText ( 'console.objectView.fields' ) ) ;
548+
526549 // Uncheck the 'stage' column
527550 fireEvent . click ( screen . getByTestId ( 'col-checkbox-stage' ) ) ;
528551 expect ( onViewUpdate ) . toHaveBeenCalledWith ( 'columns' , [ 'name' , 'amount' ] ) ;
@@ -717,6 +740,9 @@ describe('ViewConfigPanel', () => {
717740 />
718741 ) ;
719742
743+ // Expand filter sub-section
744+ fireEvent . click ( screen . getByText ( 'console.objectView.filterBy' ) ) ;
745+
720746 const fb = screen . getByTestId ( 'mock-filter-builder' ) ;
721747 expect ( fb ) . toHaveAttribute ( 'data-condition-count' , '2' ) ;
722748 expect ( screen . getByTestId ( 'filter-condition-0' ) ) . toHaveTextContent ( 'stage equals active' ) ;
@@ -736,6 +762,9 @@ describe('ViewConfigPanel', () => {
736762 />
737763 ) ;
738764
765+ // Expand filter sub-section
766+ fireEvent . click ( screen . getByText ( 'console.objectView.filterBy' ) ) ;
767+
739768 const fb = screen . getByTestId ( 'mock-filter-builder' ) ;
740769 expect ( fb ) . toHaveAttribute ( 'data-condition-count' , '2' ) ;
741770 } ) ;
@@ -759,6 +788,9 @@ describe('ViewConfigPanel', () => {
759788 />
760789 ) ;
761790
791+ // Expand filter sub-section
792+ fireEvent . click ( screen . getByText ( 'console.objectView.filterBy' ) ) ;
793+
762794 // The mock FilterBuilder receives normalized fields via data-field-count
763795 const fb = screen . getByTestId ( 'mock-filter-builder' ) ;
764796 expect ( fb ) . toHaveAttribute ( 'data-field-count' , '5' ) ;
@@ -992,4 +1024,243 @@ describe('ViewConfigPanel', () => {
9921024 // Now kanban groupBy should appear
9931025 expect ( screen . getByTestId ( 'type-opt-kanban-groupByField' ) ) . toBeInTheDocument ( ) ;
9941026 } ) ;
1027+
1028+ // ── Breadcrumb header tests ──
1029+
1030+ it ( 'renders breadcrumb header with Page > ViewType' , ( ) => {
1031+ render (
1032+ < ViewConfigPanel
1033+ open = { true }
1034+ onClose = { vi . fn ( ) }
1035+ activeView = { mockActiveView }
1036+ objectDef = { mockObjectDef }
1037+ />
1038+ ) ;
1039+
1040+ const breadcrumb = screen . getByTestId ( 'panel-breadcrumb' ) ;
1041+ expect ( breadcrumb ) . toBeInTheDocument ( ) ;
1042+ expect ( breadcrumb ) . toHaveTextContent ( 'Grid' ) ;
1043+ } ) ;
1044+
1045+ it ( 'breadcrumb updates when view type changes' , ( ) => {
1046+ render (
1047+ < ViewConfigPanel
1048+ open = { true }
1049+ onClose = { vi . fn ( ) }
1050+ activeView = { { ...mockActiveView , type : 'kanban' } }
1051+ objectDef = { mockObjectDef }
1052+ />
1053+ ) ;
1054+
1055+ const breadcrumb = screen . getByTestId ( 'panel-breadcrumb' ) ;
1056+ expect ( breadcrumb ) . toHaveTextContent ( 'Kanban' ) ;
1057+ } ) ;
1058+
1059+ // ── Collapsible section tests ──
1060+
1061+ it ( 'collapses and expands Data section' , ( ) => {
1062+ render (
1063+ < ViewConfigPanel
1064+ open = { true }
1065+ onClose = { vi . fn ( ) }
1066+ activeView = { mockActiveView }
1067+ objectDef = { mockObjectDef }
1068+ />
1069+ ) ;
1070+
1071+ // Data section is expanded by default — source row visible
1072+ expect ( screen . getByText ( 'Opportunity' ) ) . toBeInTheDocument ( ) ;
1073+
1074+ // Click section header to collapse
1075+ const sectionBtn = screen . getByTestId ( 'section-data' ) ;
1076+ fireEvent . click ( sectionBtn ) ;
1077+
1078+ // Source row should be hidden
1079+ expect ( screen . queryByText ( 'Opportunity' ) ) . not . toBeInTheDocument ( ) ;
1080+
1081+ // Click again to expand
1082+ fireEvent . click ( sectionBtn ) ;
1083+ expect ( screen . getByText ( 'Opportunity' ) ) . toBeInTheDocument ( ) ;
1084+ } ) ;
1085+
1086+ it ( 'collapses and expands Appearance section' , ( ) => {
1087+ render (
1088+ < ViewConfigPanel
1089+ open = { true }
1090+ onClose = { vi . fn ( ) }
1091+ activeView = { mockActiveView }
1092+ objectDef = { mockObjectDef }
1093+ />
1094+ ) ;
1095+
1096+ // Appearance section is expanded by default
1097+ expect ( screen . getByTestId ( 'toggle-showDescription' ) ) . toBeInTheDocument ( ) ;
1098+
1099+ // Click section header to collapse
1100+ fireEvent . click ( screen . getByTestId ( 'section-appearance' ) ) ;
1101+
1102+ // Toggle should be hidden
1103+ expect ( screen . queryByTestId ( 'toggle-showDescription' ) ) . not . toBeInTheDocument ( ) ;
1104+ } ) ;
1105+
1106+ // ── Appearance fields tests ──
1107+
1108+ it ( 'renders new appearance fields: color, fieldTextColor, rowHeight, wrapHeaders, collapseAllByDefault' , ( ) => {
1109+ render (
1110+ < ViewConfigPanel
1111+ open = { true }
1112+ onClose = { vi . fn ( ) }
1113+ activeView = { mockActiveView }
1114+ objectDef = { mockObjectDef }
1115+ />
1116+ ) ;
1117+
1118+ expect ( screen . getByTestId ( 'appearance-color' ) ) . toBeInTheDocument ( ) ;
1119+ expect ( screen . getByTestId ( 'appearance-fieldTextColor' ) ) . toBeInTheDocument ( ) ;
1120+ expect ( screen . getByTestId ( 'appearance-rowHeight' ) ) . toBeInTheDocument ( ) ;
1121+ expect ( screen . getByTestId ( 'toggle-wrapHeaders' ) ) . toBeInTheDocument ( ) ;
1122+ expect ( screen . getByTestId ( 'toggle-collapseAllByDefault' ) ) . toBeInTheDocument ( ) ;
1123+ } ) ;
1124+
1125+ it ( 'changes row height via icon buttons' , ( ) => {
1126+ const onViewUpdate = vi . fn ( ) ;
1127+ render (
1128+ < ViewConfigPanel
1129+ open = { true }
1130+ onClose = { vi . fn ( ) }
1131+ activeView = { mockActiveView }
1132+ objectDef = { mockObjectDef }
1133+ onViewUpdate = { onViewUpdate }
1134+ />
1135+ ) ;
1136+
1137+ const mediumBtn = screen . getByTestId ( 'row-height-medium' ) ;
1138+ fireEvent . click ( mediumBtn ) ;
1139+ expect ( onViewUpdate ) . toHaveBeenCalledWith ( 'rowHeight' , 'medium' ) ;
1140+ } ) ;
1141+
1142+ it ( 'toggles wrapHeaders via Switch' , ( ) => {
1143+ const onViewUpdate = vi . fn ( ) ;
1144+ render (
1145+ < ViewConfigPanel
1146+ open = { true }
1147+ onClose = { vi . fn ( ) }
1148+ activeView = { mockActiveView }
1149+ objectDef = { mockObjectDef }
1150+ onViewUpdate = { onViewUpdate }
1151+ />
1152+ ) ;
1153+
1154+ fireEvent . click ( screen . getByTestId ( 'toggle-wrapHeaders' ) ) ;
1155+ expect ( onViewUpdate ) . toHaveBeenCalledWith ( 'wrapHeaders' , true ) ;
1156+ } ) ;
1157+
1158+ // ── User actions fields tests ──
1159+
1160+ it ( 'renders new user action fields: editRecordsInline, addDeleteRecordsInline, clickIntoRecordDetails' , ( ) => {
1161+ render (
1162+ < ViewConfigPanel
1163+ open = { true }
1164+ onClose = { vi . fn ( ) }
1165+ activeView = { mockActiveView }
1166+ objectDef = { mockObjectDef }
1167+ />
1168+ ) ;
1169+
1170+ expect ( screen . getByTestId ( 'toggle-editRecordsInline' ) ) . toBeInTheDocument ( ) ;
1171+ expect ( screen . getByTestId ( 'toggle-addDeleteRecordsInline' ) ) . toBeInTheDocument ( ) ;
1172+ expect ( screen . getByTestId ( 'toggle-clickIntoRecordDetails' ) ) . toBeInTheDocument ( ) ;
1173+ } ) ;
1174+
1175+ it ( 'toggles editRecordsInline via Switch' , ( ) => {
1176+ const onViewUpdate = vi . fn ( ) ;
1177+ render (
1178+ < ViewConfigPanel
1179+ open = { true }
1180+ onClose = { vi . fn ( ) }
1181+ activeView = { mockActiveView }
1182+ objectDef = { mockObjectDef }
1183+ onViewUpdate = { onViewUpdate }
1184+ />
1185+ ) ;
1186+
1187+ fireEvent . click ( screen . getByTestId ( 'toggle-editRecordsInline' ) ) ;
1188+ expect ( onViewUpdate ) . toHaveBeenCalledWith ( 'editRecordsInline' , false ) ;
1189+ } ) ;
1190+
1191+ // ── Data section: Group by and Prefix field tests ──
1192+
1193+ it ( 'renders Group by and Prefix field selectors in Data section' , ( ) => {
1194+ render (
1195+ < ViewConfigPanel
1196+ open = { true }
1197+ onClose = { vi . fn ( ) }
1198+ activeView = { mockActiveView }
1199+ objectDef = { mockObjectDef }
1200+ />
1201+ ) ;
1202+
1203+ expect ( screen . getByTestId ( 'data-groupBy' ) ) . toBeInTheDocument ( ) ;
1204+ expect ( screen . getByTestId ( 'data-prefixField' ) ) . toBeInTheDocument ( ) ;
1205+ } ) ;
1206+
1207+ it ( 'changes groupBy and propagates to kanban type option' , ( ) => {
1208+ const onViewUpdate = vi . fn ( ) ;
1209+ render (
1210+ < ViewConfigPanel
1211+ open = { true }
1212+ onClose = { vi . fn ( ) }
1213+ activeView = { { ...mockActiveView , type : 'kanban' } }
1214+ objectDef = { mockObjectDef }
1215+ onViewUpdate = { onViewUpdate }
1216+ />
1217+ ) ;
1218+
1219+ const groupBySelect = screen . getByTestId ( 'data-groupBy' ) ;
1220+ fireEvent . change ( groupBySelect , { target : { value : 'stage' } } ) ;
1221+
1222+ expect ( onViewUpdate ) . toHaveBeenCalledWith ( 'groupBy' , 'stage' ) ;
1223+ expect ( onViewUpdate ) . toHaveBeenCalledWith ( 'kanban' , expect . objectContaining ( { groupByField : 'stage' } ) ) ;
1224+ } ) ;
1225+
1226+ // ── Calendar endDateField test ──
1227+
1228+ it ( 'shows calendar endDateField when view type is calendar' , ( ) => {
1229+ render (
1230+ < ViewConfigPanel
1231+ open = { true }
1232+ onClose = { vi . fn ( ) }
1233+ activeView = { { ...mockActiveView , type : 'calendar' } }
1234+ objectDef = { mockObjectDef }
1235+ />
1236+ ) ;
1237+
1238+ expect ( screen . getByTestId ( 'type-opt-calendar-startDateField' ) ) . toBeInTheDocument ( ) ;
1239+ expect ( screen . getByTestId ( 'type-opt-calendar-endDateField' ) ) . toBeInTheDocument ( ) ;
1240+ expect ( screen . getByTestId ( 'type-opt-calendar-titleField' ) ) . toBeInTheDocument ( ) ;
1241+ } ) ;
1242+
1243+ // ── Data sub-section expand/collapse tests ──
1244+
1245+ it ( 'expands and collapses sort/filter/fields sub-sections in Data' , ( ) => {
1246+ render (
1247+ < ViewConfigPanel
1248+ open = { true }
1249+ onClose = { vi . fn ( ) }
1250+ activeView = { mockActiveView }
1251+ objectDef = { mockObjectDef }
1252+ />
1253+ ) ;
1254+
1255+ // Sort sub-section starts collapsed
1256+ expect ( screen . queryByTestId ( 'inline-sort-builder' ) ) . not . toBeInTheDocument ( ) ;
1257+
1258+ // Click to expand
1259+ fireEvent . click ( screen . getByText ( 'console.objectView.sortBy' ) ) ;
1260+ expect ( screen . getByTestId ( 'inline-sort-builder' ) ) . toBeInTheDocument ( ) ;
1261+
1262+ // Click again to collapse
1263+ fireEvent . click ( screen . getByText ( 'console.objectView.sortBy' ) ) ;
1264+ expect ( screen . queryByTestId ( 'inline-sort-builder' ) ) . not . toBeInTheDocument ( ) ;
1265+ } ) ;
9951266} ) ;
0 commit comments