@@ -700,3 +700,66 @@ test.describe("pivot run through", () => {
700700 await validateTableContents ( page , "table" , expectSortedDeltaCol , 4 ) ;
701701 } ) ;
702702} ) ;
703+
704+ test . describe ( "pivot expansion persistence" , ( ) => {
705+ test . use ( { project : "AdBids" } ) ;
706+
707+ // Expanded rows are keyed by dimension values, so they survive config
708+ // changes that keep the same rows. Previously any change reset the tree.
709+ // https://github.com/rilldata/rill/issues/9781
710+ test ( "expanded rows survive adding a measure and sorting" , async ( {
711+ page,
712+ } ) => {
713+ test . setTimeout ( 45_000 ) ;
714+ const watcher = new ResourceWatcher ( page ) ;
715+
716+ await gotoNavEntry ( page , "/metrics/AdBids_metrics.yaml" ) ;
717+ await page . getByRole ( "button" , { name : "switch to code editor" } ) . click ( ) ;
718+ await watcher . updateAndWaitForDashboard ( pivotDashboard ) ;
719+ await gotoNavEntry ( page , "/dashboards/AdBids_metrics_explore.yaml" ) ;
720+ await page . getByRole ( "button" , { name : "Preview" } ) . click ( ) ;
721+ await page . getByRole ( "link" , { name : "Pivot" , exact : true } ) . click ( ) ;
722+
723+ const rowZone = page . locator ( ".dnd-zone.horizontal" ) . nth ( 0 ) ;
724+ const columnZone = page . locator ( ".dnd-zone.horizontal" ) . nth ( 1 ) ;
725+ const totalRecords = page . getByLabel ( "Total records pivot chip" , {
726+ exact : true ,
727+ } ) ;
728+ const bidPrice = page . getByLabel ( "Sum of Bid Price pivot chip" , {
729+ exact : true ,
730+ } ) ;
731+ const timeMonth = page . getByLabel ( "Time pivot chip" , { exact : true } ) ;
732+ const publisher = page . getByLabel ( "Publisher pivot chip" , { exact : true } ) ;
733+
734+ // Build rows = Time (month) > Publisher, columns = Total records.
735+ await dragPivotChip ( page , totalRecords , columnZone ) ;
736+ await dragPivotChip ( page , timeMonth , rowZone ) ;
737+ await dragPivotChip ( page , publisher , rowZone ) ;
738+ await expect ( page . locator ( ".status.running" ) ) . toHaveCount ( 0 ) ;
739+
740+ // Expand a month; a nested publisher row becomes visible.
741+ await page . locator ( "td" ) . filter ( { hasText : "Jan" } ) . first ( ) . click ( ) ;
742+ await expect ( page . locator ( ".status.running" ) ) . toHaveCount ( 0 ) ;
743+ await expect (
744+ page . locator ( "td" ) . filter ( { hasText : "Facebook" } ) . first ( ) ,
745+ ) . toBeVisible ( ) ;
746+
747+ // Adding a measure used to collapse the tree; the nested row must remain.
748+ await dragPivotChip ( page , bidPrice , columnZone ) ;
749+ await expect ( page . locator ( ".status.running" ) ) . toHaveCount ( 0 ) ;
750+ await expect (
751+ page . locator ( "td" ) . filter ( { hasText : "Facebook" } ) . first ( ) ,
752+ ) . toBeVisible ( ) ;
753+
754+ // Sorting by a measure used to collapse the tree; still expanded.
755+ await page
756+ . locator ( ".header-cell" )
757+ . filter ( { hasText : "Total records" } )
758+ . first ( )
759+ . click ( ) ;
760+ await expect ( page . locator ( ".status.running" ) ) . toHaveCount ( 0 ) ;
761+ await expect (
762+ page . locator ( "td" ) . filter ( { hasText : "Facebook" } ) . first ( ) ,
763+ ) . toBeVisible ( ) ;
764+ } ) ;
765+ } ) ;
0 commit comments