@@ -21,6 +21,7 @@ import {
2121 getSpanRectFromText ,
2222 loadAndWait ,
2323 scrollIntoView ,
24+ showViewsManager ,
2425 waitForPageChanging ,
2526 waitForPageRendered ,
2627} from "./test_utils.mjs" ;
@@ -1451,6 +1452,82 @@ describe("PDF viewer", () => {
14511452 } ) ;
14521453 } ) ;
14531454
1455+ describe ( "Outline tree shift-click toggle (PR 20740)" , ( ) => {
1456+ let pages ;
1457+
1458+ beforeEach ( async ( ) => {
1459+ pages = await loadAndWait (
1460+ "nested_outline.pdf" ,
1461+ "#viewsManagerToggleButton"
1462+ ) ;
1463+ } ) ;
1464+
1465+ afterEach ( async ( ) => {
1466+ await closePages ( pages ) ;
1467+ } ) ;
1468+
1469+ it ( "should only toggle the clicked item's subtree, not the whole outline" , async ( ) => {
1470+ await Promise . all (
1471+ pages . map ( async ( [ browserName , page ] ) => {
1472+ // Open the sidebar.
1473+ await showViewsManager ( page ) ;
1474+
1475+ // Switch to outline view.
1476+ await page . click ( "#viewsManagerSelectorButton" ) ;
1477+ await page . waitForSelector ( "#outlinesViewMenu" , { visible : true } ) ;
1478+ await page . click ( "#outlinesViewMenu" ) ;
1479+
1480+ // Wait for the outline tree to render with nesting (toggle buttons).
1481+ await page . waitForSelector ( "#outlinesView.withNesting" ) ;
1482+
1483+ // Initially all three top-level togglers must be expanded.
1484+ const initialHiddenCount = await page . $$eval (
1485+ "#outlinesView > .treeItem > .treeItemToggler" ,
1486+ togglers =>
1487+ togglers . filter ( t => t . classList . contains ( "treeItemsHidden" ) )
1488+ . length
1489+ ) ;
1490+ expect ( initialHiddenCount ) . withContext ( `In ${ browserName } ` ) . toBe ( 0 ) ;
1491+
1492+ // Shift-click the first top-level toggler (section "1. Introduction")
1493+ // to collapse only its subtree.
1494+ // The toggler has width/height 0 (visual content via ::before), so
1495+ // we dispatch the MouseEvent directly rather than using page.click().
1496+ await page . evaluate ( ( ) => {
1497+ const toggler = document . querySelector (
1498+ "#outlinesView > .treeItem:nth-child(1) > .treeItemToggler"
1499+ ) ;
1500+ toggler . dispatchEvent (
1501+ new MouseEvent ( "click" , {
1502+ shiftKey : true ,
1503+ bubbles : true ,
1504+ cancelable : true ,
1505+ } )
1506+ ) ;
1507+ } ) ;
1508+
1509+ // Section 1's toggler must now be collapsed.
1510+ const section1Collapsed = await page . $eval (
1511+ "#outlinesView > .treeItem:nth-child(1) > .treeItemToggler" ,
1512+ t => t . classList . contains ( "treeItemsHidden" )
1513+ ) ;
1514+ expect ( section1Collapsed ) . withContext ( `In ${ browserName } ` ) . toBeTrue ( ) ;
1515+
1516+ // Sections 2 and 3 must remain expanded (the bug collapsed the whole
1517+ // outline by passing `this.container` instead of
1518+ // `target.parentNode`).
1519+ const otherHiddenCount = await page . $$eval (
1520+ "#outlinesView > .treeItem:nth-child(n+2) > .treeItemToggler" ,
1521+ togglers =>
1522+ togglers . filter ( t => t . classList . contains ( "treeItemsHidden" ) )
1523+ . length
1524+ ) ;
1525+ expect ( otherHiddenCount ) . withContext ( `In ${ browserName } ` ) . toBe ( 0 ) ;
1526+ } )
1527+ ) ;
1528+ } ) ;
1529+ } ) ;
1530+
14541531 describe ( "Scroll into view" , ( ) => {
14551532 let pages ;
14561533
0 commit comments