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
88 changes: 38 additions & 50 deletions .github/workflows/java-examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,62 +62,50 @@ jobs:
run: keytool -import -noprompt -trustcacerts -alias SeleniumHQ -file examples/java/src/test/resources/tls.crt -keystore ${{ steps.java.outputs.path }}/lib/security/cacerts -storepass changeit
- name: Run Tests Stable (in Maven)
if: matrix.release == 'stable'
uses: nick-invision/retry@v4.0.0
with:
timeout_minutes: 40
max_attempts: 3
command: |
cd examples/java
mvn -B test -D"jdk.internal.httpclient.disableHostnameVerification=true"
timeout-minutes: 40
run: |
cd examples/java
mvn -B test -D"jdk.internal.httpclient.disableHostnameVerification=true"
Comment on lines +65 to +68

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Documentation fix carries test tuning 📘 Rule violation ⚙ Maintainability

java-examples.yml removes the retry action, while LoggingTest.cs lengthens an event wait and
LogTest.java changes a browser stack-frame assertion. These CI and test-stability edits do not
restore translated pages or adjust their front matter and links, so they broaden this documentation
PR into independently reviewable behavior changes.
Agent Prompt
## Issue description
The PR includes CI retry changes and test-stability adjustments that are unrelated to restoring translated documentation pages.

## Fix Focus Areas
- .github/workflows/java-examples.yml[65-108]
- examples/dotnet/SeleniumDocs/BiDi/CDP/LoggingTest.cs[29-29]
- examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/LogTest.java[100-100]

## Recommended Fix
Remove these workflow and test changes from this documentation PR and submit them as one or more separately scoped PRs.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

