From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../test/browser/browser_pdfjs_preview.js | 753 +++++++++++++++++++++ 1 file changed, 753 insertions(+) create mode 100644 browser/components/downloads/test/browser/browser_pdfjs_preview.js (limited to 'browser/components/downloads/test/browser/browser_pdfjs_preview.js') diff --git a/browser/components/downloads/test/browser/browser_pdfjs_preview.js b/browser/components/downloads/test/browser/browser_pdfjs_preview.js new file mode 100644 index 0000000000..cbd8516468 --- /dev/null +++ b/browser/components/downloads/test/browser/browser_pdfjs_preview.js @@ -0,0 +1,753 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +let gDownloadDir; + +// The test is long, and it's not worth splitting it since all the tests share +// the same boilerplate code. +requestLongerTimeout(4); + +SimpleTest.requestFlakyTimeout( + "Giving a chance for possible last-pb-context-exited to occur (Bug 1329912)" +); + +/* + Coverage for opening downloaded PDFs from download views +*/ + +const TestCases = [ + { + name: "Download panel, default click behavior", + whichUI: "downloadPanel", + itemSelector: "#downloadsListBox richlistitem .downloadMainArea", + async userEvents(itemTarget, win) { + EventUtils.synthesizeMouseAtCenter(itemTarget, {}, win); + }, + expected: { + downloadCount: 1, + newWindow: false, + opensTab: true, + tabSelected: true, + }, + }, + { + name: "Download panel, system viewer menu items prefd off", + whichUI: "downloadPanel", + itemSelector: "#downloadsListBox richlistitem .downloadMainArea", + async userEvents(itemTarget, win) { + EventUtils.synthesizeMouseAtCenter(itemTarget, {}, win); + }, + prefs: [ + ["browser.download.openInSystemViewerContextMenuItem", false], + ["browser.download.alwaysOpenInSystemViewerContextMenuItem", false], + ], + expected: { + downloadCount: 1, + newWindow: false, + opensTab: true, + tabSelected: true, + useSystemMenuItemDisabled: true, + alwaysMenuItemDisabled: true, + }, + }, + { + name: "Download panel, open from keyboard", + whichUI: "downloadPanel", + itemSelector: "#downloadsListBox richlistitem .downloadMainArea", + async userEvents(itemTarget, win) { + itemTarget.focus(); + EventUtils.synthesizeKey("VK_RETURN", {}, win); + }, + expected: { + downloadCount: 1, + newWindow: false, + opensTab: true, + tabSelected: true, + }, + }, + { + name: "Download panel, open in new window", + whichUI: "downloadPanel", + itemSelector: "#downloadsListBox richlistitem .downloadMainArea", + async userEvents(itemTarget, win) { + EventUtils.synthesizeMouseAtCenter(itemTarget, { shiftKey: true }, win); + }, + expected: { + downloadCount: 1, + newWindow: true, + opensTab: false, + tabSelected: true, + }, + }, + { + name: "Download panel, open foreground tab", // duplicates the default behavior + whichUI: "downloadPanel", + itemSelector: "#downloadsListBox richlistitem .downloadMainArea", + async userEvents(itemTarget, win) { + EventUtils.synthesizeMouseAtCenter( + itemTarget, + { ctrlKey: true, metaKey: true }, + win + ); + }, + expected: { + downloadCount: 1, + newWindow: false, + opensTab: true, + tabSelected: true, + }, + }, + { + name: "Download panel, open background tab", + whichUI: "downloadPanel", + itemSelector: "#downloadsListBox richlistitem .downloadMainArea", + async userEvents(itemTarget, win) { + EventUtils.synthesizeMouseAtCenter( + itemTarget, + { ctrlKey: true, metaKey: true, shiftKey: true }, + win + ); + }, + expected: { + downloadCount: 1, + newWindow: false, + opensTab: true, + tabSelected: false, + }, + }, + + { + name: "Library all downloads dialog, default click behavior", + whichUI: "allDownloads", + async userEvents(itemTarget, win) { + // double click + await triggerDblclickOn(itemTarget, {}, win); + }, + expected: { + downloadCount: 1, + newWindow: false, + opensTab: true, + tabSelected: true, + }, + }, + { + name: "Library all downloads dialog, system viewer menu items prefd off", + whichUI: "allDownloads", + async userEvents(itemTarget, win) { + // double click + await triggerDblclickOn(itemTarget, {}, win); + }, + prefs: [ + ["browser.download.openInSystemViewerContextMenuItem", false], + ["browser.download.alwaysOpenInSystemViewerContextMenuItem", false], + ], + expected: { + downloadCount: 1, + newWindow: false, + opensTab: true, + tabSelected: true, + useSystemMenuItemDisabled: true, + alwaysMenuItemDisabled: true, + }, + }, + { + name: "Library all downloads dialog, open from keyboard", + whichUI: "allDownloads", + async userEvents(itemTarget, win) { + itemTarget.focus(); + EventUtils.synthesizeKey("VK_RETURN", {}, win); + }, + expected: { + downloadCount: 1, + newWindow: false, + opensTab: true, + tabSelected: true, + }, + }, + { + name: "Library all downloads dialog, open in new window", + whichUI: "allDownloads", + async userEvents(itemTarget, win) { + // double click + await triggerDblclickOn(itemTarget, { shiftKey: true }, win); + }, + expected: { + downloadCount: 1, + newWindow: true, + opensTab: false, + tabSelected: true, + }, + }, + { + name: "Library all downloads dialog, open foreground tab", // duplicates default behavior + whichUI: "allDownloads", + async userEvents(itemTarget, win) { + // double click + await triggerDblclickOn( + itemTarget, + { ctrlKey: true, metaKey: true }, + win + ); + }, + expected: { + downloadCount: 1, + newWindow: false, + opensTab: true, + tabSelected: true, + }, + }, + { + name: "Library all downloads dialog, open background tab", + whichUI: "allDownloads", + async userEvents(itemTarget, win) { + // double click + await triggerDblclickOn( + itemTarget, + { ctrlKey: true, metaKey: true, shiftKey: true }, + win + ); + }, + expected: { + downloadCount: 1, + newWindow: false, + opensTab: true, + tabSelected: false, + }, + }, + { + name: "about:downloads, default click behavior", + whichUI: "aboutDownloads", + itemSelector: "#downloadsListBox richlistitem .downloadContainer", + async userEvents(itemSelector, win) { + let browser = win.gBrowser.selectedBrowser; + is(browser.currentURI.spec, "about:downloads"); + await contentTriggerDblclickOn(itemSelector, {}, browser); + }, + expected: { + downloadCount: 1, + newWindow: false, + opensTab: true, + tabSelected: true, + }, + }, + { + name: "about:downloads, system viewer menu items prefd off", + whichUI: "aboutDownloads", + itemSelector: "#downloadsListBox richlistitem .downloadContainer", + async userEvents(itemSelector, win) { + let browser = win.gBrowser.selectedBrowser; + is(browser.currentURI.spec, "about:downloads"); + await contentTriggerDblclickOn(itemSelector, {}, browser); + }, + prefs: [ + ["browser.download.openInSystemViewerContextMenuItem", false], + ["browser.download.alwaysOpenInSystemViewerContextMenuItem", false], + ], + expected: { + downloadCount: 1, + newWindow: false, + opensTab: true, + tabSelected: true, + useSystemMenuItemDisabled: true, + alwaysMenuItemDisabled: true, + }, + }, + { + name: "about:downloads, open in new window", + whichUI: "aboutDownloads", + itemSelector: "#downloadsListBox richlistitem .downloadContainer", + async userEvents(itemSelector, win) { + let browser = win.gBrowser.selectedBrowser; + is(browser.currentURI.spec, "about:downloads"); + await contentTriggerDblclickOn(itemSelector, { shiftKey: true }, browser); + }, + expected: { + downloadCount: 1, + newWindow: true, + opensTab: false, + tabSelected: true, + }, + }, + { + name: "about:downloads, open in foreground tab", + whichUI: "aboutDownloads", + itemSelector: "#downloadsListBox richlistitem .downloadContainer", + async userEvents(itemSelector, win) { + let browser = win.gBrowser.selectedBrowser; + is(browser.currentURI.spec, "about:downloads"); + await contentTriggerDblclickOn( + itemSelector, + { ctrlKey: true, metaKey: true }, + browser + ); + }, + expected: { + downloadCount: 1, + newWindow: false, + opensTab: true, + tabSelected: true, + }, + }, + { + name: "about:downloads, open in background tab", + whichUI: "aboutDownloads", + itemSelector: "#downloadsListBox richlistitem .downloadContainer", + async userEvents(itemSelector, win) { + let browser = win.gBrowser.selectedBrowser; + is(browser.currentURI.spec, "about:downloads"); + await contentTriggerDblclickOn( + itemSelector, + { ctrlKey: true, metaKey: true, shiftKey: true }, + browser + ); + }, + expected: { + downloadCount: 1, + newWindow: false, + opensTab: true, + tabSelected: false, + }, + }, + { + name: "Private download in about:downloads, opens in new private window", + skip: true, // Bug 1641770 + whichUI: "aboutDownloads", + itemSelector: "#downloadsListBox richlistitem .downloadContainer", + async userEvents(itemSelector, win) { + let browser = win.gBrowser.selectedBrowser; + is(browser.currentURI.spec, "about:downloads"); + await contentTriggerDblclickOn(itemSelector, { shiftKey: true }, browser); + }, + isPrivate: true, + expected: { + downloadCount: 1, + newWindow: true, + opensTab: false, + tabSelected: true, + }, + }, +]; + +function triggerDblclickOn(target, modifiers = {}, win) { + let promise = BrowserTestUtils.waitForEvent(target, "dblclick"); + EventUtils.synthesizeMouseAtCenter( + target, + Object.assign({ clickCount: 1 }, modifiers), + win + ); + EventUtils.synthesizeMouseAtCenter( + target, + Object.assign({ clickCount: 2 }, modifiers), + win + ); + return promise; +} + +function contentTriggerDblclickOn(selector, eventModifiers = {}, browser) { + return SpecialPowers.spawn( + browser, + [selector, eventModifiers], + async function (itemSelector, modifiers) { + const EventUtils = ContentTaskUtils.getEventUtils(content); + let itemTarget = content.document.querySelector(itemSelector); + ok(itemTarget, "Download item target exists"); + + let doubleClicked = ContentTaskUtils.waitForEvent(itemTarget, "dblclick"); + // NOTE: we are using sendMouseEvent instead of synthesizeMouseAtCenter + // here to prevent an unexpected timeout failure in devedition builds + // due to the ContentTaskUtils.waitForEvent promise never been resolved. + EventUtils.sendMouseEvent( + { type: "dblclick", ...modifiers }, + itemTarget, + content + ); + info("Waiting for double-click content task"); + await doubleClicked; + } + ); +} + +async function verifyContextMenu(contextMenu, expected = {}) { + info("verifyContextMenu with expected: " + JSON.stringify(expected, null, 2)); + let alwaysMenuItem = contextMenu.querySelector( + ".downloadAlwaysUseSystemDefaultMenuItem" + ); + let useSystemMenuItem = contextMenu.querySelector( + ".downloadUseSystemDefaultMenuItem" + ); + info("Waiting for the context menu to show up"); + await TestUtils.waitForCondition( + () => BrowserTestUtils.is_visible(contextMenu), + "The context menu is visible" + ); + await TestUtils.waitForTick(); + + info("Checking visibility of the system viewer menu items"); + is( + BrowserTestUtils.is_hidden(useSystemMenuItem), + expected.useSystemMenuItemDisabled, + `The 'Use system viewer' menu item was ${ + expected.useSystemMenuItemDisabled ? "hidden" : "visible" + }` + ); + is( + BrowserTestUtils.is_hidden(alwaysMenuItem), + expected.alwaysMenuItemDisabled, + `The 'Use system viewer' menu item was ${ + expected.alwaysMenuItemDisabled ? "hidden" : "visible" + }` + ); + + if (!expected.useSystemMenuItemDisabled && expected.alwaysChecked) { + is( + alwaysMenuItem.getAttribute("checked"), + "true", + "The 'Always...' menu item is checked" + ); + } else if (!expected.useSystemMenuItemDisabled) { + ok( + !alwaysMenuItem.hasAttribute("checked"), + "The 'Always...' menu item not checked" + ); + } +} + +async function addPDFDownload(itemData) { + let startTimeMs = Date.now(); + info("addPDFDownload with itemData: " + JSON.stringify(itemData, null, 2)); + + let downloadPathname = PathUtils.join(gDownloadDir, itemData.targetFilename); + delete itemData.targetFilename; + + info("Creating saved download file at:" + downloadPathname); + let pdfFile = await createDownloadedFile(downloadPathname, DATA_PDF); + info("Created file at:" + pdfFile.path); + + let downloadList = await Downloads.getList( + itemData.isPrivate ? Downloads.PRIVATE : Downloads.PUBLIC + ); + let download = { + source: { + url: "https://example.com/some.pdf", + isPrivate: itemData.isPrivate, + }, + target: { + path: pdfFile.path, + }, + succeeded: DownloadsCommon.DOWNLOAD_FINISHED, + canceled: false, + error: null, + hasPartialData: false, + hasBlockedData: itemData.hasBlockedData || false, + startTime: new Date(startTimeMs++), + ...itemData, + }; + if (itemData.errorObj) { + download.errorObj = itemData.errorObj; + } + + await downloadList.add(await Downloads.createDownload(download)); + return download; +} + +async function testSetup() { + // remove download files, empty out collections + let downloadList = await Downloads.getList(Downloads.ALL); + let downloadCount = (await downloadList.getAll()).length; + is(downloadCount, 0, "At the start of the test, there should be 0 downloads"); + + await task_resetState(); + if (!gDownloadDir) { + gDownloadDir = await setDownloadDir(); + } + info("Created download directory: " + gDownloadDir); +} + +async function openDownloadPanel(expectedItemCount) { + // Open the user interface and wait for data to be fully loaded. + let richlistbox = document.getElementById("downloadsListBox"); + await task_openPanel(); + await TestUtils.waitForCondition( + () => + richlistbox.childElementCount == expectedItemCount && + !richlistbox.getAttribute("disabled") + ); +} + +async function testOpenPDFPreview({ + name, + whichUI, + downloadProperties, + itemSelector, + expected, + prefs = [], + userEvents, + isPrivate, +}) { + info("Test case: " + name); + // Wait for focus first + await promiseFocus(); + await testSetup(); + if (prefs.length) { + await SpecialPowers.pushPrefEnv({ + set: prefs, + }); + } + + // Populate downloads database with the data required by this test. + info("Adding download objects"); + if (!downloadProperties) { + downloadProperties = { + targetFilename: "downloaded.pdf", + }; + } + let download = await addPDFDownload({ + ...downloadProperties, + isPrivate, + }); + info("Got download pathname:" + download.target.path); + is( + !!download.source.isPrivate, + !!isPrivate, + `Added download is ${isPrivate ? "private" : "not private"} as expected` + ); + let downloadList = await Downloads.getList( + isPrivate ? Downloads.PRIVATE : Downloads.PUBLIC + ); + let downloads = await downloadList.getAll(); + is( + downloads.length, + expected.downloadCount, + `${isPrivate ? "Private" : "Public"} list has expected ${ + downloads.length + } downloads` + ); + + let pdfFileURI = NetUtil.newURI(new FileUtils.File(download.target.path)); + info("pdfFileURI:" + pdfFileURI.spec); + + let uiWindow = window; + let previewWindow = window; + // we never want to unload the test browser by loading the file: URI into it + await BrowserTestUtils.withNewTab("about:blank", async initialBrowser => { + let previewTab; + let previewHappened; + + if (expected.newWindow) { + info( + "previewHappened will wait for new browser window with url: " + + pdfFileURI.spec + ); + // wait for a new browser window + previewHappened = BrowserTestUtils.waitForNewWindow({ + anyWindow: true, + url: pdfFileURI.spec, + }); + } else if (expected.opensTab) { + // wait for a tab to be opened + info("previewHappened will wait for tab with URI:" + pdfFileURI.spec); + previewHappened = BrowserTestUtils.waitForNewTab( + gBrowser, + pdfFileURI.spec, + false, // dont wait for load + true // any tab, not just the next one + ); + } else { + info( + "previewHappened will wait to load " + + pdfFileURI.spec + + " into the current tab" + ); + previewHappened = BrowserTestUtils.browserLoaded( + initialBrowser, + false, + pdfFileURI.spec + ); + } + + let itemTarget; + let contextMenu; + + switch (whichUI) { + case "downloadPanel": + info("Opening download panel"); + await openDownloadPanel(expected.downloadCount); + info("/Opening download panel"); + itemTarget = document.querySelector(itemSelector); + contextMenu = uiWindow.document.querySelector("#downloadsContextMenu"); + + break; + case "allDownloads": + // we'll be interacting with the library dialog + uiWindow = await openLibrary("Downloads"); + + let listbox = uiWindow.document.getElementById("downloadsListBox"); + ok(listbox, "download list box present"); + // wait for the expected number of items in the view, + // and for the first item to be visible && clickable + await TestUtils.waitForCondition(() => { + return ( + listbox.itemChildren.length == expected.downloadCount && + BrowserTestUtils.is_visible(listbox.itemChildren[0]) + ); + }); + itemTarget = listbox.itemChildren[0]; + contextMenu = uiWindow.document.querySelector("#downloadsContextMenu"); + + break; + case "aboutDownloads": + info("Preparing about:downloads browser window"); + + // Because of bug 1329912, we sometimes get a bogus last-pb-context-exited notification + // which removes all the private downloads and about:downloads renders a empty list + // we'll allow time for that to happen before loading about:downloads + let pbExitedOrTimeout = isPrivate + ? new Promise(resolve => { + const topic = "last-pb-context-exited"; + const ENOUGH_TIME = 1000; + function observer() { + info(`Bogus ${topic} observed`); + done(); + } + function done() { + clearTimeout(timerId); + Services.obs.removeObserver(observer, topic); + resolve(); + } + /* eslint-disable mozilla/no-arbitrary-setTimeout */ + const timerId = setTimeout(done, ENOUGH_TIME); + Services.obs.addObserver(observer, "last-pb-context-exited"); + }) + : Promise.resolve(); + + if (isPrivate) { + uiWindow = await BrowserTestUtils.openNewBrowserWindow({ + private: true, + }); + } + info( + "in aboutDownloads, initially there are tabs: " + + uiWindow.gBrowser.tabs.length + ); + + let browser = uiWindow.gBrowser.selectedBrowser; + await pbExitedOrTimeout; + + info("Loading about:downloads"); + let downloadsLoaded = BrowserTestUtils.waitForEvent( + browser, + "InitialDownloadsLoaded", + true + ); + BrowserTestUtils.loadURIString(browser, "about:downloads"); + await BrowserTestUtils.browserLoaded(browser); + info("waiting for downloadsLoaded"); + await downloadsLoaded; + + await ContentTask.spawn( + browser, + [expected.downloadCount], + async function awaitListItems(expectedCount) { + await ContentTaskUtils.waitForCondition( + () => + content.document.getElementById("downloadsListBox") + .childElementCount == expectedCount, + `Await ${expectedCount} download list items` + ); + } + ); + break; + } + + if (contextMenu) { + info("trigger the contextmenu"); + await openContextMenu(itemTarget || itemSelector, uiWindow); + info("context menu should be open, verify its menu items"); + let expectedValues = { + useSystemMenuItemDisabled: false, + alwaysMenuItemDisabled: false, + ...expected, + }; + await verifyContextMenu(contextMenu, expectedValues); + contextMenu.hidePopup(); + } else { + todo(contextMenu, "No context menu checks for test: " + name); + } + + info("Executing user events"); + await userEvents(itemTarget || itemSelector, uiWindow); + + info("Waiting for previewHappened"); + let results = await previewHappened; + if (expected.newWindow) { + previewWindow = results; + info("New window expected, got previewWindow? " + previewWindow); + } + previewTab = + previewWindow.gBrowser.tabs[previewWindow.gBrowser.tabs.length - 1]; + ok(previewTab, "Got preview tab"); + + let isSelected = previewWindow.gBrowser.selectedTab == previewTab; + if (expected.tabSelected) { + ok(isSelected, "The preview tab was selected"); + } else { + ok(!isSelected, "The preview tab was opened in the background"); + } + + is( + previewTab.linkedBrowser.currentURI.spec, + pdfFileURI.spec, + "previewTab has the expected currentURI" + ); + + is( + PrivateBrowsingUtils.isBrowserPrivate(previewTab.linkedBrowser), + !!isPrivate, + `The preview tab was ${isPrivate ? "private" : "not private"} as expected` + ); + + info("cleaning up"); + if (whichUI == "downloadPanel") { + DownloadsPanel.hidePanel(); + } + let lastPBContextExitedPromise = isPrivate + ? TestUtils.topicObserved("last-pb-context-exited").then(() => + TestUtils.waitForTick() + ) + : Promise.resolve(); + + info("Test opened a new UI window? " + (uiWindow !== window)); + if (uiWindow !== window) { + info("Closing uiWindow"); + await BrowserTestUtils.closeWindow(uiWindow); + } + if (expected.newWindow) { + // will also close the previewTab + await BrowserTestUtils.closeWindow(previewWindow); + } else { + await BrowserTestUtils.removeTab(previewTab); + } + info("Waiting for lastPBContextExitedPromise"); + await lastPBContextExitedPromise; + }); + await downloadList.removeFinished(); + if (prefs.length) { + await SpecialPowers.popPrefEnv(); + } +} + +// register the tests +for (let testData of TestCases) { + if (testData.skip) { + info("Skipping test:" + testData.name); + continue; + } + // use the 'name' property of each test case as the test function name + // so we get useful logs + let tmp = { + async [testData.name]() { + await testOpenPDFPreview(testData); + }, + }; + add_task(tmp[testData.name]); +} -- cgit v1.2.3