var { FileUtils } = ChromeUtils.import("resource://gre/modules/FileUtils.jsm"); var { HandlerServiceTestUtils } = ChromeUtils.import( "resource://testing-common/HandlerServiceTestUtils.jsm" ); var gMimeSvc = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); var gHandlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].getService( Ci.nsIHandlerService ); function createMockedHandlerApp() { // Mock the executable let mockedExecutable = FileUtils.getFile("TmpD", ["mockedExecutable"]); if (!mockedExecutable.exists()) { mockedExecutable.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o755); } // Mock the handler app let mockedHandlerApp = Cc[ "@mozilla.org/uriloader/local-handler-app;1" ].createInstance(Ci.nsILocalHandlerApp); mockedHandlerApp.executable = mockedExecutable; mockedHandlerApp.detailedDescription = "Mocked handler app"; registerCleanupFunction(function() { // remove the mocked executable from disk. if (mockedExecutable.exists()) { mockedExecutable.remove(true); } }); return mockedHandlerApp; } function createMockedObjects(createHandlerApp) { // Mock the mime info let internalMockedMIME = gMimeSvc.getFromTypeAndExtension( "text/x-test-handler", null ); internalMockedMIME.alwaysAskBeforeHandling = true; internalMockedMIME.preferredAction = Ci.nsIHandlerInfo.useHelperApp; internalMockedMIME.appendExtension("abc"); if (createHandlerApp) { let mockedHandlerApp = createMockedHandlerApp(); internalMockedMIME.description = mockedHandlerApp.detailedDescription; internalMockedMIME.possibleApplicationHandlers.appendElement( mockedHandlerApp ); internalMockedMIME.preferredApplicationHandler = mockedHandlerApp; } // Proxy for the mocked MIME info for faking the read-only attributes let mockedMIME = new Proxy(internalMockedMIME, { get(target, property) { switch (property) { case "hasDefaultHandler": return true; case "defaultDescription": return "Default description"; default: return target[property]; } }, }); // Mock the launcher: let mockedLauncher = { MIMEInfo: mockedMIME, source: Services.io.newURI("http://www.mozilla.org/"), suggestedFileName: "test_download_dialog.abc", targetFileIsExecutable: false, saveToDisk() {}, cancel() {}, launchWithApplication() {}, setWebProgressListener() {}, saveDestinationAvailable() {}, contentLength: 42, targetFile: null, // never read // PRTime is microseconds since epoch, Date.now() returns milliseconds: timeDownloadStarted: Date.now() * 1000, QueryInterface: ChromeUtils.generateQI([ "nsICancelable", "nsIHelperAppLauncher", ]), }; registerCleanupFunction(function() { // remove the mocked mime info from database. let mockHandlerInfo = gMimeSvc.getFromTypeAndExtension( "text/x-test-handler", null ); if (gHandlerSvc.exists(mockHandlerInfo)) { gHandlerSvc.remove(mockHandlerInfo); } }); return mockedLauncher; } async function openHelperAppDialog(launcher) { let helperAppDialog = Cc[ "@mozilla.org/helperapplauncherdialog;1" ].createInstance(Ci.nsIHelperAppLauncherDialog); let helperAppDialogShownPromise = BrowserTestUtils.domWindowOpenedAndLoaded(); try { helperAppDialog.show(launcher, window, "foopy"); } catch (ex) { ok( false, "Trying to show unknownContentType.xhtml failed with exception: " + ex ); Cu.reportError(ex); } let dlg = await helperAppDialogShownPromise; is( dlg.location.href, "chrome://mozapps/content/downloads/unknownContentType.xhtml", "Got correct dialog" ); return dlg; } async function waitForSubDialog(browser, url, state) { let eventStr = state ? "dialogopen" : "dialogclose"; let tabDialogBox = gBrowser.getTabDialogBox(browser); let dialogStack = tabDialogBox.getTabDialogManager()._dialogStack; let checkFn; if (state) { checkFn = dialogEvent => dialogEvent.detail.dialog?._openedURL == url; } let event = await BrowserTestUtils.waitForEvent( dialogStack, eventStr, true, checkFn ); let { dialog } = event.detail; // If the dialog is closing wait for it to be fully closed before resolving if (!state) { await dialog._closingPromise; } return event.detail.dialog; } /** * Wait for protocol permission dialog open/close. * @param {MozBrowser} browser - Browser element the dialog belongs to. * @param {boolean} state - true: dialog open, false: dialog close * @returns {Promise} - Returns a promise which resolves with the * SubDialog object of the dialog which closed or opened. */ async function waitForProtocolPermissionDialog(browser, state) { return waitForSubDialog( browser, "chrome://mozapps/content/handling/permissionDialog.xhtml", state ); } /** * Wait for protocol app chooser dialog open/close. * @param {MozBrowser} browser - Browser element the dialog belongs to. * @param {boolean} state - true: dialog open, false: dialog close * @returns {Promise} - Returns a promise which resolves with the * SubDialog object of the dialog which closed or opened. */ async function waitForProtocolAppChooserDialog(browser, state) { return waitForSubDialog( browser, "chrome://mozapps/content/handling/appChooser.xhtml", state ); } async function promiseDownloadFinished(list) { return new Promise(resolve => { list.addView({ onDownloadChanged(download) { info("Download changed!"); if (download.succeeded || download.error) { info("Download succeeded or errored"); list.removeView(this); resolve(download); } }, }); }); } function setupMailHandler() { let mailHandlerInfo = HandlerServiceTestUtils.getHandlerInfo("mailto"); let gOldMailHandlers = []; // Remove extant web handlers because they have icons that // we fetch from the web, which isn't allowed in tests. let handlers = mailHandlerInfo.possibleApplicationHandlers; for (let i = handlers.Count() - 1; i >= 0; i--) { try { let handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp); gOldMailHandlers.push(handler); // If we get here, this is a web handler app. Remove it: handlers.removeElementAt(i); } catch (ex) {} } let previousHandling = mailHandlerInfo.alwaysAskBeforeHandling; mailHandlerInfo.alwaysAskBeforeHandling = true; // Create a dummy web mail handler so we always know the mailto: protocol. // Without this, the test fails on VMs without a default mailto: handler, // because no dialog is ever shown, as we ignore subframe navigations to // protocols that cannot be handled. let dummy = Cc["@mozilla.org/uriloader/web-handler-app;1"].createInstance( Ci.nsIWebHandlerApp ); dummy.name = "Handler 1"; dummy.uriTemplate = "https://example.com/first/%s"; mailHandlerInfo.possibleApplicationHandlers.appendElement(dummy); gHandlerSvc.store(mailHandlerInfo); registerCleanupFunction(() => { // Re-add the original protocol handlers: let mailHandlers = mailHandlerInfo.possibleApplicationHandlers; for (let i = handlers.Count() - 1; i >= 0; i--) { try { // See if this is a web handler. If it is, it'll throw, otherwise, // we will remove it. mailHandlers.queryElementAt(i, Ci.nsIWebHandlerApp); mailHandlers.removeElementAt(i); } catch (ex) {} } for (let h of gOldMailHandlers) { mailHandlers.appendElement(h); } mailHandlerInfo.alwaysAskBeforeHandling = previousHandling; gHandlerSvc.store(mailHandlerInfo); }); } let gDownloadDir; async function setDownloadDir() { let tmpDir = await PathUtils.getTempDir(); tmpDir = PathUtils.join( tmpDir, "testsavedir" + Math.floor(Math.random() * 2 ** 32) ); // Create this dir if it doesn't exist (ignores existing dirs) await IOUtils.makeDirectory(tmpDir); registerCleanupFunction(async function() { try { await IOUtils.remove(tmpDir, { recursive: true }); } catch (e) { Cu.reportError(e); } }); Services.prefs.setIntPref("browser.download.folderList", 2); Services.prefs.setCharPref("browser.download.dir", tmpDir); return tmpDir; } add_task(async function test_common_initialize() { gDownloadDir = await setDownloadDir(); Services.prefs.setCharPref("browser.download.loglevel", "Debug"); });