diff options
Diffstat (limited to 'toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_saveAs.html')
-rw-r--r-- | toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_saveAs.html | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_saveAs.html b/toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_saveAs.html new file mode 100644 index 0000000000..64cfcfd289 --- /dev/null +++ b/toolkit/components/extensions/test/mochitest/test_chrome_ext_downloads_saveAs.html @@ -0,0 +1,257 @@ +<!doctype html> +<html> +<head> + <title>Test downloads.download() saveAs option</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script> + <script src="head.js"></script> + <link rel="stylesheet" href="chrome://mochikit/content/tests/SimpleTest/test.css"/> +</head> +<body> + +<script type="text/javascript"> +"use strict"; + +const {FileUtils} = ChromeUtils.import("resource://gre/modules/FileUtils.jsm"); + +const PROMPTLESS_DOWNLOAD_PREF = "browser.download.useDownloadDir"; + +const DOWNLOAD_FILENAME = "file_download.nonext.txt"; +const DEFAULT_SUBDIR = "subdir"; + +// We need to be able to distinguish files downloaded by the file picker from +// files downloaded without it. +let pickerDir; +let pbPickerDir; // for incognito downloads +let defaultDir; + +add_task(async function setup() { + // Reset DownloadLastDir preferences in case other tests set them. + SpecialPowers.Services.obs.notifyObservers( + null, + "browser:purge-session-history" + ); + + // Set up temporary directories. + let downloadDir = FileUtils.getDir("TmpD", ["downloads"]); + pickerDir = downloadDir.clone(); + pickerDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); + info(`Using file picker download directory ${pickerDir.path}`); + pbPickerDir = downloadDir.clone(); + pbPickerDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); + info(`Using private browsing file picker download directory ${pbPickerDir.path}`); + defaultDir = downloadDir.clone(); + defaultDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); + info(`Using default download directory ${defaultDir.path}`); + let subDir = defaultDir.clone(); + subDir.append(DEFAULT_SUBDIR); + subDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); + + isnot(pickerDir.path, defaultDir.path, + "Should be able to distinguish between files saved with or without the file picker"); + isnot(pickerDir.path, pbPickerDir.path, + "Should be able to distinguish between files saved in and out of private browsing mode"); + + await SpecialPowers.pushPrefEnv({"set": [ + ["browser.download.folderList", 2], + ["browser.download.dir", defaultDir.path], + ]}); + + SimpleTest.registerCleanupFunction(async () => { + await SpecialPowers.popPrefEnv(); + pickerDir.remove(true); + pbPickerDir.remove(true); + defaultDir.remove(true); // This also removes DEFAULT_SUBDIR. + }); +}); + +add_task(async function test_downloads_saveAs() { + const pickerFile = pickerDir.clone(); + pickerFile.append(DOWNLOAD_FILENAME); + + const pbPickerFile = pbPickerDir.clone(); + pbPickerFile.append(DOWNLOAD_FILENAME); + + const defaultFile = defaultDir.clone(); + defaultFile.append(DOWNLOAD_FILENAME); + + const {MockFilePicker} = SpecialPowers; + MockFilePicker.init(window); + + function mockFilePickerCallback(expectedStartingDir, pickedFile) { + return fp => { + // Assert that the downloads API correctly sets the starting directory. + ok(fp.displayDirectory.equals(expectedStartingDir), "Got the expected FilePicker displayDirectory"); + + // Assert that the downloads API configures both default properties. + is(fp.defaultString, DOWNLOAD_FILENAME, "Got the expected FilePicker defaultString"); + is(fp.defaultExtension, "txt", "Got the expected FilePicker defaultExtension"); + + MockFilePicker.setFiles([pickedFile]); + }; + } + + function background() { + const url = URL.createObjectURL(new Blob(["file content"])); + browser.test.onMessage.addListener(async (filename, saveAs, isPrivate) => { + try { + let options = { + url, + filename, + incognito: isPrivate, + }; + // Only define the saveAs option if the argument was actually set + if (saveAs !== undefined) { + options.saveAs = saveAs; + } + let id = await browser.downloads.download(options); + browser.downloads.onChanged.addListener(delta => { + if (delta.id == id && delta.state.current === "complete") { + browser.test.sendMessage("done", {ok: true, id}); + } + }); + } catch ({message}) { + browser.test.sendMessage("done", {ok: false, message}); + } + }); + browser.test.sendMessage("ready"); + } + + const manifest = { + background, + incognitoOverride: "spanning", + manifest: {permissions: ["downloads"]}, + }; + const extension = ExtensionTestUtils.loadExtension(manifest); + + await extension.startup(); + await extension.awaitMessage("ready"); + + // options should have the following properties: + // saveAs (Boolean or undefined) + // isPrivate (Boolean) + // fileName (string) + // expectedStartingDir (nsIFile) + // destinationFile (nsIFile) + async function testExpectFilePicker(options) { + ok(!options.destinationFile.exists(), "the file should have been cleaned up properly previously"); + + MockFilePicker.showCallback = mockFilePickerCallback( + options.expectedStartingDir, + options.destinationFile + ); + MockFilePicker.returnValue = MockFilePicker.returnOK; + + extension.sendMessage(options.fileName, options.saveAs, options.isPrivate); + let result = await extension.awaitMessage("done"); + ok(result.ok, `downloads.download() works with saveAs=${options.saveAs}`); + + ok(options.destinationFile.exists(), "the file exists."); + is(options.destinationFile.fileSize, 12, "downloaded file is the correct size"); + options.destinationFile.remove(false); + MockFilePicker.reset(); + + // Test the user canceling the save dialog. + MockFilePicker.returnValue = MockFilePicker.returnCancel; + + extension.sendMessage(options.fileName, options.saveAs, options.isPrivate); + result = await extension.awaitMessage("done"); + + ok(!result.ok, "download rejected if the user cancels the dialog"); + is(result.message, "Download canceled by the user", "with the correct message"); + ok(!options.destinationFile.exists(), "file was not downloaded"); + MockFilePicker.reset(); + } + + async function testNoFilePicker(saveAs) { + ok(!defaultFile.exists(), "the file should have been cleaned up properly previously"); + + extension.sendMessage(DOWNLOAD_FILENAME, saveAs, false); + let result = await extension.awaitMessage("done"); + ok(result.ok, `downloads.download() works with saveAs=${saveAs}`); + + ok(defaultFile.exists(), "the file exists."); + is(defaultFile.fileSize, 12, "downloaded file is the correct size"); + defaultFile.remove(false); + } + + info("Testing that saveAs=true uses the file picker as expected"); + let expectedStartingDir = defaultDir; + let fpOptions = { + saveAs: true, + isPrivate: false, + fileName: DOWNLOAD_FILENAME, + expectedStartingDir: expectedStartingDir, + destinationFile: pickerFile, + }; + await testExpectFilePicker(fpOptions); + + info("Testing that saveas=true reuses last file picker directory"); + fpOptions.expectedStartingDir = pickerDir; + await testExpectFilePicker(fpOptions); + + info("Testing that saveAs=true in PB reuses last directory"); + let nonPBStartingDir = fpOptions.expectedStartingDir; + fpOptions.isPrivate = true; + fpOptions.destinationFile = pbPickerFile; + await testExpectFilePicker(fpOptions); + + info("Testing that saveAs=true in PB uses a separate last directory"); + fpOptions.expectedStartingDir = pbPickerDir; + await testExpectFilePicker(fpOptions); + + info("Testing that saveAs=true in Permanent PB mode ignores the incognito option"); + await SpecialPowers.pushPrefEnv({ + set: [["browser.privatebrowsing.autostart", true]], + }); + fpOptions.isPrivate = false; + fpOptions.expectedStartingDir = pbPickerDir; + await testExpectFilePicker(fpOptions); + + info("Testing that saveas=true reuses the non-PB last directory after private download"); + await SpecialPowers.popPrefEnv(); + fpOptions.isPrivate = false; + fpOptions.expectedStartingDir = nonPBStartingDir; + fpOptions.destinationFile = pickerFile; + await testExpectFilePicker(fpOptions); + + info("Testing that saveAs=true does not reuse last directory when filename contains a path separator"); + fpOptions.fileName = DEFAULT_SUBDIR + "/" + DOWNLOAD_FILENAME; + let destinationFile = defaultDir.clone(); + destinationFile.append(DEFAULT_SUBDIR); + fpOptions.expectedStartingDir = destinationFile.clone(); + destinationFile.append(DOWNLOAD_FILENAME); + fpOptions.destinationFile = destinationFile; + await testExpectFilePicker(fpOptions); + + info("Testing that saveAs=false does not use the file picker"); + fpOptions.saveAs = false; + await testNoFilePicker(fpOptions.saveAs); + + // When saveAs is not set, the behavior should be determined by the Firefox + // pref that normally determines whether the "Save As" prompt should be + // displayed. + info(`Testing that the file picker is used when saveAs is not specified ` + + `but ${PROMPTLESS_DOWNLOAD_PREF} is disabled`); + fpOptions.saveAs = undefined; + await SpecialPowers.pushPrefEnv({"set": [ + [PROMPTLESS_DOWNLOAD_PREF, false], + ]}); + await testExpectFilePicker(fpOptions); + + info(`Testing that the file picker is NOT used when saveAs is not ` + + `specified but ${PROMPTLESS_DOWNLOAD_PREF} is enabled`); + await SpecialPowers.popPrefEnv(); + await SpecialPowers.pushPrefEnv({"set": [ + [PROMPTLESS_DOWNLOAD_PREF, true], + ]}); + await testNoFilePicker(fpOptions.saveAs); + + await extension.unload(); + MockFilePicker.cleanup(); +}); + +</script> + +</body> +</html> |