commit fdbb94b7398f3382836d2513c3b8a61b767f71e9
parent 3ccdf3d2bbdfe4e58c6a612b7a7c823cc9bc57ef
Author: Duncan McIntosh <dmcintosh@mozilla.com>
Date: Mon, 27 Oct 2025 15:07:47 +0000
Bug 1995987 - Set the backup chooser's initial directory to the folder containing the backup instead of the backup itself. r=mconley
This passes through the actual backup path across the child/parent
boundary since PathUtils doesn't seem available inside of content. The
displayDirectoryPath property is renamed to reflect its new role.
Differential Revision: https://phabricator.services.mozilla.com/D270041
Diffstat:
5 files changed, 69 insertions(+), 9 deletions(-)
diff --git a/browser/components/backup/actors/BackupUIChild.sys.mjs b/browser/components/backup/actors/BackupUIChild.sys.mjs
@@ -60,7 +60,7 @@ export class BackupUIChild extends JSWindowActorChild {
let { path, filename, iconURL } = await this.sendQuery("ShowFilepicker", {
win: event.detail?.win,
filter: event.detail?.filter,
- displayDirectoryPath: event.detail?.displayDirectoryPath,
+ existingBackupPath: event.detail?.existingBackupPath,
});
let widgets = ChromeUtils.nondeterministicGetWeakSetKeys(
diff --git a/browser/components/backup/actors/BackupUIParent.sys.mjs b/browser/components/backup/actors/BackupUIParent.sys.mjs
@@ -128,7 +128,7 @@ export class BackupUIParent extends JSWindowActorParent {
}
this.#bs.setScheduledBackups(false);
} else if (message.name == "ShowFilepicker") {
- let { win, filter, displayDirectoryPath } = message.data;
+ let { win, filter, existingBackupPath } = message.data;
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
@@ -141,11 +141,11 @@ export class BackupUIParent extends JSWindowActorParent {
fp.appendFilters(Ci.nsIFilePicker[filter]);
}
- if (displayDirectoryPath) {
+ if (existingBackupPath) {
try {
- let exists = await IOUtils.exists(displayDirectoryPath);
- if (exists) {
- fp.displayDirectory = await IOUtils.getFile(displayDirectoryPath);
+ let folder = (await IOUtils.getFile(existingBackupPath)).parent;
+ if (folder.exists()) {
+ fp.displayDirectory = folder;
}
} catch (_) {
// If the file can not be found we will skip setting the displayDirectory.
diff --git a/browser/components/backup/content/restore-from-backup.mjs b/browser/components/backup/content/restore-from-backup.mjs
@@ -134,7 +134,7 @@ export default class RestoreFromBackup extends MozLitElement {
}
}
- async handleChooseBackupFile() {
+ handleChooseBackupFile() {
this.dispatchEvent(
new CustomEvent("BackupUI:ShowFilepicker", {
bubbles: true,
@@ -142,7 +142,7 @@ export default class RestoreFromBackup extends MozLitElement {
detail: {
win: window.browsingContext,
filter: "filterHTML",
- displayDirectoryPath: this.backupServiceState?.backupFileToRestore,
+ existingBackupPath: this.backupServiceState?.backupFileToRestore,
},
})
);
diff --git a/browser/components/backup/tests/browser/browser_settings_restore_from_backup.js b/browser/components/backup/tests/browser/browser_settings_restore_from_backup.js
@@ -170,6 +170,62 @@ add_task(async function test_restore_from_backup() {
});
/**
+ * Tests that the backup file chooser starts at the correct folder.
+ */
+add_task(async function test_restore_uses_matching_initial_folder() {
+ await BrowserTestUtils.withNewTab("about:preferences#sync", async browser => {
+ const mockBackupFilePath = await IOUtils.createUniqueFile(
+ TEST_PROFILE_PATH,
+ "backup.html"
+ );
+
+ const mockBackupFile = Cc["@mozilla.org/file/local;1"].createInstance(
+ Ci.nsIFile
+ );
+ mockBackupFile.initWithPath(mockBackupFilePath);
+
+ let filePickerShownPromise = new Promise(resolve => {
+ MockFilePicker.showCallback = async picker => {
+ Assert.equal(
+ picker.displayDirectory.path,
+ TEST_PROFILE_PATH,
+ "Folder containing backup was shown"
+ );
+ MockFilePicker.setFiles([mockBackupFile]);
+ resolve();
+ };
+ });
+ MockFilePicker.returnValue = MockFilePicker.returnOK;
+
+ let settings = browser.contentDocument.querySelector("backup-settings");
+ await settings.updateComplete;
+
+ Assert.ok(
+ settings.restoreFromBackupButtonEl,
+ "Button to restore backups should be found"
+ );
+
+ settings.restoreFromBackupButtonEl.click();
+ await settings.updateComplete;
+
+ let restoreFromBackup = settings.restoreFromBackupEl;
+ Assert.ok(restoreFromBackup, "restore-from-backup should be found");
+
+ let selectedFilePromise = BrowserTestUtils.waitForEvent(
+ settings,
+ "BackupUI:SelectNewFilepickerPath"
+ );
+
+ restoreFromBackup.backupServiceState.backupFileToRestore =
+ mockBackupFilePath;
+ restoreFromBackup.chooseButtonEl.click();
+
+ await filePickerShownPromise;
+ await selectedFilePromise;
+ });
+});
+
+/**
* Tests that the dialog stays open while restoring from the settings page.
*/
add_task(async function test_restore_in_progress() {
diff --git a/browser/components/backup/tests/chrome/test_restore_from_backup.html b/browser/components/backup/tests/chrome/test_restore_from_backup.html
@@ -85,6 +85,7 @@
*/
add_task(async function test_choose() {
let restoreFromBackup = document.getElementById("test-restore-from-backup");
+ restoreFromBackup.backupServiceState.backupFileToRestore = "/backup/file\\path.html";
ok(restoreFromBackup.chooseButtonEl, "Choose button should be found");
@@ -93,8 +94,11 @@
restoreFromBackup.chooseButtonEl.click();
- await promise;
+ let event = await promise;
ok(true, "Detected event after pressing the choose button");
+ is(event.detail.win, window.browsingContext, "Current window will be the parent");
+ is(event.detail.filter, "filterHTML", "Only HTML files will be shown");
+ is(event.detail.existingBackupPath, "/backup/file\\path.html", "Path to the backup file is given");
});
/**