forked from mirrors/gecko-dev
Depends on D146727 Differential Revision: https://phabricator.services.mozilla.com/D146728
751 lines
24 KiB
JavaScript
751 lines
24 KiB
JavaScript
// There are at least seven different ways in a which a file can be saved or downloaded. This
|
|
// test ensures that the filename is determined correctly when saving in these ways. The seven
|
|
// ways are:
|
|
// - save the file individually from the File menu
|
|
// - save as complete web page (this uses a different codepath than the previous one)
|
|
// - dragging an image to the local file system
|
|
// - copy an image and paste it as a file to the local file system (windows only)
|
|
// - open a link with content-disposition set to attachment
|
|
// - open a link with the download attribute
|
|
// - save a link or image from the context menu
|
|
|
|
requestLongerTimeout(5);
|
|
|
|
let types = {
|
|
text: "text/plain",
|
|
png: "image/png",
|
|
jpeg: "image/jpeg",
|
|
webp: "image/webp",
|
|
otherimage: "image/unknown",
|
|
// Other js types (application/javascript and text/javascript) are handled by the system
|
|
// inconsistently, but application/x-javascript is handled by the external helper app service,
|
|
// so it is used here for this test.
|
|
js: "application/x-javascript",
|
|
binary: "application/octet-stream",
|
|
gook: "application/x-gook",
|
|
zip: "application/zip",
|
|
json: "application/json",
|
|
};
|
|
|
|
const PNG_DATA = atob(
|
|
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAA" +
|
|
"ACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII="
|
|
);
|
|
|
|
const JPEG_DATA = atob(
|
|
"/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4z" +
|
|
"NDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAABAAEDASIAAhEB" +
|
|
"AxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS" +
|
|
"0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKz" +
|
|
"tLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgEC" +
|
|
"BAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpj" +
|
|
"ZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6" +
|
|
"/9oADAMBAAIRAxEAPwD3+iiigD//2Q=="
|
|
);
|
|
|
|
const WEBP_DATA = atob(
|
|
"UklGRiIAAABXRUJQVlA4TBUAAAAvY8AYAAfQ/4j+B4CE8H+/ENH/VCIA"
|
|
);
|
|
|
|
const DEFAULT_INDEX_FILENAME =
|
|
AppConstants.platform == "win" ? "index.htm" : "index.html";
|
|
|
|
const PROMISE_FILENAME_TYPE = "application/x-moz-file-promise-dest-filename";
|
|
|
|
let MockFilePicker = SpecialPowers.MockFilePicker;
|
|
MockFilePicker.init(window);
|
|
|
|
let expectedItems;
|
|
let sendAsAttachment = false;
|
|
let httpServer = null;
|
|
|
|
function handleRequest(aRequest, aResponse) {
|
|
const queryString = new URLSearchParams(aRequest.queryString);
|
|
let type = queryString.get("type");
|
|
let filename = queryString.get("filename");
|
|
let dispname = queryString.get("dispname");
|
|
|
|
aResponse.setStatusLine(aRequest.httpVersion, 200);
|
|
if (type) {
|
|
aResponse.setHeader("Content-Type", types[type]);
|
|
}
|
|
|
|
if (dispname) {
|
|
let dispositionType = sendAsAttachment ? "attachment" : "inline";
|
|
aResponse.setHeader(
|
|
"Content-Disposition",
|
|
dispositionType + ';name="' + dispname + '"'
|
|
);
|
|
} else if (filename) {
|
|
let dispositionType = sendAsAttachment ? "attachment" : "inline";
|
|
aResponse.setHeader(
|
|
"Content-Disposition",
|
|
dispositionType + ';filename="' + filename + '"'
|
|
);
|
|
} else if (sendAsAttachment) {
|
|
aResponse.setHeader("Content-Disposition", "attachment");
|
|
}
|
|
|
|
if (type == "png") {
|
|
aResponse.write(PNG_DATA);
|
|
} else if (type == "jpeg") {
|
|
aResponse.write(JPEG_DATA);
|
|
} else if (type == "webp") {
|
|
aResponse.write(WEBP_DATA);
|
|
} else {
|
|
aResponse.write("// Some Text");
|
|
}
|
|
}
|
|
|
|
function handleBasicImageRequest(aRequest, aResponse) {
|
|
aResponse.setHeader("Content-Type", "image/png");
|
|
aResponse.write(PNG_DATA);
|
|
}
|
|
|
|
function handleRedirect(aRequest, aResponse) {
|
|
const queryString = new URLSearchParams(aRequest.queryString);
|
|
let filename = queryString.get("filename");
|
|
|
|
aResponse.setStatusLine(aRequest.httpVersion, 302);
|
|
aResponse.setHeader("Location", "/bell" + filename[0] + "?" + queryString);
|
|
}
|
|
|
|
function promiseDownloadFinished(list) {
|
|
return new Promise(resolve => {
|
|
list.addView({
|
|
onDownloadChanged(download) {
|
|
if (download.stopped) {
|
|
list.removeView(this);
|
|
resolve(download);
|
|
}
|
|
},
|
|
});
|
|
});
|
|
}
|
|
|
|
// nsIFile::CreateUnique crops long filenames if the path is too long, but
|
|
// we don't know exactly how long depending on the full path length, so
|
|
// for those save methods that use CreateUnique, instead just verify that
|
|
// the filename starts with the right string and has the correct extension.
|
|
function checkShortenedFilename(actual, expected) {
|
|
if (actual.length < expected.length) {
|
|
let actualDot = actual.lastIndexOf(".");
|
|
let actualExtension = actual.substring(actualDot);
|
|
let expectedExtension = expected.substring(expected.lastIndexOf("."));
|
|
if (
|
|
actualExtension == expectedExtension &&
|
|
expected.startsWith(actual.substring(0, actualDot))
|
|
) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
add_task(async function init() {
|
|
const { HttpServer } = ChromeUtils.import(
|
|
"resource://testing-common/httpd.js"
|
|
);
|
|
httpServer = new HttpServer();
|
|
httpServer.start(8000);
|
|
|
|
// Need to load the page from localhost:8000 as the download attribute
|
|
// only applies to links from the same domain.
|
|
let saveFilenamesPage = FileUtils.getFile(
|
|
"CurWorkD",
|
|
"/browser/uriloader/exthandler/tests/mochitest/save_filenames.html".split(
|
|
"/"
|
|
)
|
|
);
|
|
httpServer.registerFile("/save_filenames.html", saveFilenamesPage);
|
|
|
|
// A variety of different scripts are set up to better ensure uniqueness.
|
|
httpServer.registerPathHandler("/save_filename.sjs", handleRequest);
|
|
httpServer.registerPathHandler("/save_thename.sjs", handleRequest);
|
|
httpServer.registerPathHandler("/getdata.png", handleRequest);
|
|
httpServer.registerPathHandler("/base", handleRequest);
|
|
httpServer.registerPathHandler("/basedata", handleRequest);
|
|
httpServer.registerPathHandler("/basetext", handleRequest);
|
|
httpServer.registerPathHandler("/text2.txt", handleRequest);
|
|
httpServer.registerPathHandler("/text3.gonk", handleRequest);
|
|
httpServer.registerPathHandler("/basic.png", handleBasicImageRequest);
|
|
httpServer.registerPathHandler("/aquamarine.jpeg", handleBasicImageRequest);
|
|
httpServer.registerPathHandler("/lazuli.exe", handleBasicImageRequest);
|
|
httpServer.registerPathHandler("/redir", handleRedirect);
|
|
httpServer.registerPathHandler("/bellr", handleRequest);
|
|
httpServer.registerPathHandler("/bellg", handleRequest);
|
|
httpServer.registerPathHandler("/bellb", handleRequest);
|
|
|
|
await BrowserTestUtils.openNewForegroundTab(
|
|
gBrowser,
|
|
"http://localhost:8000/save_filenames.html"
|
|
);
|
|
|
|
expectedItems = await getItems("items");
|
|
});
|
|
|
|
function getItems(parentid) {
|
|
return SpecialPowers.spawn(
|
|
gBrowser.selectedBrowser,
|
|
[parentid, AppConstants.platform],
|
|
(id, platform) => {
|
|
let elements = [];
|
|
let elem = content.document.getElementById(id).firstElementChild;
|
|
while (elem) {
|
|
let filename =
|
|
elem.dataset["filenamePlatform" + platform] || elem.dataset.filename;
|
|
let url = elem.getAttribute("src");
|
|
let draggable =
|
|
elem.localName == "img" && elem.dataset.nodrag != "true";
|
|
let unknown = elem.dataset.unknown;
|
|
let noattach = elem.dataset.noattach;
|
|
elements.push({ draggable, unknown, filename, url, noattach });
|
|
elem = elem.nextElementSibling;
|
|
}
|
|
return elements;
|
|
}
|
|
);
|
|
}
|
|
|
|
function getDirectoryEntries(dir) {
|
|
let files = [];
|
|
let entries = dir.directoryEntries;
|
|
while (true) {
|
|
let file = entries.nextFile;
|
|
if (!file) {
|
|
break;
|
|
}
|
|
files.push(file.leafName);
|
|
}
|
|
entries.close();
|
|
return files;
|
|
}
|
|
|
|
// This test saves the document as a complete web page and verifies
|
|
// that the resources are saved with the correct filename.
|
|
add_task(async function save_document() {
|
|
let browser = gBrowser.selectedBrowser;
|
|
|
|
let tmp = SpecialPowers.Services.dirsvc.get("TmpD", Ci.nsIFile);
|
|
const baseFilename = "test_save_filenames_" + Date.now();
|
|
|
|
let tmpFile = tmp.clone();
|
|
tmpFile.append(baseFilename + "_document.html");
|
|
let tmpDir = tmp.clone();
|
|
tmpDir.append(baseFilename + "_document_files");
|
|
|
|
MockFilePicker.displayDirectory = tmpDir;
|
|
MockFilePicker.showCallback = function(fp) {
|
|
MockFilePicker.setFiles([tmpFile]);
|
|
MockFilePicker.filterIndex = 0; // kSaveAsType_Complete
|
|
};
|
|
|
|
let downloadsList = await Downloads.getList(Downloads.PUBLIC);
|
|
let savePromise = new Promise((resolve, reject) => {
|
|
downloadsList.addView({
|
|
onDownloadChanged(download) {
|
|
if (download.succeeded) {
|
|
downloadsList.removeView(this);
|
|
downloadsList.removeFinished();
|
|
resolve();
|
|
}
|
|
},
|
|
});
|
|
});
|
|
saveBrowser(browser);
|
|
await savePromise;
|
|
|
|
let filesSaved = getDirectoryEntries(tmpDir);
|
|
|
|
for (let idx = 0; idx < expectedItems.length; idx++) {
|
|
let filename = expectedItems[idx].filename;
|
|
if (idx == 66 && AppConstants.platform == "win") {
|
|
// This is special-cased on Windows. The default filename will be used, since
|
|
// the filename is invalid, but since the previous test file has the same issue,
|
|
// this second file will be saved with a number suffix added to it.
|
|
filename = "index_002";
|
|
}
|
|
|
|
let file = tmpDir.clone();
|
|
file.append(filename);
|
|
|
|
let fileIdx = -1;
|
|
// Use checkShortenedFilename to check long filenames.
|
|
if (filename.length > 240) {
|
|
for (let t = 0; t < filesSaved.length; t++) {
|
|
if (
|
|
filesSaved[t].length > 60 &&
|
|
checkShortenedFilename(filesSaved[t], filename)
|
|
) {
|
|
fileIdx = t;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
fileIdx = filesSaved.indexOf(filename);
|
|
}
|
|
|
|
ok(
|
|
fileIdx >= 0,
|
|
"file i" +
|
|
idx +
|
|
" " +
|
|
filename +
|
|
" was saved with the correct name using saveDocument"
|
|
);
|
|
if (fileIdx >= 0) {
|
|
// If found, remove it from the list. At end of the test, the
|
|
// list should be empty.
|
|
filesSaved.splice(fileIdx, 1);
|
|
}
|
|
}
|
|
|
|
is(filesSaved.length, 0, "all files accounted for");
|
|
tmpDir.remove(true);
|
|
tmpFile.remove(false);
|
|
});
|
|
|
|
// This test simulates dragging the images in the document and ensuring that
|
|
// the correct filename is used for each one.
|
|
// On Mac, the data is added in the parent process instead, so we cannot
|
|
// test dragging directly.
|
|
if (AppConstants.platform != "macosx") {
|
|
add_task(async function drag_files() {
|
|
let browser = gBrowser.selectedBrowser;
|
|
|
|
await SpecialPowers.spawn(browser, [PROMISE_FILENAME_TYPE], type => {
|
|
content.addEventListener("dragstart", event => {
|
|
content.draggedFile = event.dataTransfer.getData(type);
|
|
event.preventDefault();
|
|
});
|
|
});
|
|
|
|
for (let idx = 0; idx < expectedItems.length; idx++) {
|
|
if (!expectedItems[idx].draggable) {
|
|
// You can't drag non-images and invalid images.
|
|
continue;
|
|
}
|
|
|
|
await BrowserTestUtils.synthesizeMouse(
|
|
"#i" + idx,
|
|
1,
|
|
1,
|
|
{ type: "mousedown" },
|
|
browser
|
|
);
|
|
await BrowserTestUtils.synthesizeMouse(
|
|
"#i" + idx,
|
|
11,
|
|
11,
|
|
{ type: "mousemove" },
|
|
browser
|
|
);
|
|
await BrowserTestUtils.synthesizeMouse(
|
|
"#i" + idx,
|
|
20,
|
|
20,
|
|
{ type: "mousemove" },
|
|
browser
|
|
);
|
|
await BrowserTestUtils.synthesizeMouse(
|
|
"#i" + idx,
|
|
20,
|
|
20,
|
|
{ type: "mouseup" },
|
|
browser
|
|
);
|
|
|
|
let draggedFile = await SpecialPowers.spawn(browser, [], () => {
|
|
let file = content.draggedFile;
|
|
content.draggedFile = null;
|
|
return file;
|
|
});
|
|
|
|
is(
|
|
draggedFile,
|
|
expectedItems[idx].filename,
|
|
"i" +
|
|
idx +
|
|
" " +
|
|
expectedItems[idx].filename +
|
|
" was saved with the correct name when dragging"
|
|
);
|
|
}
|
|
});
|
|
}
|
|
|
|
// This test checks that copying an image provides the right filename
|
|
// for pasting to the local file system. This is only implemented on Windows.
|
|
if (AppConstants.platform == "win") {
|
|
add_task(async function copy_image() {
|
|
for (let idx = 0; idx < expectedItems.length; idx++) {
|
|
if (!expectedItems[idx].draggable) {
|
|
// You can't context-click on non-images.
|
|
continue;
|
|
}
|
|
|
|
let data = await SpecialPowers.spawn(
|
|
gBrowser.selectedBrowser,
|
|
[idx, PROMISE_FILENAME_TYPE],
|
|
(imagenum, type) => {
|
|
// No need to wait for the data to be really on the clipboard, we only
|
|
// need the promise data added when the command is performed.
|
|
SpecialPowers.setCommandNode(
|
|
content,
|
|
content.document.getElementById("i" + imagenum)
|
|
);
|
|
SpecialPowers.doCommand(content, "cmd_copyImageContents");
|
|
|
|
return SpecialPowers.getClipboardData(type);
|
|
}
|
|
);
|
|
|
|
is(
|
|
data,
|
|
expectedItems[idx].filename,
|
|
"i" +
|
|
idx +
|
|
" " +
|
|
expectedItems[idx].filename +
|
|
" was saved with the correct name when copying"
|
|
);
|
|
}
|
|
});
|
|
}
|
|
|
|
// This test checks the default filename selected when selecting to save
|
|
// a file from either the context menu or what would happen when save page
|
|
// as was selected from the file menu. Note that this tests a filename assigned
|
|
// when using content-disposition: inline.
|
|
add_task(async function saveas_files() {
|
|
// Iterate over each item and try saving them from the context menu,
|
|
// and the Save Page As command on the File menu.
|
|
for (let testname of ["context menu", "save page as"]) {
|
|
for (let idx = 0; idx < expectedItems.length; idx++) {
|
|
let menu;
|
|
if (testname == "context menu") {
|
|
if (!expectedItems[idx].draggable) {
|
|
// You can't context-click on non-images.
|
|
continue;
|
|
}
|
|
|
|
menu = document.getElementById("contentAreaContextMenu");
|
|
let popupShown = BrowserTestUtils.waitForEvent(menu, "popupshown");
|
|
BrowserTestUtils.synthesizeMouse(
|
|
"#i" + idx,
|
|
5,
|
|
5,
|
|
{ type: "contextmenu", button: 2 },
|
|
gBrowser.selectedBrowser
|
|
);
|
|
await popupShown;
|
|
} else {
|
|
if (expectedItems[idx].unknown == "typeonly") {
|
|
// Items marked with unknown="typeonly" have unknown content types and
|
|
// will be downloaded instead of opened in a tab.
|
|
let list = await Downloads.getList(Downloads.PUBLIC);
|
|
let downloadFinishedPromise = promiseDownloadFinished(list);
|
|
|
|
await BrowserTestUtils.openNewForegroundTab(
|
|
gBrowser,
|
|
expectedItems[idx].url
|
|
);
|
|
|
|
let download = await downloadFinishedPromise;
|
|
|
|
let filename = PathUtils.filename(download.target.path);
|
|
is(
|
|
filename,
|
|
expectedItems[idx].filename,
|
|
"open link" +
|
|
idx +
|
|
" " +
|
|
expectedItems[idx].filename +
|
|
" was downloaded with the correct name when opened as a url"
|
|
);
|
|
|
|
try {
|
|
await IOUtils.remove(download.target.path);
|
|
} catch (ex) {}
|
|
|
|
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
|
continue;
|
|
}
|
|
|
|
await BrowserTestUtils.openNewForegroundTab(
|
|
gBrowser,
|
|
expectedItems[idx].url
|
|
);
|
|
}
|
|
|
|
let filename = await new Promise(resolve => {
|
|
MockFilePicker.showCallback = function(fp) {
|
|
setTimeout(() => {
|
|
resolve(fp.defaultString);
|
|
}, 0);
|
|
return Ci.nsIFilePicker.returnCancel;
|
|
};
|
|
|
|
if (testname == "context menu") {
|
|
let menuitem = document.getElementById("context-saveimage");
|
|
menu.activateItem(menuitem);
|
|
} else if (testname == "save page as") {
|
|
document.getElementById("Browser:SavePage").doCommand();
|
|
}
|
|
});
|
|
|
|
// Trying to open an unknown or binary type will just open a blank
|
|
// page, so trying to save will just save the blank page with the
|
|
// filename index.html.
|
|
let expectedFilename = expectedItems[idx].unknown
|
|
? DEFAULT_INDEX_FILENAME
|
|
: expectedItems[idx].filename;
|
|
|
|
// When saving via contentAreaUtils.js, the content disposition name
|
|
// field is used as an alternate.
|
|
if (expectedFilename == "save_thename.png") {
|
|
expectedFilename = "withname.png";
|
|
}
|
|
|
|
is(
|
|
filename,
|
|
expectedFilename,
|
|
"i" +
|
|
idx +
|
|
" " +
|
|
expectedFilename +
|
|
" was saved with the correct name " +
|
|
testname
|
|
);
|
|
|
|
if (testname == "save page as") {
|
|
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// This test checks that links that result in files with
|
|
// content-disposition: attachment are saved with the right filenames.
|
|
add_task(async function save_links() {
|
|
sendAsAttachment = true;
|
|
|
|
// Create some links based on each image and insert them into the document.
|
|
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
|
|
let doc = content.document;
|
|
let insertPos = doc.getElementById("attachment-links");
|
|
|
|
let idx = 0;
|
|
let elem = doc.getElementById("items").firstElementChild;
|
|
while (elem) {
|
|
let attachmentlink = doc.createElement("a");
|
|
attachmentlink.id = "attachmentlink" + idx;
|
|
attachmentlink.href = elem.localName == "object" ? elem.data : elem.src;
|
|
attachmentlink.textContent = elem.dataset.filename;
|
|
insertPos.appendChild(attachmentlink);
|
|
insertPos.appendChild(doc.createTextNode(" "));
|
|
|
|
elem = elem.nextElementSibling;
|
|
idx++;
|
|
}
|
|
});
|
|
|
|
let list = await Downloads.getList(Downloads.PUBLIC);
|
|
|
|
for (let idx = 0; idx < expectedItems.length; idx++) {
|
|
// Skip the items that won't have a content-disposition.
|
|
if (expectedItems[idx].noattach) {
|
|
continue;
|
|
}
|
|
|
|
let downloadFinishedPromise = promiseDownloadFinished(list);
|
|
|
|
BrowserTestUtils.synthesizeMouse(
|
|
"#attachmentlink" + idx,
|
|
5,
|
|
5,
|
|
{},
|
|
gBrowser.selectedBrowser
|
|
);
|
|
|
|
let download = await downloadFinishedPromise;
|
|
|
|
let filename = PathUtils.filename(download.target.path);
|
|
|
|
let expectedFilename = expectedItems[idx].filename;
|
|
if (AppConstants.platform == "win") {
|
|
// On Windows, .txt is added when saving as an attachment
|
|
// to avoid this looking like an executable. This
|
|
// is done in validateLeafName in HelperAppDlg.jsm.
|
|
// XXXndeakin should we do this for all save mechanisms?
|
|
if (idx == 54) {
|
|
expectedFilename += ".txt";
|
|
} else if (idx == 68) {
|
|
// jar files are considered to be executable.
|
|
expectedFilename += ".zip";
|
|
}
|
|
}
|
|
|
|
// Use checkShortenedFilename to check long filenames.
|
|
if (expectedItems[idx].filename.length > 240) {
|
|
ok(
|
|
checkShortenedFilename(filename, expectedFilename),
|
|
"attachmentlink" +
|
|
idx +
|
|
" " +
|
|
expectedFilename +
|
|
" was saved with the correct name when opened as attachment (with long name)"
|
|
);
|
|
} else {
|
|
is(
|
|
filename,
|
|
expectedFilename,
|
|
"attachmentlink" +
|
|
idx +
|
|
" " +
|
|
expectedFilename +
|
|
" was saved with the correct name when opened as attachment"
|
|
);
|
|
}
|
|
|
|
try {
|
|
await IOUtils.remove(download.target.path);
|
|
} catch (ex) {}
|
|
}
|
|
|
|
sendAsAttachment = false;
|
|
});
|
|
|
|
// This test checks some cases where links to images are saved using Save Link As,
|
|
// and when opening them in a new tab and then using Save Page As.
|
|
add_task(async function saveas_image_links() {
|
|
let links = await getItems("links");
|
|
|
|
// Iterate over each link and try saving the links from the context menu,
|
|
// and then after opening a new tab for that link and then selecting
|
|
// the Save Page As command on the File menu.
|
|
for (let testname of ["save link as", "save link then save page as"]) {
|
|
for (let idx = 0; idx < links.length; idx++) {
|
|
let menu = document.getElementById("contentAreaContextMenu");
|
|
let popupShown = BrowserTestUtils.waitForEvent(menu, "popupshown");
|
|
BrowserTestUtils.synthesizeMouse(
|
|
"#link" + idx,
|
|
5,
|
|
5,
|
|
{ type: "contextmenu", button: 2 },
|
|
gBrowser.selectedBrowser
|
|
);
|
|
await popupShown;
|
|
|
|
let promptPromise = new Promise(resolve => {
|
|
MockFilePicker.showCallback = function(fp) {
|
|
setTimeout(() => {
|
|
resolve(fp.defaultString);
|
|
}, 0);
|
|
return Ci.nsIFilePicker.returnCancel;
|
|
};
|
|
});
|
|
|
|
if (testname == "save link as") {
|
|
let menuitem = document.getElementById("context-savelink");
|
|
menu.activateItem(menuitem);
|
|
} else {
|
|
let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser);
|
|
|
|
let menuitem = document.getElementById("context-openlinkintab");
|
|
menu.activateItem(menuitem);
|
|
|
|
let tab = await newTabPromise;
|
|
await BrowserTestUtils.switchTab(gBrowser, tab);
|
|
|
|
document.getElementById("Browser:SavePage").doCommand();
|
|
}
|
|
|
|
let filename = await promptPromise;
|
|
|
|
let expectedFilename = links[idx].filename;
|
|
// Only codepaths that go through contentAreaUtils.js use the
|
|
// name from the content disposition.
|
|
if (testname == "save link as" && expectedFilename == "four.png") {
|
|
expectedFilename = "save_filename.png";
|
|
}
|
|
|
|
is(
|
|
filename,
|
|
expectedFilename,
|
|
"i" +
|
|
idx +
|
|
" " +
|
|
expectedFilename +
|
|
" link was saved with the correct name " +
|
|
testname
|
|
);
|
|
|
|
if (testname == "save link then save page as") {
|
|
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// This test checks that links that with a download attribute
|
|
// are saved with the right filenames.
|
|
add_task(async function save_download_links() {
|
|
let downloads = await getItems("downloads");
|
|
|
|
let list = await Downloads.getList(Downloads.PUBLIC);
|
|
for (let idx = 0; idx < downloads.length; idx++) {
|
|
let downloadFinishedPromise = promiseDownloadFinished(list);
|
|
|
|
BrowserTestUtils.synthesizeMouse(
|
|
"#download" + idx,
|
|
2,
|
|
2,
|
|
{},
|
|
gBrowser.selectedBrowser
|
|
);
|
|
|
|
let download = await downloadFinishedPromise;
|
|
|
|
let filename = PathUtils.filename(download.target.path);
|
|
|
|
if (downloads[idx].filename.length > 240) {
|
|
ok(
|
|
checkShortenedFilename(filename, downloads[idx].filename),
|
|
"download" +
|
|
idx +
|
|
" " +
|
|
downloads[idx].filename +
|
|
" was saved with the correct name when link has download attribute"
|
|
);
|
|
} else {
|
|
if (idx == 66 && filename == "index(1)") {
|
|
// Sometimes, the previous test's file still exists or wasn't created in time
|
|
// and a non-duplicated name is created. Allow this rather than figuring out
|
|
// how to avoid it since it doesn't affect what is being tested here.
|
|
filename = "index";
|
|
}
|
|
|
|
is(
|
|
filename,
|
|
downloads[idx].filename,
|
|
"download" +
|
|
idx +
|
|
" " +
|
|
downloads[idx].filename +
|
|
" was saved with the correct name when link has download attribute"
|
|
);
|
|
}
|
|
|
|
try {
|
|
await IOUtils.remove(download.target.path);
|
|
} catch (ex) {}
|
|
}
|
|
});
|
|
|
|
add_task(async () => {
|
|
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
|
MockFilePicker.cleanup();
|
|
await new Promise(resolve => httpServer.stop(resolve));
|
|
});
|