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 --- .../browser_shows_where_to_save_dialog.js | 303 +++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 uriloader/exthandler/tests/mochitest/browser_shows_where_to_save_dialog.js (limited to 'uriloader/exthandler/tests/mochitest/browser_shows_where_to_save_dialog.js') diff --git a/uriloader/exthandler/tests/mochitest/browser_shows_where_to_save_dialog.js b/uriloader/exthandler/tests/mochitest/browser_shows_where_to_save_dialog.js new file mode 100644 index 0000000000..6bf375dfff --- /dev/null +++ b/uriloader/exthandler/tests/mochitest/browser_shows_where_to_save_dialog.js @@ -0,0 +1,303 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { DownloadIntegration } = ChromeUtils.importESModule( + "resource://gre/modules/DownloadIntegration.sys.mjs" +); + +const TEST_PATH = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" +); + +const { handleInternally, useHelperApp, useSystemDefault, saveToDisk } = + Ci.nsIHandlerInfo; + +let MockFilePicker = SpecialPowers.MockFilePicker; +MockFilePicker.init(window); + +add_setup(async function () { + await SpecialPowers.pushPrefEnv({ + set: [ + ["browser.download.always_ask_before_handling_new_types", false], + ["browser.download.useDownloadDir", false], + ], + }); + + registerCleanupFunction(async () => { + let hiddenPromise = BrowserTestUtils.waitForEvent( + DownloadsPanel.panel, + "popuphidden" + ); + DownloadsPanel.hidePanel(); + await hiddenPromise; + MockFilePicker.cleanup(); + }); +}); + +// This test ensures that a "Save as..." filepicker dialog is shown for a file +// if useDownloadDir ("Always ask where to save files") is set to false and +// the filetype is set to save to disk. +add_task(async function aDownloadSavedToDiskPromptsForFolder() { + let publicList = await Downloads.getList(Downloads.PUBLIC); + ensureMIMEState( + { preferredAction: saveToDisk }, + { type: "text/plain", ext: "txt" } + ); + registerCleanupFunction(async () => { + await publicList.removeFinished(); + }); + let filePickerShownPromise = new Promise(resolve => { + MockFilePicker.showCallback = function (fp) { + setTimeout(resolve, 0); + return Ci.nsIFilePicker.returnCancel; + }; + }); + + let loadingTab = await BrowserTestUtils.openNewForegroundTab({ + gBrowser, + opening: TEST_PATH + "file_txt_attachment_test.txt", + waitForLoad: false, + waitForStateStop: true, + }); + + info("Waiting on filepicker."); + await filePickerShownPromise; + ok(true, "filepicker should have been shown"); + + BrowserTestUtils.removeTab(loadingTab); +}); + +// This test ensures that downloads configured to open internally create only +// one file destination when saved via the filepicker, and don't prompt. +add_task(async function testFilesHandledInternally() { + let dir = await setupFilePickerDirectory(); + + ensureMIMEState( + { preferredAction: handleInternally }, + { type: "image/webp", ext: "webp" } + ); + + let filePickerShown = false; + MockFilePicker.showCallback = function (fp) { + filePickerShown = true; + return Ci.nsIFilePicker.returnCancel; + }; + + let thirdTabPromise = BrowserTestUtils.waitForNewTab( + gBrowser, + url => { + info("Got load for " + url); + return url.endsWith("file_green.webp") && url.startsWith("file:"); + }, + true, + true + ); + let loadingTab = await BrowserTestUtils.openNewForegroundTab({ + gBrowser, + opening: TEST_PATH + "file_green.webp", + waitForLoad: false, + waitForStateStop: true, + }); + + let openedTab = await thirdTabPromise; + ok(!filePickerShown, "file picker should not have shown up."); + + assertCorrectFile(dir, "file_green.webp"); + + // Cleanup + BrowserTestUtils.removeTab(loadingTab); + BrowserTestUtils.removeTab(openedTab); +}); + +// This test ensures that downloads configured to open with a system default +// app create only one file destination and don't open the filepicker. +add_task(async function testFilesHandledBySystemDefaultApp() { + let dir = await setupFilePickerDirectory(); + + ensureMIMEState({ preferredAction: useSystemDefault }); + + let filePickerShown = false; + MockFilePicker.showCallback = function (fp) { + filePickerShown = true; + return Ci.nsIFilePicker.returnCancel; + }; + + let oldLaunchFile = DownloadIntegration.launchFile; + let launchFileCalled = new Promise(resolve => { + DownloadIntegration.launchFile = async (file, mimeInfo) => { + is( + useSystemDefault, + mimeInfo.preferredAction, + "The file should be launched with a system app handler." + ); + resolve(); + }; + }); + + let loadingTab = await BrowserTestUtils.openNewForegroundTab({ + gBrowser, + opening: TEST_PATH + "file_pdf_application_pdf.pdf", + waitForLoad: false, + waitForStateStop: true, + }); + + await launchFileCalled; + ok(!filePickerShown, "file picker should not have shown up."); + + assertCorrectFile(dir, "file_pdf_application_pdf.pdf"); + + // Cleanup + BrowserTestUtils.removeTab(loadingTab); + DownloadIntegration.launchFile = oldLaunchFile; +}); + +// This test ensures that downloads configured to open with a helper app create +// only one file destination when saved via the filepicker. +add_task(async function testFilesHandledByHelperApp() { + let dir = await setupFilePickerDirectory(); + + // Create a custom helper app so we can check that a launcherPath is + // configured for the serialized download. + let appHandler = Cc[ + "@mozilla.org/uriloader/local-handler-app;1" + ].createInstance(Ci.nsILocalHandlerApp); + appHandler.name = "Dummy Test Handler"; + appHandler.executable = Services.dirsvc.get("ProfD", Ci.nsIFile); + appHandler.executable.append("helper_handler_test.exe"); + + if (!appHandler.executable.exists()) { + appHandler.executable.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o777); + } + + ensureMIMEState({ + preferredAction: useHelperApp, + preferredHandlerApp: appHandler, + }); + + let filePickerShown = false; + MockFilePicker.showCallback = function (fp) { + filePickerShown = true; + return Ci.nsIFilePicker.returnCancel; + }; + + let publicDownloads = await Downloads.getList(Downloads.PUBLIC); + let downloadFinishedPromise = new Promise(resolve => { + publicDownloads.addView({ + onDownloadChanged(download) { + if (download.succeeded || download.error) { + ok( + download.launcherPath.includes("helper_handler_test.exe"), + "Launcher path is available." + ); + resolve(); + } + }, + }); + }); + + let oldLaunchFile = DownloadIntegration.launchFile; + let launchFileCalled = new Promise(resolve => { + DownloadIntegration.launchFile = async (file, mimeInfo) => { + is( + useHelperApp, + mimeInfo.preferredAction, + "The file should be launched with a helper app handler." + ); + resolve(); + }; + }); + + let loadingTab = await BrowserTestUtils.openNewForegroundTab({ + gBrowser, + opening: TEST_PATH + "file_pdf_application_pdf.pdf", + waitForLoad: false, + waitForStateStop: true, + }); + + await downloadFinishedPromise; + await launchFileCalled; + ok(!filePickerShown, "file picker should not have shown up."); + assertCorrectFile(dir, "file_pdf_application_pdf.pdf"); + + // Cleanup + BrowserTestUtils.removeTab(loadingTab); + DownloadIntegration.launchFile = oldLaunchFile; +}); + +async function setupFilePickerDirectory() { + let saveDir = createSaveDir(); + Services.prefs.setComplexValue("browser.download.dir", Ci.nsIFile, saveDir); + Services.prefs.setIntPref("browser.download.folderList", 2); + + MockFilePicker.displayDirectory = saveDir; + MockFilePicker.returnValue = MockFilePicker.returnOK; + MockFilePicker.showCallback = function (fp) { + let file = saveDir.clone(); + file.append(fp.defaultString); + MockFilePicker.setFiles([file]); + }; + + registerCleanupFunction(async () => { + Services.prefs.clearUserPref("browser.download.dir"); + Services.prefs.clearUserPref("browser.download.folderList"); + let publicList = await Downloads.getList(Downloads.PUBLIC); + let unfinishedDownloads = new Set( + (await publicList.getAll()).filter(dl => !dl.succeeded && !dl.error) + ); + if (unfinishedDownloads.size) { + info(`Have ${unfinishedDownloads.size} unfinished downloads, waiting.`); + await new Promise(resolve => { + let view = { + onChanged(dl) { + if (unfinishedDownloads.has(dl) && (dl.succeeded || dl.error)) { + unfinishedDownloads.delete(dl); + info(`Removed another download.`); + if (!unfinishedDownloads.size) { + publicList.removeView(view); + resolve(); + } + } + }, + }; + publicList.addView(view); + }); + } + try { + await IOUtils.remove(saveDir.path, { recursive: true }); + } catch (e) { + console.error(e); + } + }); + + return saveDir; +} + +function assertCorrectFile(saveDir, filename) { + info("Make sure additional files haven't been created."); + let iter = saveDir.directoryEntries; + let file = iter.nextFile; + ok(file.path.includes(filename), "Download has correct filename"); + ok(!iter.nextFile, "Only one file was created."); +} + +function createSaveDir() { + info("Creating save directory."); + let time = new Date().getTime(); + let saveDir = Services.dirsvc.get("TmpD", Ci.nsIFile); + saveDir.append(time); + return saveDir; +} + +function ensureMIMEState( + { preferredAction, preferredHandlerApp = null }, + { type = "application/pdf", ext = "pdf" } = {} +) { + const mimeInfo = gMimeSvc.getFromTypeAndExtension(type, ext); + mimeInfo.preferredAction = preferredAction; + mimeInfo.preferredApplicationHandler = preferredHandlerApp; + mimeInfo.alwaysAskBeforeHandling = false; + gHandlerSvc.store(mimeInfo); +} -- cgit v1.2.3