commit 76ec61f47fa59e18c79d2793cea2dc7d12b19806
parent d5170780c8bb580ed73318c3a4458cc4fdb13714
Author: Harsheet <hsohaney@mozilla.com>
Date: Mon, 3 Nov 2025 16:59:48 +0000
Bug 1997067 - Add error handling for the case where there is no valid default folder for backups. r=cdupuis
Differential Revision: https://phabricator.services.mozilla.com/D270733
Diffstat:
3 files changed, 140 insertions(+), 17 deletions(-)
diff --git a/browser/components/backup/BackupService.sys.mjs b/browser/components/backup/BackupService.sys.mjs
@@ -841,10 +841,20 @@ export class BackupService extends EventTarget {
* @returns {string} The path of the default parent directory
*/
static get DEFAULT_PARENT_DIR_PATH() {
- return (
- BackupService.oneDriveFolderPath?.path ||
- Services.dirsvc.get("Docs", Ci.nsIFile).path
- );
+ let path = "";
+ try {
+ path =
+ BackupService.oneDriveFolderPath?.path ||
+ Services.dirsvc.get("Docs", Ci.nsIFile).path;
+ } catch (e) {
+ // If this errors, we can safely return an empty string
+ lazy.logConsole.error(
+ "There was an error when getting the Default Parent Directory: ",
+ e
+ );
+ }
+
+ return path;
}
/**
@@ -1162,11 +1172,13 @@ export class BackupService extends EventTarget {
get state() {
if (!Object.keys(this.#_state.defaultParent).length) {
let defaultPath = BackupService.DEFAULT_PARENT_DIR_PATH;
- this.#_state.defaultParent = {
- path: defaultPath,
- fileName: PathUtils.filename(defaultPath),
- iconURL: this.getIconFromFilePath(defaultPath),
- };
+ if (defaultPath) {
+ this.#_state.defaultParent = {
+ path: defaultPath,
+ fileName: PathUtils.filename(defaultPath),
+ iconURL: this.getIconFromFilePath(defaultPath),
+ };
+ }
}
return Object.freeze(structuredClone(this.#_state));
@@ -4118,6 +4130,14 @@ export class BackupService extends EventTarget {
this.stateUpdate();
}
+ /**
+ * TEST ONLY: reset's the defaultParent state for testing purposes
+ */
+ resetDefaultParentInternalState() {
+ this.#_state.defaultParent = {};
+ this.stateUpdate();
+ }
+
/*
* Attempts to open a native file explorer window at the last backup file's
* location on the filesystem.
diff --git a/browser/components/backup/content/turn-on-scheduled-backups.mjs b/browser/components/backup/content/turn-on-scheduled-backups.mjs
@@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-import { html } from "chrome://global/content/vendor/lit.all.mjs";
+import { html, nothing } from "chrome://global/content/vendor/lit.all.mjs";
import { MozLitElement } from "chrome://global/content/lit-utils.mjs";
// eslint-disable-next-line import/no-unassigned-import
@@ -255,17 +255,22 @@ export default class TurnOnScheduledBackups extends MozLitElement {
let filename = this.defaultLabel;
let iconURL = this.defaultIconURL || this.#placeholderIconURL;
+ const hasFilename = !!filename;
+ const l10nArgs = hasFilename
+ ? JSON.stringify({ recommendedFolder: filename })
+ : null;
+
return html`
<input
id="backup-location-filepicker-input-default"
class="backup-location-filepicker-input"
type="text"
readonly
- data-l10n-id="turn-on-scheduled-backups-location-default-folder"
- data-l10n-args=${JSON.stringify({
- recommendedFolder: filename,
- })}
- data-l10n-attrs="value"
+ data-l10n-id=${hasFilename
+ ? "turn-on-scheduled-backups-location-default-folder"
+ : nothing}
+ data-l10n-args=${hasFilename ? l10nArgs : nothing}
+ data-l10n-attrs=${hasFilename ? "value" : "placeholder"}
style=${`background-image: url(${iconURL})`}
/>
`;
diff --git a/browser/components/backup/tests/browser/browser_settings_create_backup.js b/browser/components/backup/tests/browser/browser_settings_create_backup.js
@@ -18,8 +18,8 @@ add_setup(async () => {
);
await SpecialPowers.pushPrefEnv({
set: [
- [BACKUP_DEFAULT_LOCATION_PREF, TEST_PROFILE_PATH],
- [SCHEDULED_BACKUPS_ENABLED_PREF, true],
+ [BACKUP_DEFAULT_LOCATION_PREF, ""],
+ [SCHEDULED_BACKUPS_ENABLED_PREF, false],
],
});
@@ -30,9 +30,107 @@ add_setup(async () => {
});
/**
+ * Tests the case where there is no DEFAULT_PARENT_DIR_PATH
+ */
+add_task(async function test_no_default_folder() {
+ const sandbox = sinon.createSandbox();
+
+ let bs = getAndMaybeInitBackupService();
+ bs.resetDefaultParentInternalState();
+
+ let callCount = 0;
+ let getterStub = sandbox
+ .stub(BackupService, "DEFAULT_PARENT_DIR_PATH")
+ .get(() => {
+ callCount++;
+ return "";
+ });
+
+ await BrowserTestUtils.withNewTab("about:preferences#sync", async browser => {
+ let settings = browser.contentDocument.querySelector("backup-settings");
+ let turnOnButton = settings.scheduledBackupsButtonEl;
+
+ await settings.updateComplete;
+
+ console.log(
+ "DO WE HAVE A DEFAULT PARENT ALREADY???",
+ settings.backupServiceState.defaultParent
+ );
+
+ Assert.ok(bs.archiveEnabledStatus, "Archive is enabled for backups");
+
+ Assert.ok(
+ turnOnButton,
+ "Button to turn on scheduled backups should be found"
+ );
+
+ turnOnButton.click();
+
+ await settings.updateComplete;
+
+ let turnOnScheduledBackups = settings.turnOnScheduledBackupsEl;
+
+ Assert.ok(
+ turnOnScheduledBackups,
+ "turn-on-scheduled-backups should be found"
+ );
+
+ // woops looks like getting the default dir threw an error, lets make sure we handled that
+ Assert.greaterOrEqual(
+ callCount,
+ 1,
+ "The default dir getter was called atleast once"
+ );
+
+ let filePathInputDefault = turnOnScheduledBackups.filePathInputDefaultEl;
+
+ Assert.equal(
+ filePathInputDefault.value,
+ "",
+ "Default input displays the expected text"
+ );
+
+ let dialog = settings.turnOnScheduledBackupsDialogEl;
+ let dialogClosePromise = BrowserTestUtils.waitForEvent(dialog, "close");
+ dialog.close();
+
+ await dialogClosePromise;
+
+ getterStub.restore();
+ });
+
+ await BrowserTestUtils.withNewTab("about:preferences#sync", async browser => {
+ let settings = browser.contentDocument.querySelector("backup-settings");
+
+ Assert.ok(
+ settings.turnOnScheduledBackupsEl,
+ "turn-on-scheduled-backups should be found"
+ );
+ settings.scheduledBackupsButtonEl.click();
+
+ const documentsPath = BackupService.DEFAULT_PARENT_DIR_PATH;
+
+ Assert.equal(
+ settings.turnOnScheduledBackupsEl.filePathInputDefaultEl.value,
+ `${PathUtils.filename(documentsPath)} (recommended)`,
+ "Default input displays the expected text"
+ );
+ });
+
+ sandbox.restore();
+ await SpecialPowers.popPrefEnv();
+});
+
+/**
* Test creating a new backup using the "Backup now" button
*/
add_task(async function test_create_new_backup_trigger() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ [BACKUP_DEFAULT_LOCATION_PREF, TEST_PROFILE_PATH],
+ [SCHEDULED_BACKUPS_ENABLED_PREF, true],
+ ],
+ });
await BrowserTestUtils.withNewTab("about:preferences#sync", async browser => {
Services.fog.testResetFOG();