Skip to content

Commit

Permalink
[java] Merge mutable capabilities with options correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
pujagani authored Nov 28, 2022
1 parent ef63f5d commit 955581f
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 0 deletions.
1 change: 1 addition & 0 deletions java/src/org/openqa/selenium/MutableCapabilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class MutableCapabilities implements Capabilities {
static {
HashSet<String> keys = new HashSet<>();
keys.add("goog:chromeOptions");
keys.add("ms:edgeOptions");
keys.add("moz:firefoxOptions");
keys.add("se:ieOptions");
OPTION_KEYS = Collections.unmodifiableSet(keys);
Expand Down
2 changes: 2 additions & 0 deletions java/src/org/openqa/selenium/chrome/ChromeOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ public ChromeOptions merge(Capabilities extraCapabilities) {
ChromeOptions newInstance = new ChromeOptions();
newInstance.mergeInPlace(this);
newInstance.mergeInPlace(extraCapabilities);
newInstance.mergeInOptionsFromCaps(CAPABILITY, extraCapabilities);

return newInstance;
}

Expand Down
45 changes: 45 additions & 0 deletions java/src/org/openqa/selenium/chromium/ChromiumOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -290,4 +290,49 @@ protected void mergeInPlace(Capabilities capabilities) {
options.experimentalOptions.forEach(this::setExperimentalOption);
}
}

protected void mergeInOptionsFromCaps(String capabilityName, Capabilities capabilities) {
if (!(capabilities instanceof ChromiumOptions)) {
Object object = capabilities.getCapability(capabilityName);

if (object instanceof Map) {
@SuppressWarnings("unchecked") Map<String, Object> options = (Map<String, Object>) object;

@SuppressWarnings("unchecked") List<String>
arguments =
(List<String>) (options.getOrDefault("args", new HashMap<>()));
@SuppressWarnings("unchecked") List<Object> extensionList =
(List<Object>) (options.getOrDefault("extensions", new ArrayList<>()));

arguments.forEach(arg -> {
if (!args.contains(arg)) {
addArguments(arg);
}
});

extensionList.forEach(extension -> {
if (!extensions.contains(extension)) {
if (extension instanceof File) {
addExtensions((File) extension);
} else if (extension instanceof String) {
addEncodedExtensions((String) extension);
}
}
});

Object binary = options.get("binary");
if (binary instanceof String) {
setBinary((String) binary);
} else if (binary instanceof File) {
setBinary((File) binary);
}

options.forEach((k, v) -> {
if (!k.equals("binary") && !k.equals("extensions") && !k.equals("args")) {
setExperimentalOption(k, v);
}
});
}
}
}
}
5 changes: 5 additions & 0 deletions java/src/org/openqa/selenium/edge/EdgeOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import org.openqa.selenium.Capabilities;
import org.openqa.selenium.chromium.ChromiumOptions;
import org.openqa.selenium.internal.Require;
import org.openqa.selenium.remote.CapabilityType;

