Merge pull request #20750 from calixteman/pr20740_followup

Add an integration test for PR 20740
This commit is contained in:
calixteman 2026-02-27 17:34:20 +01:00 committed by GitHub
commit 123ed241e6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 102 additions and 30 deletions

View File

@ -28,24 +28,13 @@ import {
kbDelete,
loadAndWait,
scrollIntoView,
showViewsManager,
waitAndClick,
waitForDOMMutation,
} from "./test_utils.mjs";
async function waitForThumbnailVisible(page, pageNums) {
const hasAnimations = await page.evaluate(
() => !window.matchMedia("(prefers-reduced-motion: reduce)").matches
);
await page.click("#viewsManagerToggleButton");
if (hasAnimations) {
await page.waitForSelector("#outerContainer.viewsManagerMoving", {
visible: true,
});
}
await page.waitForSelector(
"#outerContainer:not(.viewsManagerMoving).viewsManagerOpen",
{ visible: true }
);
await showViewsManager(page);
const thumbSelector = "#thumbnailsView .thumbnailImageContainer > img";
await page.waitForSelector(thumbSelector, { visible: true });

View File

@ -964,6 +964,26 @@ async function highlightSpan(
await page.waitForSelector(getEditorSelector(nextId));
}
async function showViewsManager(page) {
const hasAnimations = await page.evaluate(
() => !window.matchMedia("(prefers-reduced-motion: reduce)").matches
);
const movingPromise = hasAnimations
? page.waitForSelector("#outerContainer.viewsManagerMoving", {
visible: true,
})
: Promise.resolve();
await page.click("#viewsManagerToggleButton");
if (hasAnimations) {
await movingPromise;
}
await page.waitForSelector("#viewsManager", { visible: true });
await page.waitForSelector(
"#outerContainer:not(.viewsManagerMoving).viewsManagerOpen",
{ visible: true }
);
}
// Unicode bidi isolation characters, Fluent adds these markers to the text.
const FSI = "\u2068";
const PDI = "\u2069";
@ -1030,6 +1050,7 @@ export {
selectEditors,
serializeBitmapDimensions,
setCaretAt,
showViewsManager,
switchToEditor,
unselectEditor,
waitAndClick,

View File

@ -5,6 +5,7 @@ import {
kbFocusNext,
loadAndWait,
PDI,
showViewsManager,
} from "./test_utils.mjs";
function waitForThumbnailVisible(page, pageNum) {
@ -29,23 +30,6 @@ async function waitForMenu(page, buttonSelector, visible = true) {
);
}
async function showViewsManager(page) {
const hasAnimations = await page.evaluate(
() => !window.matchMedia("(prefers-reduced-motion: reduce)").matches
);
await page.click("#viewsManagerToggleButton");
if (hasAnimations) {
await page.waitForSelector("#outerContainer.viewsManagerMoving", {
visible: true,
});
}
await page.waitForSelector("#viewsManager", { visible: true });
await page.waitForSelector(
"#outerContainer:not(.viewsManagerMoving).viewsManagerOpen",
{ visible: true }
);
}
describe("PDF Thumbnail View", () => {
describe("Works without errors", () => {
let pages;

View File

@ -21,6 +21,7 @@ import {
getSpanRectFromText,
loadAndWait,
scrollIntoView,
showViewsManager,
waitForPageChanging,
waitForPageRendered,
} from "./test_utils.mjs";
@ -1451,6 +1452,82 @@ describe("PDF viewer", () => {
});
});
describe("Outline tree shift-click toggle (PR 20740)", () => {
let pages;
beforeEach(async () => {
pages = await loadAndWait(
"nested_outline.pdf",
"#viewsManagerToggleButton"
);
});
afterEach(async () => {
await closePages(pages);
});
it("should only toggle the clicked item's subtree, not the whole outline", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
// Open the sidebar.
await showViewsManager(page);
// Switch to outline view.
await page.click("#viewsManagerSelectorButton");
await page.waitForSelector("#outlinesViewMenu", { visible: true });
await page.click("#outlinesViewMenu");
// Wait for the outline tree to render with nesting (toggle buttons).
await page.waitForSelector("#outlinesView.withNesting");
// Initially all three top-level togglers must be expanded.
const initialHiddenCount = await page.$$eval(
"#outlinesView > .treeItem > .treeItemToggler",
togglers =>
togglers.filter(t => t.classList.contains("treeItemsHidden"))
.length
);
expect(initialHiddenCount).withContext(`In ${browserName}`).toBe(0);
// Shift-click the first top-level toggler (section "1. Introduction")
// to collapse only its subtree.
// The toggler has width/height 0 (visual content via ::before), so
// we dispatch the MouseEvent directly rather than using page.click().
await page.evaluate(() => {
const toggler = document.querySelector(
"#outlinesView > .treeItem:nth-child(1) > .treeItemToggler"
);
toggler.dispatchEvent(
new MouseEvent("click", {
shiftKey: true,
bubbles: true,
cancelable: true,
})
);
});
// Section 1's toggler must now be collapsed.
const section1Collapsed = await page.$eval(
"#outlinesView > .treeItem:nth-child(1) > .treeItemToggler",
t => t.classList.contains("treeItemsHidden")
);
expect(section1Collapsed).withContext(`In ${browserName}`).toBeTrue();
// Sections 2 and 3 must remain expanded (the bug collapsed the whole
// outline by passing `this.container` instead of
// `target.parentNode`).
const otherHiddenCount = await page.$$eval(
"#outlinesView > .treeItem:nth-child(n+2) > .treeItemToggler",
togglers =>
togglers.filter(t => t.classList.contains("treeItemsHidden"))
.length
);
expect(otherHiddenCount).withContext(`In ${browserName}`).toBe(0);
})
);
});
});
describe("Scroll into view", () => {
let pages;

View File

@ -874,3 +874,4 @@
!bug2013793.pdf
!bug2014080.pdf
!two_pages.pdf
!nested_outline.pdf

Binary file not shown.