/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; const { Downloads } = ChromeUtils.importESModule( "resource://gre/modules/Downloads.sys.mjs" ); const { DownloadIntegration } = ChromeUtils.importESModule( "resource://gre/modules/DownloadIntegration.sys.mjs" ); const TEST_PATH = getRootDirectory(gTestPath).replace( "chrome://mochitests/content", "https://example.com" ); const { handleInternally, saveToDisk, useSystemDefault, alwaysAsk, useHelperApp, } = Ci.nsIHandlerInfo; function waitForAcceptButtonToGetEnabled(doc) { let dialog = doc.querySelector("#unknownContentType"); let button = dialog.getButton("accept"); return TestUtils.waitForCondition( () => !button.disabled, "Wait for Accept button to get enabled" ); } add_setup(async function () { await SpecialPowers.pushPrefEnv({ set: [ // Remove the security delay for the dialog during the test. ["security.dialog_enable_delay", 0], ["browser.helperApps.showOpenOptionForViewableInternally", true], // Make sure we don't open a file picker dialog somehow. ["browser.download.useDownloadDir", true], ], }); // Restore handlers after the whole test has run const registerRestoreHandler = function (type, ext) { const mimeInfo = gMimeSvc.getFromTypeAndExtension(type, ext); const existed = gHandlerSvc.exists(mimeInfo); registerCleanupFunction(() => { if (existed) { gHandlerSvc.store(mimeInfo); } else { gHandlerSvc.remove(mimeInfo); } }); }; registerRestoreHandler("image/svg+xml", "svg"); }); function ensureMIMEState({ preferredAction, alwaysAskBeforeHandling }) { const mimeInfo = gMimeSvc.getFromTypeAndExtension("image/svg+xml", "svg"); mimeInfo.preferredAction = preferredAction; mimeInfo.alwaysAskBeforeHandling = alwaysAskBeforeHandling; gHandlerSvc.store(mimeInfo); } function waitDelay(delay) { return new Promise(resolve => { /* eslint-disable mozilla/no-arbitrary-setTimeout */ window.setTimeout(resolve, delay); }); } function promisePanelOpened() { if (DownloadsPanel.panel && DownloadsPanel.panel.state == "open") { return Promise.resolve(); } return BrowserTestUtils.waitForEvent(DownloadsPanel.panel, "popupshown"); } const kTestCasesPrefEnabled = [ { description: "Pref enabled - internal handling as default should not change prefs", preDialogState: { preferredAction: handleInternally, alwaysAskBeforeHandling: false, }, expectTab: true, expectLaunch: false, expectedPreferredAction: handleInternally, expectedAlwaysAskBeforeHandling: false, expectUCT: false, }, { description: "Pref enabled - external handling as default should not change prefs", preDialogState: { preferredAction: useSystemDefault, alwaysAskBeforeHandling: false, }, expectTab: false, expectLaunch: true, expectedPreferredAction: useSystemDefault, expectedAlwaysAskBeforeHandling: false, expectUCT: false, }, { description: "Pref enabled - saveToDisk as default should not change prefs", preDialogState: { preferredAction: saveToDisk, alwaysAskBeforeHandling: false, }, expectTab: false, expectLaunch: false, expectedPreferredAction: saveToDisk, expectedAlwaysAskBeforeHandling: false, expectUCT: false, }, { description: "Pref enabled - choose internal + alwaysAsk default + checkbox should update persisted default", preDialogState: { preferredAction: alwaysAsk, alwaysAskBeforeHandling: false, }, dialogActions(doc) { let handleItem = doc.querySelector("#handleInternally"); handleItem.click(); ok(handleItem.selected, "The 'open' option should now be selected"); let checkbox = doc.querySelector("#rememberChoice"); checkbox.checked = true; checkbox.doCommand(); }, // new tab will not launch in test environment when alwaysAsk is preferredAction expectTab: false, expectLaunch: false, expectedPreferredAction: handleInternally, expectedAlwaysAskBeforeHandling: false, expectUCT: true, }, { description: "Pref enabled - saveToDisk with alwaysAsk default should update persisted default", preDialogState: { preferredAction: alwaysAsk, alwaysAskBeforeHandling: false, }, dialogActions(doc) { let saveItem = doc.querySelector("#save"); saveItem.click(); ok(saveItem.selected, "The 'save' option should now be selected"); }, expectTab: false, expectLaunch: false, expectedPreferredAction: saveToDisk, expectedAlwaysAskBeforeHandling: false, expectUCT: true, }, ]; add_task( async function test_check_saving_handler_choices_with_always_ask_before_handling_new_types_pref_enabled() { SpecialPowers.pushPrefEnv({ set: [["browser.download.always_ask_before_handling_new_types", false]], }); let publicList = await Downloads.getList(Downloads.PUBLIC); registerCleanupFunction(async () => { await publicList.removeFinished(); }); let file = "file_image_svgxml.svg"; for (let testCase of kTestCasesPrefEnabled) { info("Testing with " + file + "; " + testCase.description); ensureMIMEState(testCase.preDialogState); const { expectTab, expectLaunch, description, expectUCT } = testCase; let oldLaunchFile = DownloadIntegration.launchFile; let fileLaunched = Promise.withResolvers(); DownloadIntegration.launchFile = () => { ok( expectLaunch, `The file should ${ expectLaunch ? "" : "not " }be launched with an external application - ${description}` ); fileLaunched.resolve(); }; info("Load window and tabs"); let dialogWindowPromise = BrowserTestUtils.domWindowOpenedAndLoaded(); let loadingTab = await BrowserTestUtils.openNewForegroundTab({ gBrowser, opening: TEST_PATH + file, waitForLoad: false, waitForStateStop: true, }); // See if UCT window appears in loaded tab. let dialogWindow = await Promise.race([ waitDelay(1000), dialogWindowPromise, ]); is( !!dialogWindow, expectUCT, `UCT window should${expectUCT ? "" : " not"} have appeared` ); let download; if (dialogWindow) { is( dialogWindow.location.href, "chrome://mozapps/content/downloads/unknownContentType.xhtml", "Unknown content dialogWindow should be loaded correctly." ); let doc = dialogWindow.document; let internalHandlerRadio = doc.querySelector("#handleInternally"); info("Waiting for accept button to get enabled"); await waitForAcceptButtonToGetEnabled(doc); ok( !internalHandlerRadio.hidden, "The option should be visible for SVG" ); info("Running UCT dialog options before downloading file"); await testCase.dialogActions(doc); let dialog = doc.querySelector("#unknownContentType"); dialog.acceptDialog(); info("Waiting for downloads to finish"); let downloadFinishedPromise = promiseDownloadFinished(publicList); download = await downloadFinishedPromise; } else { let downloadPanelPromise = promisePanelOpened(); await downloadPanelPromise; is( DownloadsPanel.isPanelShowing, true, "DownloadsPanel should be open" ); info("Skipping UCT dialog options"); info("Waiting for downloads to finish"); // Unlike when the UCT window opens, the download immediately starts. let downloadList = await publicList; [download] = downloadList._downloads; } if (expectLaunch) { info("Waiting for launch to finish"); await fileLaunched.promise; } DownloadIntegration.launchFile = oldLaunchFile; is( download.contentType, "image/svg+xml", "File contentType should be correct" ); is( download.source.url, `${TEST_PATH + file}`, "File name should be correct." ); is( (await publicList.getAll()).length, 1, "download should appear in public list" ); // Check mime info: const mimeInfo = gMimeSvc.getFromTypeAndExtension("image/svg+xml", "svg"); gHandlerSvc.fillHandlerInfo(mimeInfo, ""); is( mimeInfo.preferredAction, testCase.expectedPreferredAction, "preferredAction - " + description ); is( mimeInfo.alwaysAskBeforeHandling, testCase.expectedAlwaysAskBeforeHandling, "alwaysAskBeforeHandling - " + description ); info("Cleaning up"); BrowserTestUtils.removeTab(loadingTab); // By default, if internal is default with pref enabled, we view the svg file in // in a new tab. Close this tab in order for the test case to pass. if (expectTab && testCase.preferredAction !== alwaysAsk) { BrowserTestUtils.removeTab(gBrowser.selectedTab); } await publicList.removeFinished(); if (download?.target.exists) { try { await IOUtils.remove(download.target.path); } catch (ex) { /* ignore */ } } } } );