- name: Run Tests Stable (in Gradle)
if: matrix.release == 'stable'
uses: nick-invision/retry@v4.0.0
with:
timeout_minutes: 40
max_attempts: 3
command: |
cd examples/java
./gradlew test --tests 'dev.selenium.*UsingSeleniumTest'
timeout-minutes: 40
run: |
cd examples/java
./gradlew test --tests 'dev.selenium.*UsingSeleniumTest'
- name: Run Tests Nightly Linux/macOS
if: matrix.release == 'nightly' && matrix.os != 'windows'
uses: nick-invision/retry@v4.0.0
with:
timeout_minutes: 40
max_attempts: 3
command: |
# Get current selenium.version from Maven
current_version=$(mvn -f examples/java/pom.xml help:evaluate -Dexpression=selenium.version -q -DforceStdout)
echo "Current selenium.version: $current_version"
# If version is in the form X.Y.Z, bump minor and set to SNAPSHOT
if [[ $current_version =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
major="${BASH_REMATCH[1]}"
minor="${BASH_REMATCH[2]}"
next_minor=$((minor + 1))
new_version="$major.$next_minor.0-SNAPSHOT"
echo "Using selenium.version $new_version for tests"
cd examples/java
mvn -B -U test -D"jdk.internal.httpclient.disableHostnameVerification=true" -Dselenium.version=$new_version
fi
timeout-minutes: 40
run: |
# Get current selenium.version from Maven
current_version=$(mvn -f examples/java/pom.xml help:evaluate -Dexpression=selenium.version -q -DforceStdout)
echo "Current selenium.version: $current_version"
# If version is in the form X.Y.Z, bump minor and set to SNAPSHOT
if [[ $current_version =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
major="${BASH_REMATCH[1]}"
minor="${BASH_REMATCH[2]}"
next_minor=$((minor + 1))
new_version="$major.$next_minor.0-SNAPSHOT"
echo "Using selenium.version $new_version for tests"
cd examples/java
mvn -B -U test -D"jdk.internal.httpclient.disableHostnameVerification=true" -Dselenium.version=$new_version
fi
- name: Run Tests Nightly Windows
if: matrix.release == 'nightly' && matrix.os == 'windows'
uses: nick-invision/retry@v4.0.0
with:
timeout_minutes: 40
max_attempts: 3
command: |
# Get current selenium.version from Maven
$current_version = & mvn -f examples/java/pom.xml help:evaluate "-Dexpression=selenium.version" -q "-DforceStdout"
Write-Output "Current selenium.version: $current_version"
# If version is in the form X.Y.Z, bump minor and set to SNAPSHOT
if ($current_version -match '^([0-9]+)\.([0-9]+)\.([0-9]+)$') {
$major = $matches[1]
$minor = $matches[2]
$next_minor = [int]$minor + 1
$new_version = "$major.$next_minor.0-SNAPSHOT"
Write-Output "Using selenium.version $new_version for tests"
cd examples/java
mvn -B -U test "-Djdk.internal.httpclient.disableHostnameVerification=true" "-Dselenium.version=$new_version"
}
timeout-minutes: 40
run: |
# Get current selenium.version from Maven
$current_version = & mvn -f examples/java/pom.xml help:evaluate "-Dexpression=selenium.version" -q "-DforceStdout"
Write-Output "Current selenium.version: $current_version"
# If version is in the form X.Y.Z, bump minor and set to SNAPSHOT
if ($current_version -match '^([0-9]+)\.([0-9]+)\.([0-9]+)$') {
$major = $matches[1]
$minor = $matches[2]
$next_minor = [int]$minor + 1
$new_version = "$major.$next_minor.0-SNAPSHOT"
Write-Output "Using selenium.version $new_version for tests"
cd examples/java
mvn -B -U test "-Djdk.internal.httpclient.disableHostnameVerification=true" "-Dselenium.version=$new_version"
}
- name: Upload test report
uses: actions/upload-artifact@v7
if: failure()
Expand Down
2 changes: 1 addition & 1 deletion examples/dotnet/SeleniumDocs/BiDi/CDP/LoggingTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public async Task ConsoleLogs()

driver.FindElement(By.Id("consoleLog")).Click();
driver.FindElement(By.Id("consoleError")).Click();
new WebDriverWait(driver, TimeSpan.FromSeconds(5)).Until(_ => messages.Count > 1);
new WebDriverWait(driver, TimeSpan.FromSeconds(10)).Until(_ => messages.Count > 1);
monitor.StopEventMonitoring();

Assert.IsTrue(messages.Contains("Hello, world!"));
Expand Down
14 changes: 14 additions & 0 deletions examples/dotnet/SeleniumDocs/Drivers/OptionsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,19 @@ public void SetUnhandledPromptBehavior()
driver.Quit();
}
}
[TestMethod]
public void SetsProxy()
{
ChromeOptions options = new ChromeOptions();
Proxy proxy = new Proxy();
proxy.Kind = ProxyKind.Manual;
proxy.IsAutoDetect = false;
proxy.SslProxy = "myproxy.com:8080";
options.Proxy = proxy;
options.AddArgument("ignore-certificate-errors");

Assert.IsNotNull(options.Proxy);
Assert.AreEqual("myproxy.com:8080", options.Proxy.SslProxy);
}
}
}
2 changes: 1 addition & 1 deletion examples/java/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ repositories {
mavenCentral()
}

ext['seleniumVersion'] = System.getProperty('selenium.version', '4.47.0')
ext['seleniumVersion'] = System.getProperty('selenium.version', '4.49.0')
Comment thread
diemol marked this conversation as resolved.
Resolved

dependencies {
testImplementation "org.seleniumhq.selenium:selenium-java:${seleniumVersion}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ void testRetrieveStacktraceForALog()

StackTrace stackTrace = logEntry.getStackTrace();
Assertions.assertNotNull(stackTrace);
Assertions.assertEquals(4, stackTrace.getCallFrames().size());
Assertions.assertEquals(3, stackTrace.getCallFrames().size());
}
}

Expand Down
13 changes: 13 additions & 0 deletions examples/java/src/test/java/dev/selenium/drivers/OptionsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Assertions;
import org.openqa.selenium.PageLoadStrategy;
import org.openqa.selenium.Proxy;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Driver option snippets show wrong lines 📘 Rule violation ≡ Correctness

The new Proxy import at line 11 of OptionsTest.java shifts every existing example below the
imports without adjusting its established gh-codeblock ranges. The driver index and options pages
in English, Japanese, Portuguese, and Chinese therefore select neighboring lines for their
pre-existing Java samples whenever Hugo renders them.
Agent Prompt
## Issue description
Adding the `Proxy` import shifted the existing Java options examples by one line, but the established `gh-codeblock` ranges still use their old line numbers.