import static org.openqa.selenium.remote.Browser.EDGE;
Expand Down Expand Up @@ -56,9 +57,13 @@ public EdgeOptions() {

@Override
public EdgeOptions merge(Capabilities extraCapabilities) {
Require.nonNull("Capabilities to merge", extraCapabilities);

EdgeOptions newInstance = new EdgeOptions();
newInstance.mergeInPlace(this);
newInstance.mergeInPlace(extraCapabilities);
newInstance.mergeInOptionsFromCaps(CAPABILITY, extraCapabilities);

return newInstance;
}
}
48 changes: 48 additions & 0 deletions java/src/org/openqa/selenium/firefox/FirefoxOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,55 @@ public FirefoxOptions merge(Capabilities capabilities) {
newInstance.mirror(this);
if (capabilities instanceof FirefoxOptions) {
newInstance.mirror((FirefoxOptions) capabilities);
} else {
Object optionsValue = capabilities.getCapability(FIREFOX_OPTIONS);

if (optionsValue instanceof Map) {
@SuppressWarnings("unchecked") Map<String, Object>
options =
(Map<String, Object>) optionsValue;

@SuppressWarnings("unchecked") List<String> arguments =
(List<String>) (options.getOrDefault("args", new ArrayList<>()));
@SuppressWarnings("unchecked") Map<String, Object> prefs =
(Map<String, Object>) options.getOrDefault("prefs", new HashMap<>());
String rawProfile = (String) options.get("profile");
@SuppressWarnings("unchecked") Map<String, Object> logLevelMap =
(Map<String, Object>) options.getOrDefault("log", new HashMap<>());
FirefoxDriverLogLevel logLevel =
FirefoxDriverLogLevel.fromString((String) logLevelMap.get("level"));

arguments.forEach(arg -> {
if (!((List<String>) newInstance.firefoxOptions.get(Keys.ARGS.key())).contains(arg)) {
newInstance.addArguments(arg);
}
});

Object binary = options.get("binary");
if (binary instanceof String) {
newInstance.setBinary((String) binary);
} else if (binary instanceof Path) {
newInstance.setBinary((Path) binary);
} else if (binary instanceof FirefoxBinary) {
newInstance.setBinary((FirefoxBinary) binary);
}

prefs.forEach(newInstance::addPreference);

if (rawProfile != null) {
try {
newInstance.setProfile(FirefoxProfile.fromJson(rawProfile));
} catch (IOException e) {
throw new WebDriverException(e);
}
}

if (logLevel != null) {
newInstance.setLogLevel(logLevel);
}
}
}

return newInstance;
}

Expand Down
57 changes: 57 additions & 0 deletions java/test/org/openqa/selenium/chrome/ChromeOptionsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Tag;
import org.openqa.selenium.AcceptedW3CCapabilityKeys;
import org.openqa.selenium.MutableCapabilities;
import org.openqa.selenium.PageLoadStrategy;
import org.openqa.selenium.UnexpectedAlertBehaviour;
import org.openqa.selenium.testing.TestUtilities;
Expand All @@ -37,9 +38,11 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.InstanceOfAssertFactories.LIST;
import static org.assertj.core.api.InstanceOfAssertFactories.STRING;
import static org.assertj.core.api.InstanceOfAssertFactories.MAP;
import static org.openqa.selenium.chrome.ChromeDriverLogLevel.OFF;
import static org.openqa.selenium.chrome.ChromeDriverLogLevel.SEVERE;
import static org.openqa.selenium.remote.CapabilityType.ACCEPT_INSECURE_CERTS;
import static org.openqa.selenium.remote.CapabilityType.TIMEOUTS;

@Tag("UnitTests")
Expand Down Expand Up @@ -207,6 +210,60 @@ void mergingOptionsMergesExperimentalOptions() {
.containsEntry("opt3", "val3");
}

@Test
void mergingOptionsWithMutableCapabilities() {
File ext1 = TestUtilities.createTmpFile("ext1");
String ext1Encoded = Base64.getEncoder().encodeToString("ext1".getBytes());
String ext2 = Base64.getEncoder().encodeToString("ext2".getBytes());

MutableCapabilities one = new MutableCapabilities();

ChromeOptions options = new ChromeOptions();
options.addArguments("verbose");
options.addArguments("silent");
options.setExperimentalOption("opt1", "val1");
options.setExperimentalOption("opt2", "val4");
options.addExtensions(ext1);
options.addEncodedExtensions(ext2);
options.setAcceptInsecureCerts(true);
File binary = TestUtilities.createTmpFile("binary");
options.setBinary(binary);

one.setCapability(ChromeOptions.CAPABILITY, options);

ChromeOptions two = new ChromeOptions();
two.addArguments("verbose");
two.setExperimentalOption("opt2", "val2");
two.setExperimentalOption("opt3", "val3");
two = two.merge(one);

Map<String, Object> map = two.asMap();

assertThat(map).asInstanceOf(MAP)
.extractingByKey(ChromeOptions.CAPABILITY).asInstanceOf(MAP)
.extractingByKey("args").asInstanceOf(LIST)
.containsExactly("verbose", "silent");

assertThat(map).asInstanceOf(MAP)
.extractingByKey(ChromeOptions.CAPABILITY).asInstanceOf(MAP)
.containsEntry("opt1", "val1")
.containsEntry("opt2", "val4")
.containsEntry("opt3", "val3");

assertThat(map).asInstanceOf(MAP)
.extractingByKey(ACCEPT_INSECURE_CERTS).isExactlyInstanceOf(Boolean.class);

assertThat(map).asInstanceOf(MAP)
.extractingByKey(ChromeOptions.CAPABILITY).asInstanceOf(MAP)
.extractingByKey("extensions").asInstanceOf(LIST)
.containsExactly(ext1Encoded, ext2);

assertThat(map).asInstanceOf(MAP)
.extractingByKey(ChromeOptions.CAPABILITY).asInstanceOf(MAP)
.extractingByKey("binary").asInstanceOf(STRING)
.isEqualTo(binary.getPath());
}

