Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions docs-site/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -297,3 +297,21 @@ mvn test -Dselenium.boot.profile=staging
```

Only the fields present in the profile file are overridden — everything else falls back to the base config.

---

## Switching browser from the command line

Pick the browser for a single run without editing any file:

```bash
mvn test -Dbrowser=firefox
```

`-Dselenium.boot.browser=firefox` does the same and wins if both are set. The value replaces
`browser.name` from `selenium-boot.yml`, any profile, and `SeleniumBootDefaults`. It also
replaces `browser.matrix`: asking for one browser runs only that browser. Values are
case-insensitive; a blank value is ignored.

Gradle runs tests in a separate JVM, so forward the property in `build.gradle`. See
[Gradle setup](./gradle).
23 changes: 13 additions & 10 deletions docs-site/docs/gradle.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ test {
// suites 'src/test/resources/testng.xml'
}

// Forward -Denv=staging from the CLI. Forward only the keys you use:
// Forward -Denv / -Dbrowser / -Dselenium.boot.profile from the CLI. Forward only the keys you use:
// copying every JVM property (java.home, ...) breaks the run if the test JVM differs from Gradle's
['env'].each { k -> System.getProperty(k)?.with { systemProperty k, it } }
['env', 'browser', 'selenium.boot.profile'].each { k -> System.getProperty(k)?.with { systemProperty k, it } }

// Display test output in the console
testLogging {
Expand All @@ -91,9 +91,9 @@ tasks.test {
// suites("src/test/resources/testng.xml")
}

// Forward -Denv=staging from the CLI. Forward only the keys you use:
// Forward -Denv / -Dbrowser / -Dselenium.boot.profile from the CLI. Forward only the keys you use:
// copying every JVM property (java.home, ...) breaks the run if the test JVM differs from Gradle's
listOf("env").forEach { k -> System.getProperty(k)?.let { systemProperty(k, it) } }
listOf("env", "browser", "selenium.boot.profile").forEach { k -> System.getProperty(k)?.let { systemProperty(k, it) } }

testLogging {
events("passed", "skipped", "failed")
Expand Down Expand Up @@ -121,7 +121,7 @@ dependencies {

test {
useJUnitPlatform()
['env'].each { k -> System.getProperty(k)?.with { systemProperty k, it } }
['env', 'browser', 'selenium.boot.profile'].each { k -> System.getProperty(k)?.with { systemProperty k, it } }
}
```

