@@ -36,15 +36,50 @@ def click_menu_item(locator) -> None:
3636 )
3737
3838
39+ def click_and_wait_for_attribute (
40+ locator , name : str , value : str , timeout : int = 5000
41+ ) -> None :
42+ """Click a control and retry once if the expected attribute does not update."""
43+ for attempt in range (2 ):
44+ locator .evaluate (
45+ "el => { el.scrollIntoView({ block: 'center', inline: 'nearest' }); el.click(); }"
46+ )
47+ try :
48+ expect (locator ).to_have_attribute (name , value , timeout = timeout )
49+ return
50+ except AssertionError :
51+ if attempt == 1 :
52+ raise
53+
54+
55+ def click_and_wait_for_count (locator , target , count : int , timeout : int = 10000 ) -> None :
56+ """Click a control and retry once if the expected target count does not land."""
57+ for attempt in range (2 ):
58+ locator .evaluate (
59+ "el => { el.scrollIntoView({ block: 'center', inline: 'nearest' }); el.click(); }"
60+ )
61+ try :
62+ expect (target ).to_have_count (count , timeout = timeout )
63+ return
64+ except AssertionError :
65+ if attempt == 1 :
66+ raise
67+
68+
3969def open_header_menu (page : Page , trigger_locator , menu_test_id : str ):
4070 """Open a header menu and wait for it to become visible."""
4171 expect (trigger_locator ).to_be_visible (timeout = 5000 )
42- trigger_locator .evaluate (
43- "el => { el.scrollIntoView({ block: 'center', inline: 'nearest' }); el.click(); }"
44- )
4572 menu = page .get_by_test_id (menu_test_id )
46- expect (menu ).to_be_visible (timeout = 5000 )
47- return menu
73+ for attempt in range (2 ):
74+ trigger_locator .evaluate (
75+ "el => { el.scrollIntoView({ block: 'center', inline: 'nearest' }); el.click(); }"
76+ )
77+ try :
78+ expect (menu ).to_be_visible (timeout = 5000 )
79+ return menu
80+ except AssertionError :
81+ if attempt == 1 :
82+ raise
4883
4984
5085def close_header_menu (page : Page , menu_test_id : str ) -> None :
@@ -535,25 +570,34 @@ def test_mixed_row_dimension_collapse_preserves_temporal_state(page_at_app: Page
535570 1 , timeout = 10000
536571 )
537572
538- us_total_row = container .locator ("tr" ).filter (has_text = "US Total" )
573+ us_total_row = container .locator (
574+ 'tr[data-testid="pivot-subtotal-row"]:visible'
575+ ).filter (has_text = "US Total" )
539576 expect (us_total_row ).to_have_count (1 , timeout = 5000 )
540577 us_group_toggle = us_total_row .get_by_test_id ("pivot-group-toggle-US" )
541- us_group_toggle .dispatch_event ("click" )
542- expect (us_group_toggle ).to_have_attribute ("aria-expanded" , "false" , timeout = 5000 )
578+ click_and_wait_for_attribute (us_group_toggle , "aria-expanded" , "false" )
543579 expect (container .get_by_text ("US Total" )).to_be_visible (timeout = 5000 )
544580 expect (container .get_by_test_id ("pivot-temporal-parent-row" )).to_have_count (
545581 0 , timeout = 5000
546582 )
547583
548- us_total_row = container .locator ("tr" ).filter (has_text = "US Total" )
584+ us_total_row = container .locator (
585+ 'tr[data-testid="pivot-subtotal-row"]:visible'
586+ ).filter (has_text = "US Total" )
549587 expect (us_total_row ).to_have_count (1 , timeout = 5000 )
550588 us_group_toggle = us_total_row .get_by_test_id ("pivot-group-toggle-US" )
551589 expect (us_group_toggle ).to_have_attribute ("aria-expanded" , "false" , timeout = 5000 )
552- us_group_toggle .dispatch_event ("click" )
553- expect (us_group_toggle ).to_have_attribute ("aria-expanded" , "true" , timeout = 5000 )
554- expect (container .get_by_test_id ("pivot-temporal-parent-row" )).to_have_count (
555- 1 , timeout = 10000
590+ click_and_wait_for_count (
591+ us_group_toggle ,
592+ container .get_by_test_id ("pivot-temporal-parent-row" ),
593+ 1 ,
594+ timeout = 10000 ,
556595 )
596+ us_total_row = container .locator (
597+ 'tr[data-testid="pivot-subtotal-row"]:visible'
598+ ).filter (has_text = "US Total" )
599+ us_group_toggle = us_total_row .get_by_test_id ("pivot-group-toggle-US" )
600+ expect (us_group_toggle ).to_have_attribute ("aria-expanded" , "true" , timeout = 5000 )
557601
558602
559603def test_drilldown_opens_on_cell_click (page_at_app : Page ):
@@ -1184,6 +1228,15 @@ def _drilldown_sort_button(panel, column_name: str):
11841228 )
11851229
11861230
1231+ def _drilldown_sort_header (panel , column_name : str ):
1232+ """Return the sortable header cell for a drilldown column."""
1233+ return (
1234+ panel .get_by_test_id ("drilldown-table" )
1235+ .locator ("th" )
1236+ .filter (has_text = column_name )
1237+ )
1238+
1239+
11871240def test_drilldown_client_pagination_shows_controls (page_at_app : Page ):
11881241 """Client-only: clicking a cell with >500 records shows pagination controls."""
11891242 page = page_at_app
@@ -1215,8 +1268,11 @@ def test_drilldown_client_sort_orders_full_result_before_pagination(page_at_app:
12151268 page = page_at_app
12161269 _ , panel = _open_drilldown_with_pagination (page , "test_pivot_drilldown_pagination" )
12171270
1271+ revenue_header = _drilldown_sort_header (panel , "Revenue" )
12181272 _drilldown_sort_button (panel , "Revenue" ).click ()
1273+ expect (revenue_header ).to_have_attribute ("aria-sort" , "ascending" , timeout = 5000 )
12191274 _drilldown_sort_button (panel , "Revenue" ).click ()
1275+ expect (revenue_header ).to_have_attribute ("aria-sort" , "descending" , timeout = 5000 )
12201276
12211277 # Fixture values for Alpha/2023 are 10..709 inclusive, so descending page 1
12221278 # starts at 709 and descending page 2 starts at 209 after the first 500 rows.
0 commit comments