## Fix Focus Areas
- examples/java/src/test/java/dev/selenium/drivers/OptionsTest.java[11-11]
- website_and_docs/content/documentation/webdriver/drivers/_index.en.md[32-32]
- website_and_docs/content/documentation/webdriver/drivers/_index.ja.md[29-29]
- website_and_docs/content/documentation/webdriver/drivers/_index.pt-br.md[30-30]
- website_and_docs/content/documentation/webdriver/drivers/_index.zh-cn.md[30-30]
- website_and_docs/content/documentation/webdriver/drivers/options.en.md[64-495]
- website_and_docs/content/documentation/webdriver/drivers/options.ja.md[31-440]
- website_and_docs/content/documentation/webdriver/drivers/options.pt-br.md[43-476]
- website_and_docs/content/documentation/webdriver/drivers/options.zh-cn.md[34-467]

## Recommended Fix
Increment by one every existing Java `OptionsTest.java` line reference affected by the new import, while retaining the newly added proxy references that already target lines 176-180. Verify each resulting range selects the same statements it selected before the import was added.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

import org.openqa.selenium.UnexpectedAlertBehaviour;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeOptions;
Expand Down Expand Up @@ -169,5 +170,17 @@ public void setStrictFileInteractability() {
Boolean capability = (Boolean) capabilityObject;
Assertions.assertTrue(capability, "The capability STRICT_FILE_INTERACTABILITY should be set to true.");
}