Expand All @@ -137,7 +137,7 @@ dependencies {

tasks.test {
useJUnitPlatform()
listOf("env").forEach { k -> System.getProperty(k)?.let { systemProperty(k, it) } }
listOf("env", "browser", "selenium.boot.profile").forEach { k -> System.getProperty(k)?.let { systemProperty(k, it) } }
}
```

Expand Down Expand Up @@ -183,7 +183,10 @@ retry:
# Run with an environment profile
./gradlew test -Denv=staging

# Pass multiple JVM args
# Switch browser for one run (overrides browser.name and browser.matrix)
./gradlew test -Dbrowser=firefox

# Use a config profile
./gradlew test -Dselenium.boot.profile=firefox # reads selenium-boot-firefox.yml
```

Expand Down Expand Up @@ -215,7 +218,7 @@ For parallel runs with Gradle, configure the `test` task alongside `selenium-boo
test {
useTestNG()
maxParallelForks = 4 // Gradle worker processes
['env'].each { k -> System.getProperty(k)?.with { systemProperty k, it } }
['env', 'browser', 'selenium.boot.profile'].each { k -> System.getProperty(k)?.with { systemProperty k, it } }
}
```

Expand All @@ -226,7 +229,7 @@ test {
tasks.test {
useTestNG()
maxParallelForks = 4
listOf("env").forEach { k -> System.getProperty(k)?.let { systemProperty(k, it) } }
listOf("env", "browser", "selenium.boot.profile").forEach { k -> System.getProperty(k)?.let { systemProperty(k, it) } }
}
```

Expand Down Expand Up @@ -283,7 +286,7 @@ dependencies {

test {
useTestNG()
['env'].each { k -> System.getProperty(k)?.with { systemProperty k, it } }
['env', 'browser', 'selenium.boot.profile'].each { k -> System.getProperty(k)?.with { systemProperty k, it } }
testLogging { events 'passed', 'skipped', 'failed' }
}
```
Expand Down
23 changes: 23 additions & 0 deletions src/main/java/com/seleniumboot/config/ConfigurationLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.Locale;
import java.util.Objects;

import org.yaml.snakeyaml.LoaderOptions;
Expand Down Expand Up @@ -117,10 +119,31 @@ private static void completeAndValidate(SeleniumBootConfig config) {
// Programmatic defaults (SeleniumBootDefaults) take precedence over the built-in ones.
SeleniumBootDefaults.applyMissing(config);
applyBuiltInDefaults(config);
applyBrowserOverride(config);

validate(config);
}

/**
* Command-line browser override: {@code -Dselenium.boot.browser=firefox}, or the shorter
* {@code -Dbrowser=firefox} (the namespaced key wins when both are set). It beats
* {@code browser.name} from the file, profiles and {@link SeleniumBootDefaults}, and it
* replaces {@code browser.matrix} — asking for one browser must not still fan out to several.
* A blank value is ignored.
*/
private static void applyBrowserOverride(SeleniumBootConfig config) {
String override = System.getProperty("selenium.boot.browser");
if (override == null || override.isBlank()) {
override = System.getProperty("browser");
}
if (override == null || override.isBlank()) {
return;
}
SeleniumBootConfig.Browser browser = config.getBrowser();
browser.setName(override.trim().toLowerCase(Locale.ROOT));
browser.setMatrix(Collections.emptyList());
}

/**
* Fills fields the file left out. Only <em>absent</em> values are defaulted:
* {@code browser.name} (unless {@code browser.matrix} is set), {@code execution.mode},
Expand Down
68 changes: 68 additions & 0 deletions src/test/java/com/seleniumboot/unit/ConfigurationLoaderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,16 @@ public class ConfigurationLoaderTest {
public void clearSystemProperties() {
System.clearProperty("selenium.boot.config");
System.clearProperty("selenium.boot.profile");
System.clearProperty("browser");
System.clearProperty("selenium.boot.browser");
}

@AfterMethod
public void restoreSystemProperties() {
System.clearProperty("selenium.boot.config");
System.clearProperty("selenium.boot.profile");
System.clearProperty("browser");
System.clearProperty("selenium.boot.browser");
}

// ----------------------------------------------------------
Expand Down Expand Up @@ -204,4 +208,68 @@ public void load_negativeTimeoutStillRejected() throws IOException {
System.setProperty("selenium.boot.config", file.toString());
ConfigurationLoader.load();
}

// ----------------------------------------------------------
// -Dbrowser / -Dselenium.boot.browser override
// ----------------------------------------------------------

private static Path configFile(String yaml) throws IOException {
Path file = Files.createTempFile("sb-browser", ".yml");
Files.writeString(file, yaml);
System.setProperty("selenium.boot.config", file.toString());
return file;
}

@Test
public void load_browserSystemProperty_overridesYamlName() throws IOException {
configFile("browser:\n name: chrome\n");
System.setProperty("browser", "firefox");

assertEquals(ConfigurationLoader.load().getBrowser().getName(), "firefox");
}

@Test
public void load_browserSystemProperty_overridesBuiltInDefaultWithoutAFile() throws IOException {
System.setProperty("browser", "edge");

SeleniumBootConfig config = ConfigurationLoader.load(emptyWorkingDir(), emptyClasspath());

assertEquals(config.getBrowser().getName(), "edge");
}

@Test
public void load_browserSystemProperty_replacesTheMatrix() throws IOException {
configFile("browser:\n matrix: [chrome, firefox]\n");
System.setProperty("browser", "firefox");

SeleniumBootConfig config = ConfigurationLoader.load();

assertEquals(config.getBrowser().getName(), "firefox");
assertTrue(config.getBrowser().getMatrix().isEmpty(), "a single-browser override must not still fan out");
}

@Test
public void load_namespacedBrowserProperty_winsOverPlainBrowser() throws IOException {
configFile("browser:\n name: chrome\n");
System.setProperty("browser", "edge");
System.setProperty("selenium.boot.browser", "firefox");

assertEquals(ConfigurationLoader.load().getBrowser().getName(), "firefox");
}

@Test
public void load_blankBrowserProperty_isIgnored() throws IOException {
configFile("browser:\n name: firefox\n");
System.setProperty("browser", " ");

assertEquals(ConfigurationLoader.load().getBrowser().getName(), "firefox");
}

@Test
public void load_browserPropertyValue_isTrimmedAndLowerCased() throws IOException {
configFile("browser:\n name: chrome\n");
System.setProperty("browser", " Firefox ");

assertEquals(ConfigurationLoader.load().getBrowser().getName(), "firefox");
}
}
Loading