commit 884ba6e5ec39012cc63e571e8d967b5d97a80c5d
parent 9858dfd5c9408a4a02bac409b5b46967256dffd9
Author: Tim Giles <tgiles@mozilla.com>
Date: Tue, 7 Oct 2025 20:43:56 +0000
Bug 1990509 - Throw error if addSetting is called with unregistered pref. r=mkennedy
Differential Revision: https://phabricator.services.mozilla.com/D266720
Diffstat:
3 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/browser/components/preferences/main.js b/browser/components/preferences/main.js
@@ -414,7 +414,9 @@ Preferences.addSetting({
});
Preferences.addSetting({
id: "useOnScreenKeyboard",
- pref: "ui.osk.enabled",
+ // Bug 1993053: Restore the pref to `ui.osk.enabled` after changing
+ // the PrefereceNotFoundError throwing behavior.
+ pref: AppConstants.platform == "win" ? "ui.osk.enabled" : undefined,
visible: () => AppConstants.platform == "win",
});
Preferences.addSetting({
diff --git a/toolkit/content/preferences/Setting.mjs b/toolkit/content/preferences/Setting.mjs
@@ -35,6 +35,17 @@ ChromeUtils.defineESModuleGetters(lazy, {
* @typedef {string | boolean | number} SettingValue
*/
+class PreferenceNotAddedError extends Error {
+ constructor(settingId, prefId) {
+ super(
+ `Setting "${settingId}" was unable to find Preference "${prefId}". Did you register it with Preferences.add/addAll?`
+ );
+ this.name = "PreferenceNotAddedError";
+ this.settingId = settingId;
+ this.prefId = prefId;
+ }
+}
+
export class Setting extends EventEmitter {
/**
* @type {Preference | undefined | null}
@@ -57,6 +68,8 @@ export class Setting extends EventEmitter {
/**
* @param {PreferencesSettingsConfig['id']} id
* @param {PreferencesSettingsConfig} config
+ * @throws {Error} Will throw an error (PreferenceNotAddedError) if
+ * config.pref was not registered
*/
constructor(id, config) {
super();
@@ -68,6 +81,9 @@ export class Setting extends EventEmitter {
this.id = id;
this.config = config;
this.pref = config.pref && Preferences.get(config.pref);
+ if (config.pref && !this.pref) {
+ throw new PreferenceNotAddedError(id, config.pref);
+ }
this._emitting = false;
this.controllingExtensionInfo = {
diff --git a/toolkit/content/tests/chrome/test_preferencesBindings_setting.html b/toolkit/content/tests/chrome/test_preferencesBindings_setting.html
@@ -431,6 +431,27 @@
"Circular dependencies don't produce any console errors."
);
});
+
+ // Verify that a PreferenceNotAddedError is thrown if adding a
+ // Setting with a preference that has not been registered
+ // through Preferences.add/addAll.
+ add_task(async function testPrefNotRegistered() {
+ const PREF_ID = "non_existent_pref";
+ const SETTING_ID = "testSettingNoPref";
+ try {
+ Preferences.addSetting({
+ id: SETTING_ID,
+ pref: PREF_ID,
+ });
+ } catch (e) {
+ let errorName = e.name;
+ is(
+ errorName,
+ "PreferenceNotAddedError",
+ "Adding a Setting without registering the Preference should throw a PreferenceNotAddedError"
+ );
+ }
+ });
</script>
</head>
<body>