Bug 1586798 - Use WalkerFront from the currently selected element in onTagEdit()...
[gecko.git] / testing / marionette / prefs.js
blob5bce4c3018b70bc2936055d341234a013171edda
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 "use strict";
7 const { Log } = ChromeUtils.import("resource://gre/modules/Log.jsm");
8 const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
9 const { XPCOMUtils } = ChromeUtils.import(
10   "resource://gre/modules/XPCOMUtils.jsm"
13 XPCOMUtils.defineLazyServiceGetter(
14   this,
15   "env",
16   "@mozilla.org/process/environment;1",
17   "nsIEnvironment"
20 const { PREF_BOOL, PREF_INT, PREF_INVALID, PREF_STRING } = Ci.nsIPrefBranch;
22 this.EXPORTED_SYMBOLS = ["Branch", "MarionettePrefs"];
24 class Branch {
25   /**
26    * @param {string=} branch
27    *     Preference subtree.  Uses root tree given `null`.
28    */
29   constructor(branch) {
30     this._branch = Services.prefs.getBranch(branch);
31   }
33   /**
34    * Gets value of `pref` in its known type.
35    *
36    * @param {string} pref
37    *     Preference name.
38    * @param {?=} fallback
39    *     Fallback value to return if `pref` does not exist.
40    *
41    * @return {(string|boolean|number)}
42    *     Value of `pref`, or the `fallback` value if `pref` does
43    *     not exist.
44    *
45    * @throws {TypeError}
46    *     If `pref` is not a recognised preference and no `fallback`
47    *     value has been provided.
48    */
49   get(pref, fallback = null) {
50     switch (this._branch.getPrefType(pref)) {
51       case PREF_STRING:
52         return this._branch.getStringPref(pref);
54       case PREF_BOOL:
55         return this._branch.getBoolPref(pref);
57       case PREF_INT:
58         return this._branch.getIntPref(pref);
60       case PREF_INVALID:
61       default:
62         if (fallback != null) {
63           return fallback;
64         }
65         throw new TypeError(`Unrecognised preference: ${pref}`);
66     }
67   }
69   /**
70    * Sets the value of `pref`.
71    *
72    * @param {string} pref
73    *     Preference name.
74    * @param {(string|boolean|number)} value
75    *     `pref`'s new value.
76    *
77    * @throws {TypeError}
78    *     If `value` is not the correct type for `pref`.
79    */
80   set(pref, value) {
81     let typ;
82     if (typeof value != "undefined" && value != null) {
83       typ = value.constructor.name;
84     }
86     switch (typ) {
87       case "String":
88         // Unicode compliant
89         return this._branch.setStringPref(pref, value);
91       case "Boolean":
92         return this._branch.setBoolPref(pref, value);
94       case "Number":
95         return this._branch.setIntPref(pref, value);
97       default:
98         throw new TypeError(`Illegal preference type value: ${typ}`);
99     }
100   }
104  * Provides shortcuts for lazily getting and setting typed Marionette
105  * preferences.
107  * Some of Marionette's preferences are stored using primitive values
108  * that internally are represented by complex types.  One such example
109  * is `marionette.log.level` which stores a string such as `info` or
110  * `DEBUG`, and which is represented as `Log.Level`.
112  * Because we cannot trust the input of many of these preferences,
113  * this class provides abstraction that lets us safely deal with
114  * potentially malformed input.  In the `marionette.log.level` example,
115  * `DEBUG`, `Debug`, and `dEbUg` are considered valid inputs and the
116  * `LogBranch` specialisation deserialises the string value to the
117  * correct `Log.Level` by sanitising the input data first.
119  * A further complication is that we cannot rely on `Preferences.jsm`
120  * in Marionette.  See https://bugzilla.mozilla.org/show_bug.cgi?id=1357517
121  * for further details.
122  */
123 class MarionetteBranch extends Branch {
124   constructor(branch = "marionette.") {
125     super(branch);
126   }
128   /**
129    * The `marionette.enabled` preference.  When it returns true,
130    * this signifies that the Marionette server is running.
131    *
132    * @return {boolean}
133    */
134   get enabled() {
135     return this.get("enabled", false);
136   }
138   set enabled(isEnabled) {
139     this.set("enabled", isEnabled);
140   }
142   /**
143    * The `marionette.debugging.clicktostart` preference delays
144    * server startup until a modal dialogue has been clicked to allow
145    * time for user to set breakpoints in the Browser Toolbox.
146    *
147    * @return {boolean}
148    */
149   get clickToStart() {
150     return this.get("debugging.clicktostart", false);
151   }
153   /**
154    * Whether content scripts can be safely reused.
155    *
156    * @deprecated
157    * @return {boolean}
158    */
159   get contentListener() {
160     return this.get("contentListener", false);
161   }
163   set contentListener(value) {
164     this.set("contentListener", value);
165   }
167   /**
168    * The `marionette.port` preference, detailing which port
169    * the TCP server should listen on.
170    *
171    * @return {number}
172    */
173   get port() {
174     return this.get("port", 2828);
175   }
177   set port(newPort) {
178     this.set("port", newPort);
179   }
181   /**
182    * Fail-safe return of the current log level from preference
183    * `marionette.log.level`.
184    *
185    * @return {Log.Level}
186    */
187   get logLevel() {
188     // TODO: when geckodriver's minimum supported Firefox version reaches 62,
189     // the lower-casing here can be dropped (https://bugzil.la/1482829)
190     switch (this.get("log.level", "info").toLowerCase()) {
191       case "fatal":
192         return Log.Level.Fatal;
193       case "error":
194         return Log.Level.Error;
195       case "warn":
196         return Log.Level.Warn;
197       case "config":
198         return Log.Level.Config;
199       case "debug":
200         return Log.Level.Debug;
201       case "trace":
202         return Log.Level.Trace;
203       case "info":
204       default:
205         return Log.Level.Info;
206     }
207   }
209   /**
210    * Certain log messages that are known to be long are truncated
211    * before they are dumped to stdout.  The `marionette.log.truncate`
212    * preference indicates that the values should not be truncated.
213    *
214    * @return {boolean}
215    */
216   get truncateLog() {
217     return this.get("log.truncate");
218   }
220   /**
221    * Gets the `marionette.prefs.recommended` preference, signifying
222    * whether recommended automation preferences will be set when
223    * Marionette is started.
224    *
225    * @return {boolean}
226    */
227   get recommendedPrefs() {
228     return this.get("prefs.recommended", true);
229   }
232 /** Reads a JSON serialised blob stored in the environment. */
233 class EnvironmentPrefs {
234   /**
235    * Reads the environment variable `key` and tries to parse it as
236    * JSON Object, then provides an iterator over its keys and values.
237    *
238    * If the environment variable is not set, this function returns empty.
239    *
240    * @param {string} key
241    *     Environment variable.
242    *
243    * @return {Iterable.<string, (string|boolean|number)>
244    */
245   static *from(key) {
246     if (!env.exists(key)) {
247       return;
248     }
250     let prefs;
251     try {
252       prefs = JSON.parse(env.get(key));
253     } catch (e) {
254       throw new TypeError(`Unable to parse prefs from ${key}`, e);
255     }
257     for (let prefName of Object.keys(prefs)) {
258       yield [prefName, prefs[prefName]];
259     }
260   }
263 this.Branch = Branch;
264 this.EnvironmentPrefs = EnvironmentPrefs;
266 // There is a future potential of exposing this as Marionette.prefs.port
267 // if we introduce a Marionette.jsm module.
268 this.MarionettePrefs = new MarionetteBranch();