@Test
public void setsProxy() {
Proxy proxy = new Proxy();
proxy.setHttpProxy("myproxy.com:8080");
ChromeOptions options = getDefaultChromeOptions();
options.setCapability("proxy", proxy);

Object capabilityObject = options.getCapability("proxy");
Assertions.assertNotNull(capabilityObject, "Capability proxy should not be null.");
Assertions.assertEquals("myproxy.com:8080", ((Proxy) capabilityObject).getHttpProxy());
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package dev.selenium.grid;

import dev.selenium.BaseTest;
import java.net.URL;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.RemoteWebDriver;

public class GettingStartedTest extends BaseTest {

@Test
public void addsMetadataToASession() throws Exception {
URL gridUrl = startStandaloneGrid();

ChromeOptions chromeOptions = getDefaultChromeOptions();
// Showing a test name instead of the session id in the Grid UI
chromeOptions.setCapability("se:name", "My simple test");
// Other type of metadata can be seen in the Grid UI by clicking on the
// session info or via GraphQL
chromeOptions.setCapability("se:sampleMetadata", "Sample metadata value");
WebDriver driver = new RemoteWebDriver(gridUrl, chromeOptions);
this.driver = driver;
driver.get("https://www.selenium.dev");
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,29 @@
package dev.selenium.support;

import dev.selenium.BaseTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ThreadGuard;

public class ThreadGuardTest extends BaseTest {

@Test
public void protectsDriverFromCrossThreadUse() throws InterruptedException {
WebDriver protectedDriver = ThreadGuard.protect(startChromeDriver());

Throwable[] caughtOnOtherThread = new Throwable[1];
Runnable callFromOtherThread = () -> {
try {
protectedDriver.get("https://www.selenium.dev");
} catch (Throwable t) {
caughtOnOtherThread[0] = t;
}
};
Thread otherThread = new Thread(callFromOtherThread);
otherThread.start();
otherThread.join();

Assertions.assertNotNull(caughtOnOtherThread[0]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

10. Unrelated failures pass guard tests 🐞 Bug ≡ Correctness

protectsDriverFromCrossThreadUse considers any captured Throwable sufficient instead of
verifying ThreadGuard's expected thread-safety exception. If cross-thread protection regresses while
navigation fails for an unrelated browser, network, or JVM reason, this test still passes.
Agent Prompt
## Issue description
The new ThreadGuard regression test passes for any throwable from the worker thread, so unrelated failures can masquerade as successful cross-thread protection.

## Fix Focus Areas
- examples/java/src/test/java/dev/selenium/support/ThreadGuardTest.java[15-27]

## Recommended Fix
Capture the worker's throwable and assert that it is a `WebDriverException` containing the expected ThreadGuard thread-safety message, rather than only asserting that some throwable exists.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package dev.selenium.test_practices;

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.PageFactory;

class AccountPage {
}

class LoginPage {
private final WebDriver driver;

public LoginPage(WebDriver driver) {
this.driver = driver;
}

/**
* Takes a username and password, fills out the fields, and clicks "login".
*
* @return An instance of the AccountPage
*/
public AccountPage loginAsUser(String username, String password) {
WebElement loginField = driver.findElement(By.id("loginField"));
loginField.clear();
loginField.sendKeys(username);

// Fill out the password field. The locator we're using is "By.id", and we should
// have it defined elsewhere in the class.
WebElement passwordField = driver.findElement(By.id("password"));
passwordField.clear();
passwordField.sendKeys(password);

// Click the login button, which happens to have the id "submit".
driver.findElement(By.id("submit")).click();

// Create and return a new instance of the AccountPage (via the built-in Selenium
// PageFactory).
return PageFactory.initElements(driver, AccountPage.class);
}
}

public class DomainSpecificLanguageExample {

@Test
@Disabled("Illustrative only: LoginPage targets a fictional application, not a live site")
void loginAsUserAbstractsTheLoginFormFromTheTest() {
WebDriver driver = new ChromeDriver();
try {
LoginPage loginPage = new LoginPage(driver);
loginPage.loginAsUser("cbrown", "cl0wn3");
} finally {
driver.quit();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package dev.selenium.test_practices;

import java.time.Duration;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.WebDriverWait;

abstract class BasePage {
protected WebDriver driver;

public BasePage(WebDriver driver) {
this.driver = driver;
}
}

class GoogleSearchPage extends BasePage {
public GoogleSearchPage(WebDriver driver) {
super(driver);
// Generally do not assert within pages or components.
// Effectively throws an exception if the lambda condition is not met.
new WebDriverWait(driver, Duration.ofSeconds(3)).until(d -> d.findElement(By.id("logo")));
}

public GoogleSearchPage setSearchString(String sstr) {
driver.findElement(By.id("gbqfq")).sendKeys(sstr);
return this;
}

public void clickSearchButton() {
driver.findElement(By.id("gbqfb")).click();
}
}

public class FluentApiExample {

@Test
@Disabled("Illustrative only: targets Google's live, frequently changing search page markup")
void queryTheGoogleSearchPageUsingAFluentApi() {
WebDriver driver = new ChromeDriver();
try {
driver.get("http://www.google.com/webhp?hl=en&tab=ww");
GoogleSearchPage gsp = new GoogleSearchPage(driver);
gsp.setSearchString("cheese").clickSearchButton();
} finally {
driver.quit();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package dev.selenium.test_practices;

import dev.selenium.BaseTest;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;

public class FreshBrowserPerTestTest extends BaseTest {

@Test
public void startsAFreshBrowserForTheTest() {
WebDriver driver = new FirefoxDriver();
this.driver = driver;
}
}
14 changes: 14 additions & 0 deletions examples/javascript/test/drivers/options.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const chrome = require('selenium-webdriver/chrome')
const proxy = require('selenium-webdriver/proxy')
const assert = require('node:assert')

describe('Options Test', function () {
it('Sets proxy', function () {
const options = new chrome.Options()
options.setProxy(proxy.manual({ http: 'myproxy.com:8080' }))

const capability = options.getProxy()
assert.notStrictEqual(capability, undefined)
assert.strictEqual(capability.httpProxy, 'myproxy.com:8080')
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package dev.selenium.drivers

import dev.selenium.BaseTest
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
import org.openqa.selenium.Proxy
import org.openqa.selenium.chrome.ChromeOptions

class OptionsTest : BaseTest() {

@Test
fun setsProxy() {
val proxy = Proxy()
proxy.setHttpProxy("myproxy.com:8080")
val options = ChromeOptions()
options.setCapability("proxy", proxy)

val capabilityObject = options.getCapability("proxy") as Proxy
Assertions.assertNotNull(capabilityObject)
Assertions.assertEquals("myproxy.com:8080", capabilityObject.httpProxy)
}
}
Loading
Loading