1717
1818package org .openqa .selenium .firefox ;
1919
20+ import static org .openqa .selenium .remote .CapabilityType .PROXY ;
21+
2022import com .google .common .collect .ImmutableMap ;
2123import com .google .common .collect .Maps ;
2224import com .google .common .collect .Sets ;
25+
2326import org .openqa .selenium .Beta ;
2427import org .openqa .selenium .Capabilities ;
2528import org .openqa .selenium .ImmutableCapabilities ;
5861import java .util .Set ;
5962import java .util .stream .StreamSupport ;
6063
61- import static org .openqa .selenium .remote .CapabilityType .PROXY ;
62-
6364/**
6465 * An implementation of the {#link WebDriver} interface that drives Firefox.
6566 * <p>
7879public class FirefoxDriver extends RemoteWebDriver
7980 implements WebStorage , HasExtensions , HasFullPageScreenshot , HasContext , HasDevTools {
8081
81- public static final class SystemProperty {
82-
83- /**
84- * System property that defines the location of the Firefox executable file.
85- */
86- public static final String BROWSER_BINARY = "webdriver.firefox.bin" ;
87-
88- /**
89- * System property that defines the location of the file where Firefox log should be stored.
90- */
91- public static final String BROWSER_LOGFILE = "webdriver.firefox.logfile" ;
92-
93- /**
94- * System property that defines the additional library path (Linux only).
95- */
96- public static final String BROWSER_LIBRARY_PATH = "webdriver.firefox.library.path" ;
97-
98- /**
99- * System property that defines the profile that should be used as a template.
100- * When the driver starts, it will make a copy of the profile it is using,
101- * rather than using that profile directly.
102- */
103- public static final String BROWSER_PROFILE = "webdriver.firefox.profile" ;
104-
105- /**
106- * System property that defines the location of the webdriver.xpi browser extension to install
107- * in the browser. If not set, the prebuilt extension bundled with this class will be used.
108- */
109- public static final String DRIVER_XPI_PROPERTY = "webdriver.firefox.driver" ;
110-
111- /**
112- * Boolean system property that instructs FirefoxDriver to use Marionette backend,
113- * overrides any capabilities specified by the user
114- */
115- public static final String DRIVER_USE_MARIONETTE = "webdriver.firefox.marionette" ;
116- }
117-
11882 /**
11983 * @deprecated Use {@link Capability#BINARY}
12084 */
12185 @ Deprecated
12286 public static final String BINARY = Capability .BINARY ;
123-
12487 /**
12588 * @deprecated Use {@link Capability#PROFILE}
12689 */
12790 @ Deprecated
12891 public static final String PROFILE = Capability .PROFILE ;
129-
13092 /**
13193 * @deprecated Use {@link Capability#MARIONETTE}
13294 */
13395 @ Deprecated
13496 public static final String MARIONETTE = Capability .MARIONETTE ;
135-
136- public static final class Capability {
137- public static final String BINARY = "firefox_binary" ;
138- public static final String PROFILE = "firefox_profile" ;
139- public static final String MARIONETTE = "marionette" ;
140- }
141-
142- @ Beta
143- public static RemoteWebDriverBuilder builder () {
144- return RemoteWebDriver .builder ().oneOf (new FirefoxOptions ());
145- }
146-
147- private static class FirefoxDriverCommandExecutor extends DriverCommandExecutor {
148- public FirefoxDriverCommandExecutor (DriverService service ) {
149- super (service , getExtraCommands ());
150- }
151-
152- private static Map <String , CommandInfo > getExtraCommands () {
153- return ImmutableMap .<String , CommandInfo >builder ()
154- .putAll (new AddHasContext ().getAdditionalCommands ())
155- .putAll (new AddHasExtensions ().getAdditionalCommands ())
156- .putAll (new AddHasFullPageScreenshot ().getAdditionalCommands ())
157- .build ();
158- }
159- }
160-
16197 private final Capabilities capabilities ;
162- protected FirefoxBinary binary ;
16398 private final RemoteWebStorage webStorage ;
16499 private final HasExtensions extensions ;
165100 private final HasFullPageScreenshot fullPageScreenshot ;
166101 private final HasContext context ;
167102 private final Optional <URI > cdpUri ;
103+ protected FirefoxBinary binary ;
168104 private DevTools devTools ;
169-
170105 public FirefoxDriver () {
171106 this (new FirefoxOptions ());
172107 }
173-
174108 /**
175109 * @deprecated Use {@link #FirefoxDriver(FirefoxOptions)}.
176110 */
177111 @ Deprecated
178112 public FirefoxDriver (Capabilities desiredCapabilities ) {
179113 this (new FirefoxOptions (Require .nonNull ("Capabilities" , desiredCapabilities )));
180114 }
181-
182115 /**
183116 * @deprecated Use {@link #FirefoxDriver(FirefoxDriverService, FirefoxOptions)}.
184117 */
@@ -188,7 +121,6 @@ public FirefoxDriver(FirefoxDriverService service, Capabilities desiredCapabilit
188121 Require .nonNull ("Driver service" , service ),
189122 new FirefoxOptions (desiredCapabilities ));
190123 }
191-
192124 public FirefoxDriver (FirefoxOptions options ) {
193125 this (toExecutor (options ), options );
194126 }
@@ -215,30 +147,82 @@ private FirefoxDriver(FirefoxDriverCommandExecutor executor, FirefoxOptions opti
215147
216148 this .cdpUri = cdpUri ;
217149 this .capabilities = cdpUri .map (uri ->
218- new ImmutableCapabilities (
219- new PersistentCapabilities (capabilities )
220- .setCapability ("se:cdp" , uri .toString ())
221- .setCapability ("se:cdpVersion" , "85" )))
222- .orElse (new ImmutableCapabilities (capabilities ));
150+ new ImmutableCapabilities (
151+ new PersistentCapabilities (capabilities )
152+ .setCapability ("se:cdp" , uri .toString ())
153+ .setCapability ("se:cdpVersion" , "85.0" )))
154+ .orElse (new ImmutableCapabilities (capabilities ));
155+ }
156+
157+ @ Beta
158+ public static RemoteWebDriverBuilder builder () {
159+ return RemoteWebDriver .builder ().oneOf (new FirefoxOptions ());
223160 }
224161
225162 private static FirefoxDriverCommandExecutor toExecutor (FirefoxOptions options ) {
226163 Require .nonNull ("Options to construct executor from" , options );
227164
228165 String sysProperty = System .getProperty (SystemProperty .DRIVER_USE_MARIONETTE );
229- boolean isLegacy = (sysProperty != null && ! Boolean .parseBoolean (sysProperty ))
166+ boolean isLegacy = (sysProperty != null && !Boolean .parseBoolean (sysProperty ))
230167 || options .isLegacy ();
231168
232169 FirefoxDriverService .Builder <?, ?> builder =
233- StreamSupport .stream (ServiceLoader .load (DriverService .Builder .class ).spliterator (), false )
234- .filter (b -> b instanceof FirefoxDriverService .Builder )
235- .map (FirefoxDriverService .Builder .class ::cast )
236- .filter (b -> b .isLegacy () == isLegacy )
237- .findFirst ().orElseThrow (WebDriverException ::new );
170+ StreamSupport .stream (ServiceLoader .load (DriverService .Builder .class ).spliterator (), false )
171+ .filter (b -> b instanceof FirefoxDriverService .Builder )
172+ .map (FirefoxDriverService .Builder .class ::cast )
173+ .filter (b -> b .isLegacy () == isLegacy )
174+ .findFirst ().orElseThrow (WebDriverException ::new );
238175
239176 return new FirefoxDriverCommandExecutor (builder .withOptions (options ).build ());
240177 }
241178
179+ private static boolean isLegacy (Capabilities desiredCapabilities ) {
180+ Boolean forceMarionette = forceMarionetteFromSystemProperty ();
181+ if (forceMarionette != null ) {
182+ return !forceMarionette ;
183+ }
184+ Object marionette = desiredCapabilities .getCapability (Capability .MARIONETTE );
185+ return marionette instanceof Boolean && !(Boolean ) marionette ;
186+ }
187+
188+ private static Boolean forceMarionetteFromSystemProperty () {
189+ String useMarionette = System .getProperty (SystemProperty .DRIVER_USE_MARIONETTE );
190+ if (useMarionette == null ) {
191+ return null ;
192+ }
193+ return Boolean .valueOf (useMarionette );
194+ }
195+
196+ /**
197+ * Drops capabilities that we shouldn't send over the wire.
198+ *
199+ * Used for capabilities which aren't BeanToJson-convertable, and are only used by the local
200+ * launcher.
201+ */
202+ private static Capabilities dropCapabilities (Capabilities capabilities ) {
203+ if (capabilities == null ) {
204+ return new ImmutableCapabilities ();
205+ }
206+
207+ MutableCapabilities caps ;
208+
209+ if (isLegacy (capabilities )) {
210+ final Set <String > toRemove = Sets .newHashSet (Capability .BINARY , Capability .PROFILE );
211+ caps = new MutableCapabilities (
212+ Maps .filterKeys (capabilities .asMap (), key -> !toRemove .contains (key )));
213+ } else {
214+ caps = new MutableCapabilities (capabilities );
215+ }
216+
217+ // Ensure that the proxy is in a state fit to be sent to the extension
218+ Proxy proxy = Proxy .extractFrom (capabilities );
219+ if (proxy != null ) {
220+ caps .setCapability (PROXY , proxy );
221+ }
222+
223+ return caps ;
224+ }
225+
242226 @ Override
243227 public Capabilities getCapabilities () {
244228 return capabilities ;
@@ -247,8 +231,8 @@ public Capabilities getCapabilities() {
247231 @ Override
248232 public void setFileDetector (FileDetector detector ) {
249233 throw new WebDriverException (
250- "Setting the file detector only works on remote webdriver instances obtained " +
251- "via RemoteWebDriver" );
234+ "Setting the file detector only works on remote webdriver instances obtained " +
235+ "via RemoteWebDriver" );
252236 }
253237
254238 @ Override
@@ -261,15 +245,6 @@ public SessionStorage getSessionStorage() {
261245 return webStorage .getSessionStorage ();
262246 }
263247
264- private static boolean isLegacy (Capabilities desiredCapabilities ) {
265- Boolean forceMarionette = forceMarionetteFromSystemProperty ();
266- if (forceMarionette != null ) {
267- return !forceMarionette ;
268- }
269- Object marionette = desiredCapabilities .getCapability (Capability .MARIONETTE );
270- return marionette instanceof Boolean && ! (Boolean ) marionette ;
271- }
272-
273248 @ Override
274249 public String installExtension (Path path ) {
275250 Require .nonNull ("Path" , path );
@@ -304,53 +279,15 @@ public <X> X getFullPageScreenshotAs(OutputType<X> outputType) throws WebDriverE
304279 return fullPageScreenshot .getFullPageScreenshotAs (outputType );
305280 }
306281
307- @ Override
308- public void setContext (FirefoxCommandContext commandContext ) {
309- Require .nonNull ("Firefox Command Context" , commandContext );
310- context .setContext (commandContext );
311- }
312-
313282 @ Override
314283 public FirefoxCommandContext getContext () {
315284 return context .getContext ();
316285 }
317286
318- private static Boolean forceMarionetteFromSystemProperty () {
319- String useMarionette = System .getProperty (SystemProperty .DRIVER_USE_MARIONETTE );
320- if (useMarionette == null ) {
321- return null ;
322- }
323- return Boolean .valueOf (useMarionette );
324- }
325-
326- /**
327- * Drops capabilities that we shouldn't send over the wire.
328- *
329- * Used for capabilities which aren't BeanToJson-convertable, and are only used by the local
330- * launcher.
331- */
332- private static Capabilities dropCapabilities (Capabilities capabilities ) {
333- if (capabilities == null ) {
334- return new ImmutableCapabilities ();
335- }
336-
337- MutableCapabilities caps ;
338-
339- if (isLegacy (capabilities )) {
340- final Set <String > toRemove = Sets .newHashSet (Capability .BINARY , Capability .PROFILE );
341- caps = new MutableCapabilities (
342- Maps .filterKeys (capabilities .asMap (), key -> !toRemove .contains (key )));
343- } else {
344- caps = new MutableCapabilities (capabilities );
345- }
346-
347- // Ensure that the proxy is in a state fit to be sent to the extension
348- Proxy proxy = Proxy .extractFrom (capabilities );
349- if (proxy != null ) {
350- caps .setCapability (PROXY , proxy );
351- }
352-
353- return caps ;
287+ @ Override
288+ public void setContext (FirefoxCommandContext commandContext ) {
289+ Require .nonNull ("Firefox Command Context" , commandContext );
290+ context .setContext (commandContext );
354291 }
355292
356293 @ Override
@@ -383,6 +320,66 @@ public DevTools getDevTools() {
383320 throw new DevToolsException ("This version of Firefox or geckodriver does not support CDP" );
384321 }
385322
386- return maybeGetDevTools ().orElseThrow (() -> new DevToolsException ("Unable to initialize CDP connection" ));
323+ return maybeGetDevTools ()
324+ .orElseThrow (() -> new DevToolsException ("Unable to initialize CDP connection" ));
325+ }
326+
327+ public static final class SystemProperty {
328+
329+ /**
330+ * System property that defines the location of the Firefox executable file.
331+ */
332+ public static final String BROWSER_BINARY = "webdriver.firefox.bin" ;
333+
334+ /**
335+ * System property that defines the location of the file where Firefox log should be stored.
336+ */
337+ public static final String BROWSER_LOGFILE = "webdriver.firefox.logfile" ;
338+
339+ /**
340+ * System property that defines the additional library path (Linux only).
341+ */
342+ public static final String BROWSER_LIBRARY_PATH = "webdriver.firefox.library.path" ;
343+
344+ /**
345+ * System property that defines the profile that should be used as a template.
346+ * When the driver starts, it will make a copy of the profile it is using,
347+ * rather than using that profile directly.
348+ */
349+ public static final String BROWSER_PROFILE = "webdriver.firefox.profile" ;
350+
351+ /**
352+ * System property that defines the location of the webdriver.xpi browser extension to install
353+ * in the browser. If not set, the prebuilt extension bundled with this class will be used.
354+ */
355+ public static final String DRIVER_XPI_PROPERTY = "webdriver.firefox.driver" ;
356+
357+ /**
358+ * Boolean system property that instructs FirefoxDriver to use Marionette backend,
359+ * overrides any capabilities specified by the user
360+ */
361+ public static final String DRIVER_USE_MARIONETTE = "webdriver.firefox.marionette" ;
362+ }
363+
364+ public static final class Capability {
365+
366+ public static final String BINARY = "firefox_binary" ;
367+ public static final String PROFILE = "firefox_profile" ;
368+ public static final String MARIONETTE = "marionette" ;
369+ }
370+
371+ private static class FirefoxDriverCommandExecutor extends DriverCommandExecutor {
372+
373+ public FirefoxDriverCommandExecutor (DriverService service ) {
374+ super (service , getExtraCommands ());
375+ }
376+
377+ private static Map <String , CommandInfo > getExtraCommands () {
378+ return ImmutableMap .<String , CommandInfo >builder ()
379+ .putAll (new AddHasContext ().getAdditionalCommands ())
380+ .putAll (new AddHasExtensions ().getAdditionalCommands ())
381+ .putAll (new AddHasFullPageScreenshot ().getAdditionalCommands ())
382+ .build ();
383+ }
387384 }
388385}
0 commit comments