33
33
34
34
import org .openqa .selenium .Capabilities ;
35
35
import org .openqa .selenium .SessionNotCreatedException ;
36
+ import org .openqa .selenium .WebDriver ;
36
37
import org .openqa .selenium .WebDriverException ;
37
38
import org .openqa .selenium .firefox .internal .ProfilesIni ;
38
39
import org .openqa .selenium .logging .LoggingPreferences ;
39
40
import org .openqa .selenium .remote .CapabilityType ;
40
41
import org .openqa .selenium .remote .DesiredCapabilities ;
41
42
43
+ import sun .awt .image .ByteInterleavedRaster ;
44
+
42
45
import java .io .File ;
43
46
import java .io .IOException ;
44
47
import java .nio .file .Path ;
45
48
import java .nio .file .Paths ;
46
49
import java .util .ArrayList ;
47
50
import java .util .Collection ;
51
+ import java .util .Collections ;
48
52
import java .util .HashMap ;
49
53
import java .util .List ;
50
54
import java .util .Map ;
51
55
import java .util .Optional ;
52
56
import java .util .logging .Level ;
57
+ import java .util .logging .Logger ;
53
58
import java .util .stream .Collectors ;
54
59
import java .util .stream .Stream ;
55
60
68
73
public class FirefoxOptions {
69
74
70
75
public final static String FIREFOX_OPTIONS = "moz:firefoxOptions" ;
76
+ private final static Logger LOG = Logger .getLogger (FirefoxOptions .class .getName ());
71
77
72
78
private String binaryPath ;
73
79
private FirefoxBinary actualBinary ;
@@ -159,18 +165,24 @@ public boolean isLegacy() {
159
165
public FirefoxOptions setBinary (FirefoxBinary binary ) {
160
166
this .actualBinary = Preconditions .checkNotNull (binary );
161
167
binary .amendOptions (this );
168
+ desiredCapabilities .setCapability (BINARY , binary );
162
169
this .binaryPath = null ;
163
170
return this ;
164
171
}
165
172
166
173
public FirefoxOptions setBinary (Path path ) {
167
174
// Default to UNIX-style paths, even on Windows.
168
- StringBuilder builder = new StringBuilder (path .isAbsolute () ? "/" : "" );
169
- this .binaryPath = Joiner .on ("/" ).appendTo (builder , path ).toString ();
175
+ this .binaryPath = asUnixPath (path );
170
176
this .actualBinary = null ;
177
+ desiredCapabilities .setCapability (BINARY , new FirefoxBinary (path .toFile ()));
171
178
return this ;
172
179
}
173
180
181
+ private String asUnixPath (Path path ) {
182
+ StringBuilder builder = new StringBuilder (path .isAbsolute () ? "/" : "" );
183
+ return Joiner .on ("/" ).appendTo (builder , path ).toString ();
184
+ }
185
+
174
186
public FirefoxOptions setBinary (String path ) {
175
187
return setBinary (Paths .get (checkNotNull (path )));
176
188
}
@@ -228,6 +240,16 @@ private Optional<FirefoxBinary> determineBinaryFromCapabilities(Capabilities cap
228
240
229
241
public FirefoxOptions setProfile (FirefoxProfile profile ) {
230
242
this .profile = profile ;
243
+
244
+ if (!booleanPrefs .isEmpty () || !intPrefs .isEmpty () || !stringPrefs .isEmpty ()) {
245
+ LOG .info ("Will update profile with preferences from these options." );
246
+ booleanPrefs .entrySet ().forEach (e -> profile .setPreference (e .getKey (), e .getValue ()));
247
+ intPrefs .entrySet ().forEach (e -> profile .setPreference (e .getKey (), e .getValue ()));
248
+ stringPrefs .entrySet ().forEach (e -> profile .setPreference (e .getKey (), e .getValue ()));
249
+ }
250
+
251
+ desiredCapabilities .setCapability (PROFILE , profile );
252
+
231
253
return this ;
232
254
}
233
255
@@ -289,14 +311,6 @@ private static void populateProfile(FirefoxProfile profile, Capabilities capabil
289
311
}
290
312
}
291
313
292
- // Confusing API. Keeping package visible only
293
- FirefoxOptions setProfileSafely (FirefoxProfile profile ) {
294
- if (profile == null ) {
295
- return this ;
296
- }
297
- return setProfile (profile );
298
- }
299
-
300
314
public FirefoxOptions addArguments (String ... arguments ) {
301
315
addArguments (ImmutableList .copyOf (arguments ));
302
316
return this ;
@@ -309,16 +323,25 @@ public FirefoxOptions addArguments(List<String> arguments) {
309
323
310
324
public FirefoxOptions addPreference (String key , boolean value ) {
311
325
booleanPrefs .put (checkNotNull (key ), value );
326
+ if (profile != null ) {
327
+ profile .setPreference (key , value );
328
+ }
312
329
return this ;
313
330
}
314
331
315
332
public FirefoxOptions addPreference (String key , int value ) {
316
333
intPrefs .put (checkNotNull (key ), value );
334
+ if (profile != null ) {
335
+ profile .setPreference (key , value );
336
+ }
317
337
return this ;
318
338
}
319
339
320
340
public FirefoxOptions addPreference (String key , String value ) {
321
341
stringPrefs .put (checkNotNull (key ), checkNotNull (value ));
342
+ if (profile != null ) {
343
+ profile .setPreference (key , value );
344
+ }
322
345
return this ;
323
346
}
324
347
@@ -328,28 +351,33 @@ public FirefoxOptions setLogLevel(Level logLevel) {
328
351
}
329
352
330
353
public FirefoxOptions addDesiredCapabilities (Capabilities desiredCapabilities ) {
331
- if (desiredCapabilities == null ) {
354
+ return validateAndAmendUsing (this .desiredCapabilities , desiredCapabilities );
355
+ }
356
+
357
+ public FirefoxOptions addRequiredCapabilities (Capabilities requiredCapabilities ) {
358
+ return validateAndAmendUsing (this .requiredCapabilities , requiredCapabilities );
359
+ }
360
+
361
+ private FirefoxOptions validateAndAmendUsing (DesiredCapabilities existing , Capabilities caps ) {
362
+ if (caps == null ) {
332
363
return this ;
333
364
}
334
365
335
- this . desiredCapabilities . merge (desiredCapabilities );
366
+ existing . merge (caps );
336
367
337
- FirefoxProfile suggestedProfile = extractProfile (desiredCapabilities );
338
- if (suggestedProfile != null ) {
339
- if (!booleanPrefs .isEmpty () || !intPrefs .isEmpty () || !stringPrefs .isEmpty ()) {
340
- throw new IllegalStateException (
341
- "Unable to determine if preferences set on this option " +
342
- "are the same as the profile in the capabilities" );
343
- }
344
- if (profile != null && !suggestedProfile .equals (profile )) {
345
- throw new IllegalStateException (
346
- "Profile has been set on both the capabilities and these options, but they're " +
347
- "different. Unable to determine which one you want to use." );
348
- }
349
- profile = suggestedProfile ;
368
+ FirefoxProfile newProfile = extractProfile (caps );
369
+ if (profile != null && newProfile != null && !profile .equals (newProfile )) {
370
+ LOG .info ("Found a profile on these options and the capabilities. Will assume you " +
371
+ "want the profile already set here. If you're seeing this in the logs of the " +
372
+ "standalone server, we've probably just deserialized the same options twice and " +
373
+ "it's likely that there's nothing to worry about." );
350
374
}
351
375
352
- Object binary = desiredCapabilities .getCapability (BINARY );
376
+ if (newProfile != null ) {
377
+ setProfile (newProfile );
378
+ }
379
+
380
+ Object binary = existing .getCapability (BINARY );
353
381
if (binary != null ) {
354
382
if (binary instanceof File ) {
355
383
setBinary (((File ) binary ).toPath ());
@@ -365,27 +393,6 @@ public FirefoxOptions addDesiredCapabilities(Capabilities desiredCapabilities) {
365
393
return this ;
366
394
}
367
395
368
- public FirefoxOptions addRequiredCapabilities (Capabilities requiredCapabilities ) {
369
- this .requiredCapabilities .merge (requiredCapabilities );
370
-
371
- FirefoxProfile suggestedProfile = extractProfile (desiredCapabilities );
372
- if (suggestedProfile != null ) {
373
- if (!booleanPrefs .isEmpty () || !intPrefs .isEmpty () || !stringPrefs .isEmpty ()) {
374
- throw new IllegalStateException (
375
- "Unable to determine if preferences set on this option " +
376
- "are the same as the profile in the capabilities" );
377
- }
378
- if (profile != null && !suggestedProfile .equals (profile )) {
379
- throw new IllegalStateException (
380
- "Profile has been set on both the capabilities and these options, but they're " +
381
- "different. Unable to determine which one you want to use." );
382
- }
383
- profile = suggestedProfile ;
384
- }
385
-
386
- return this ;
387
- }
388
-
389
396
private FirefoxProfile extractProfile (Capabilities capabilities ) {
390
397
if (capabilities == null ) {
391
398
return null ;
@@ -409,7 +416,15 @@ private FirefoxProfile extractProfile(Capabilities capabilities) {
409
416
}
410
417
411
418
public Capabilities toDesiredCapabilities () {
412
- DesiredCapabilities capabilities = new DesiredCapabilities (desiredCapabilities );
419
+ return toCapabilities (desiredCapabilities );
420
+ }
421
+
422
+ public Capabilities toRequiredCapabilities () {
423
+ return toCapabilities (requiredCapabilities );
424
+ }
425
+
426
+ private Capabilities toCapabilities (Capabilities source ) {
427
+ DesiredCapabilities capabilities = new DesiredCapabilities (source );
413
428
414
429
if (isLegacy ()) {
415
430
capabilities .setCapability (FirefoxDriver .MARIONETTE , false );
@@ -418,40 +433,54 @@ public Capabilities toDesiredCapabilities() {
418
433
Object priorBinary = capabilities .getCapability (BINARY );
419
434
if (priorBinary instanceof Path ) {
420
435
// Again, unix-style path
421
- priorBinary = Joiner . on ( "/" ). join ((Path ) priorBinary );
436
+ priorBinary = asUnixPath ((Path ) priorBinary );
422
437
}
423
438
if (priorBinary instanceof String ) {
424
- if (actualBinary != null || !priorBinary .equals (binaryPath )) {
425
- throw new IllegalStateException (String .format (
426
- "Binary already set in capabilities, but is different from the one set here: %s, %s" ,
427
- priorBinary ,
428
- binaryPath != null ? binaryPath : actualBinary ));
429
- }
439
+ priorBinary = asUnixPath (Paths .get ((String ) priorBinary ));
430
440
}
431
441
if (priorBinary instanceof FirefoxBinary ) {
432
- // Relies on instance equality, which is fragile.
433
- if (binaryPath != null || !priorBinary .equals (actualBinary )) {
434
- throw new IllegalStateException (String .format (
435
- "Binary already set in capabilities, but is different from the one set here: %s, %s" ,
436
- priorBinary ,
437
- actualBinary != null ? actualBinary : binaryPath ));
438
- }
442
+ priorBinary = asUnixPath (((FirefoxBinary ) priorBinary ).getFile ().toPath ());
443
+ }
444
+
445
+ if ((actualBinary != null && !actualBinary .getFile ().toPath ().equals (priorBinary )) ||
446
+ (binaryPath != null && !binaryPath .equals (priorBinary ))) {
447
+ LOG .info (String .format (
448
+ "Preferring the firefox binary in these options (%s rather than %s)" ,
449
+ actualBinary != null ? actualBinary .getPath () : binaryPath ,
450
+ priorBinary ));
451
+ }
452
+ if (actualBinary != null && binaryPath == null ) {
453
+ capabilities .setCapability (BINARY , actualBinary );
454
+ } else if (binaryPath != null && actualBinary == null ) {
455
+ capabilities .setCapability (BINARY , new FirefoxBinary (new File (binaryPath )));
439
456
}
440
457
441
458
Object priorProfile = capabilities .getCapability (PROFILE );
459
+ if (priorProfile instanceof String ) {
460
+ try {
461
+ priorProfile = FirefoxProfile .fromJson ((String ) priorProfile );
462
+ } catch (IOException e ) {
463
+ throw new WebDriverException (e );
464
+ }
465
+ }
442
466
if (priorProfile != null ) {
443
467
if (!booleanPrefs .isEmpty () || !intPrefs .isEmpty () || !stringPrefs .isEmpty ()) {
444
- throw new IllegalStateException (
445
- "Unable to determine if preferences set on this option " +
446
- "are the same as the profile in the capabilities" );
468
+ LOG .info ("Setting our our preferences on the existing profile" );
447
469
}
448
470
if (profile != null && !priorProfile .equals (profile )) {
449
- throw new IllegalStateException (
450
- "Profile has been set on both the capabilities and these options, but they're " +
451
- "different. Unable to determine which one you want to use." );
471
+ LOG .info ("Found a profile on these options and the capabilities. Will assume you " +
472
+ "want the profile already set here. If you're seeing this in the logs of the " +
473
+ "standalone server, we've probably just deserialized the same options twice and " +
474
+ "it's likely that there's nothing to worry about." );
475
+ }
476
+ if (profile == null ) {
477
+ if (priorProfile instanceof FirefoxProfile ) {
478
+ profile = (FirefoxProfile ) priorProfile ;
479
+ } else {
480
+ LOG .info ("Unable to use profile: " + priorProfile .getClass ());
481
+ }
452
482
}
453
483
}
454
-
455
484
capabilities .setCapability (FIREFOX_OPTIONS , this );
456
485
457
486
if (actualBinary != null ) {
@@ -469,12 +498,9 @@ public Capabilities toDesiredCapabilities() {
469
498
return capabilities ;
470
499
}
471
500
472
- public Capabilities toRequiredCapabilities () {
473
- return requiredCapabilities ;
474
- }
475
-
476
501
public DesiredCapabilities addTo (DesiredCapabilities capabilities ) {
477
502
capabilities .merge (toDesiredCapabilities ());
503
+ capabilities .merge (toRequiredCapabilities ());
478
504
return capabilities ;
479
505
}
480
506
0 commit comments