Skip to content
Open
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
6 changes: 5 additions & 1 deletion java/src/org/openqa/selenium/By.java
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,11 @@ public final Parameters getRemoteParameters() {

private String cssEscape(String using) {
using = CSS_ESCAPE.matcher(using).replaceAll("\\\\$1");
if (!using.isEmpty() && Character.isDigit(using.charAt(0))) {
// CSS only requires the leading-digit escape for ASCII 0-9; non-ASCII Unicode digits
// (e.g. Arabic-Indic, fullwidth) are already valid identifier-start code points and must
// be left untouched, or they collide with the escape for a different ASCII digit.
char first = using.isEmpty() ? '\0' : using.charAt(0);
if (first >= '0' && first <= '9') {
using = "\\" + (30 + Integer.parseInt(using.substring(0, 1))) + " " + using.substring(1);
}
return using;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,11 @@ private Map<String, String> asElement(Object id) {

private String cssEscape(String using) {
using = CSS_ESCAPE.matcher(using).replaceAll("\\\\$1");
if (!using.isEmpty() && Character.isDigit(using.charAt(0))) {
// CSS only requires the leading-digit escape for ASCII 0-9; non-ASCII Unicode digits
// (e.g. Arabic-Indic, fullwidth) are already valid identifier-start code points and must
// be left untouched, or they collide with the escape for a different ASCII digit.
char first = using.isEmpty() ? '\0' : using.charAt(0);
if (first >= '0' && first <= '9') {
using = "\\" + (30 + Integer.parseInt(using.substring(0, 1))) + " " + using.substring(1);
}
return using;
Expand Down
26 changes: 26 additions & 0 deletions java/test/org/openqa/selenium/ByTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,30 @@ void ensureIdIsSerializedProperly() {
.containsEntry("using", "css selector")
.containsEntry("value", "#one\\ two");
}

@Test
void ensureLeadingAsciiDigitIsEscapedAsCodePoint() {
By by = By.className("5foo");

Json json = new Json();
Map<String, Object> blob = json.toType(json.toJson(by), MAP_TYPE);

assertThat(blob).containsEntry("using", "css selector").containsEntry("value", ".\\35 foo");
}

@Test
void ensureLeadingNonAsciiDigitIsNotMisescapedAsADifferentAsciiDigit() {
// U+0665 (Arabic-Indic digit five) has numeric value 5, but is not an ASCII digit.
// It is already a valid CSS identifier-start code point and must be passed through as-is,
// rather than being (mis)escaped to the same selector as an ASCII '5'.
By arabicIndicFive = By.className("Ω₯foo");
By asciiFive = By.className("5foo");

Json json = new Json();
Map<String, Object> arabicBlob = json.toType(json.toJson(arabicIndicFive), MAP_TYPE);
Map<String, Object> asciiBlob = json.toType(json.toJson(asciiFive), MAP_TYPE);

assertThat(arabicBlob).containsEntry("using", "css selector").containsEntry("value", ".Ω₯foo");
assertThat(arabicBlob.get("value")).isNotEqualTo(asciiBlob.get("value"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package org.openqa.selenium.remote.codec.w3c;

import static org.assertj.core.api.Assertions.assertThat;
import static org.openqa.selenium.json.Json.MAP_TYPE;
import static org.openqa.selenium.remote.http.Contents.string;

import java.util.Map;
import java.util.UUID;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.json.Json;
import org.openqa.selenium.remote.Command;
import org.openqa.selenium.remote.DriverCommand;
import org.openqa.selenium.remote.SessionId;
import org.openqa.selenium.remote.http.HttpRequest;

@Tag("UnitTests")
class W3CHttpCommandCodecTest {

private final W3CHttpCommandCodec codec = new W3CHttpCommandCodec();
private final SessionId sessionId = new SessionId(UUID.randomUUID());
private final Json json = new Json();

@Test
void ensureLeadingAsciiDigitClassNameIsEscapedAsCodePoint() {
Map<String, Object> params = encodeFindElement("class name", "5foo");

assertThat(params).containsEntry("using", "css selector").containsEntry("value", ".\\35 foo");
}

@Test
void ensureLeadingAsciiDigitIdIsEscapedAsCodePoint() {
Map<String, Object> params = encodeFindElement("id", "5foo");

assertThat(params).containsEntry("using", "css selector").containsEntry("value", "#\\35 foo");
}

@Test
void ensureLeadingNonAsciiDigitClassNameIsNotMisescapedAsADifferentAsciiDigit() {
// U+0665 (Arabic-Indic digit five) has numeric value 5, but is not an ASCII digit.
// It must be passed through as-is, not (mis)escaped to the same selector as an ASCII '5'.
Map<String, Object> arabicIndicFive = encodeFindElement("class name", "Ω₯foo");
Map<String, Object> asciiFive = encodeFindElement("class name", "5foo");

assertThat(arabicIndicFive)
.containsEntry("using", "css selector")
.containsEntry("value", ".Ω₯foo");
assertThat(arabicIndicFive.get("value")).isNotEqualTo(asciiFive.get("value"));
Comment on lines +56 to +65

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

1. Non-ascii source literal 🐞 Bug ☼ Reliability

W3CHttpCommandCodecTest embeds the Arabic-Indic digit Ω₯ directly in Java string literals; if the
compiler reads sources using a non-UTF-8 default encoding, this file may fail to compile or the
literal may be decoded incorrectly. Using \u0665 escapes makes the test encoding-agnostic and
aligns with existing test patterns in the repo.
Agent Prompt
### Issue description
`W3CHttpCommandCodecTest` contains raw non-ASCII characters (`Ω₯`) in Java string literals. If source encoding is not consistently UTF-8, this can break compilation or alter the test input.

### Issue Context
The Bazel Java wrapper in this repo does not obviously enforce a `-encoding` flag, and other tests use `\uXXXX` escapes for non-ASCII strings.

### Fix Focus Areas
- java/test/org/openqa/selenium/remote/codec/w3c/W3CHttpCommandCodecTest.java[56-65]

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

}

private Map<String, Object> encodeFindElement(String strategy, Object value) {
HttpRequest request =
codec.encode(new Command(sessionId, DriverCommand.FIND_ELEMENT(strategy, value)));
return json.toType(string(request), MAP_TYPE);
}
Comment on lines +68 to +72

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.

Informational

2. Deprecated string helper used 🐞 Bug βš™ Maintainability

The new test calls deprecated Contents.string(HttpMessage) to read the request body, which adds
avoidable deprecation usage and future maintenance risk. HttpRequest already exposes
contentAsString(), so the test can parse the JSON body without the deprecated helper.
Agent Prompt
### Issue description
`W3CHttpCommandCodecTest` uses deprecated `Contents.string(HttpMessage)`.

### Issue Context
`Contents.string(HttpMessage<?>)` is annotated `@Deprecated` and explicitly recommends using `HttpMessage#contentAsString()`.

### Fix Focus Areas
- java/test/org/openqa/selenium/remote/codec/w3c/W3CHttpCommandCodecTest.java[20-23]
- java/test/org/openqa/selenium/remote/codec/w3c/W3CHttpCommandCodecTest.java[68-72]

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

}