Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

<!doctype html>
<html>
<head>
<title>Test downloads.download() saveAs option</title>
<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.importESModule(
"resource://gre/modules/FileUtils.sys.mjs"
);
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(SpecialPowers.wrap(window).browsingContext);
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>