@Test
void isW3CSafe() {
Map<String, Object> converted = new ChromeOptions()
Expand Down
59 changes: 59 additions & 0 deletions java/test/org/openqa/selenium/edge/EdgeOptionsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Tag;
import org.openqa.selenium.ImmutableCapabilities;
import org.openqa.selenium.MutableCapabilities;
import org.openqa.selenium.PageLoadStrategy;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.testing.TestUtilities;

import java.io.File;
import java.io.IOException;
Expand All @@ -39,7 +41,9 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.InstanceOfAssertFactories.LIST;
import static org.assertj.core.api.InstanceOfAssertFactories.MAP;
import static org.assertj.core.api.InstanceOfAssertFactories.STRING;
import static org.openqa.selenium.remote.Browser.EDGE;
import static org.openqa.selenium.remote.CapabilityType.ACCEPT_INSECURE_CERTS;

@Tag("UnitTests")
class EdgeOptionsTest {
Expand Down Expand Up @@ -88,6 +92,61 @@ void canMergeWithoutChangingOriginalObject() {
assertThat(merged.getCapability(CapabilityType.PAGE_LOAD_STRATEGY)).isEqualTo(PageLoadStrategy.NONE);
}

@Test
void mergingOptionsWithMutableCapabilities() {
File ext1 = TestUtilities.createTmpFile("ext1");
String ext1Encoded = Base64.getEncoder().encodeToString("ext1".getBytes());
String ext2 = Base64.getEncoder().encodeToString("ext2".getBytes());

MutableCapabilities one = new MutableCapabilities();

EdgeOptions options = new EdgeOptions();
options.addArguments("verbose");
options.addArguments("silent");
options.setExperimentalOption("opt1", "val1");
options.setExperimentalOption("opt2", "val4");
options.addExtensions(ext1);
options.addEncodedExtensions(ext2);
options.setAcceptInsecureCerts(true);
File binary = TestUtilities.createTmpFile("binary");
options.setBinary(binary);

one.setCapability(EdgeOptions.CAPABILITY, options);

EdgeOptions two = new EdgeOptions();
two.addArguments("verbose");
two.setExperimentalOption("opt2", "val2");
two.setExperimentalOption("opt3", "val3");

two = two.merge(one);

Map<String, Object> map = two.asMap();

assertThat(map).asInstanceOf(MAP)
.extractingByKey(EdgeOptions.CAPABILITY).asInstanceOf(MAP)
.extractingByKey("args").asInstanceOf(LIST)
.containsExactly("verbose", "silent");

assertThat(map).asInstanceOf(MAP)
.extractingByKey(EdgeOptions.CAPABILITY).asInstanceOf(MAP)
.containsEntry("opt1", "val1")
.containsEntry("opt2", "val4")
.containsEntry("opt3", "val3");

assertThat(map).asInstanceOf(MAP)
.extractingByKey(ACCEPT_INSECURE_CERTS).isExactlyInstanceOf(Boolean.class);

assertThat(map).asInstanceOf(MAP)
.extractingByKey(EdgeOptions.CAPABILITY).asInstanceOf(MAP)
.extractingByKey("extensions").asInstanceOf(LIST)
.containsExactly(ext1Encoded, ext2);

assertThat(map).asInstanceOf(MAP)
.extractingByKey(EdgeOptions.CAPABILITY).asInstanceOf(MAP)
.extractingByKey("binary").asInstanceOf(STRING)
.isEqualTo(binary.getPath());
}

private void checkCommonStructure(EdgeOptions options) {
assertThat(options.asMap())
.containsEntry(CapabilityType.BROWSER_NAME, EDGE.browserName())
Expand Down
64 changes: 64 additions & 0 deletions java/test/org/openqa/selenium/firefox/FirefoxOptionsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import static org.assertj.core.api.Assumptions.assumeThat;
import static org.assertj.core.api.InstanceOfAssertFactories.LIST;
import static org.assertj.core.api.InstanceOfAssertFactories.MAP;
import static org.assertj.core.api.InstanceOfAssertFactories.STRING;
import static org.openqa.selenium.PageLoadStrategy.EAGER;
import static org.openqa.selenium.firefox.FirefoxDriver.SystemProperty.BROWSER_BINARY;
import static org.openqa.selenium.firefox.FirefoxDriver.SystemProperty.BROWSER_PROFILE;
Expand Down Expand Up @@ -375,6 +376,69 @@ void mergingOptionsMergesPreferences() {
.containsEntry("opt3", "val3");
}

@Test
void mergingOptionsWithMutableCapabilities() {
MutableCapabilities one = new MutableCapabilities();

FirefoxOptions options = new FirefoxOptions();
options.addArguments("verbose");
options.addArguments("silent");
options.addPreference("opt1", "val1");
options.addPreference("opt2", "val4");
options.setAcceptInsecureCerts(true);

String key = "browser.startup.homepage";
String value = "about:robots";

FirefoxProfile profile = new FirefoxProfile();
profile.setPreference(key, value);

options.setProfile(profile);

options.setLogLevel(DEBUG);

File binary = TestUtilities.createTmpFile("binary");
options.setBinary(binary.toPath());

one.setCapability(FIREFOX_OPTIONS, options);

FirefoxOptions two = new FirefoxOptions();
two.addArguments("verbose");
two.addPreference("opt2", "val2");
two.addPreference("opt3", "val3");
two = two.merge(one);

Map<String, Object> map = two.asMap();

assertThat(map).asInstanceOf(MAP)
.extractingByKey(FIREFOX_OPTIONS).asInstanceOf(MAP)
.extractingByKey("args").asInstanceOf(LIST)
.containsExactly("verbose", "silent");

assertThat(map).asInstanceOf(MAP)
.extractingByKey(FIREFOX_OPTIONS).asInstanceOf(MAP)
.extractingByKey("prefs").asInstanceOf(MAP)
.containsEntry("opt1", "val1")
.containsEntry("opt2", "val4")
.containsEntry("opt3", "val3");

assertThat(map).asInstanceOf(MAP)
.extractingByKey(ACCEPT_INSECURE_CERTS).isExactlyInstanceOf(Boolean.class);

assertThat(map).asInstanceOf(MAP)
.extractingByKey(FIREFOX_OPTIONS).asInstanceOf(MAP)
.extractingByKey("binary").asInstanceOf(STRING)
.isEqualTo(binary.getPath());

assertThat(map).asInstanceOf(MAP)
.extractingByKey(FIREFOX_OPTIONS).asInstanceOf(MAP)
.extractingByKey("log").asInstanceOf(MAP)
.containsEntry("level", "debug");

FirefoxProfile extractedProfile = two.getProfile();
assertThat(extractedProfile.getStringPreference(key, "-")).isEqualTo(value);
}

@Test
void firefoxOptionsShouldEqualEquivalentImmutableCapabilities() {
FirefoxOptions
Expand Down

0 comments on commit 955581f

Please sign in to comment.