Skip to content

Commit 4668df3

Browse files
sbabcocshs96c
andauthored
Add JSON serialization for ShadowRoot (#13680)
* Add JSON serialization for ShadowRoot * Run format script * Disable SpotBugs check for pass-thru subclass * Fix up spotbugs errors --------- Co-authored-by: Simon Mavi Stewart <[email protected]>
1 parent cdd05e0 commit 4668df3

File tree

10 files changed

+135
-95
lines changed

10 files changed

+135
-95
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,4 @@ bazel-testlogs
136136
javascript/node/selenium-webdriver/.vscode/settings.json
137137

138138
dotnet-bin
139+
.metadata/

java/spotbugs-excludes.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,4 +194,14 @@
194194
<Class name="org.openqa.selenium.testing.StaticResources"/>
195195
<Bug pattern="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE"/>
196196
</Match>
197+
198+
<Match>
199+
<Class name="org.openqa.selenium.remote.WebElementToJsonConverter" />
200+
<Bug pattern="NM_SAME_SIMPLE_NAME_AS_INTERFACE" />
201+
</Match>
202+
203+
<Match>
204+
<Class name="org.openqa.selenium.remote.internal.WebElementToJsonConverter" />
205+
<Bug pattern="NM_SAME_SIMPLE_NAME_AS_SUPERCLASS" />
206+
</Match>
197207
</FindBugsFilter>

java/src/org/openqa/selenium/remote/RemoteWebDriver.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@
8989
import org.openqa.selenium.remote.http.ClientConfig;
9090
import org.openqa.selenium.remote.http.ConnectionFailedException;
9191
import org.openqa.selenium.remote.http.HttpClient;
92-
import org.openqa.selenium.remote.internal.WebElementToJsonConverter;
9392
import org.openqa.selenium.remote.tracing.TracedHttpClient;
9493
import org.openqa.selenium.remote.tracing.Tracer;
9594
import org.openqa.selenium.remote.tracing.opentelemetry.OpenTelemetryTracer;
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.openqa.selenium.remote;
19+
20+
import static java.util.stream.Collectors.toList;
21+
22+
import java.lang.reflect.Array;
23+
import java.util.ArrayList;
24+
import java.util.Collection;
25+
import java.util.HashMap;
26+
import java.util.List;
27+
import java.util.Map;
28+
import java.util.function.Function;
29+
import org.openqa.selenium.WrapsElement;
30+
31+
/**
32+
* Converts {@link RemoteWebElement} objects, which may be {@link WrapsElement wrapped}, into their
33+
* JSON representation as defined by the WebDriver wire protocol. This class will recursively
34+
* convert Lists and Maps to catch nested references.
35+
*
36+
* @see <a
37+
* href="https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#webelement-json-object">
38+
* WebDriver JSON Wire Protocol</a>
39+
*/
40+
public class WebElementToJsonConverter implements Function<Object, Object> {
41+
@Override
42+
public Object apply(Object arg) {
43+
if (arg == null || arg instanceof String || arg instanceof Boolean || arg instanceof Number) {
44+
return arg;
45+
}
46+
47+
while (arg instanceof WrapsElement) {
48+
arg = ((WrapsElement) arg).getWrappedElement();
49+
}
50+
51+
if (arg instanceof RemoteWebElement) {
52+
return Map.of(Dialect.W3C.getEncodedElementKey(), ((RemoteWebElement) arg).getId());
53+
}
54+
55+
if (arg instanceof ShadowRoot) {
56+
return Map.of(Dialect.W3C.getShadowRootElementKey(), ((ShadowRoot) arg).getId());
57+
}
58+
59+
if (arg.getClass().isArray()) {
60+
arg = arrayToList(arg);
61+
}
62+
63+
if (arg instanceof Collection<?>) {
64+
Collection<?> args = (Collection<?>) arg;
65+
return args.stream().map(this).collect(toList());
66+
}
67+
68+
if (arg instanceof Map<?, ?>) {
69+
Map<?, ?> args = (Map<?, ?>) arg;
70+
Map<String, Object> converted = new HashMap<>(args.size());
71+
for (Map.Entry<?, ?> entry : args.entrySet()) {
72+
Object key = entry.getKey();
73+
if (!(key instanceof String)) {
74+
throw new IllegalArgumentException(
75+
"All keys in Map script arguments must be strings: " + key.getClass().getName());
76+
}
77+
converted.put((String) key, apply(entry.getValue()));
78+
}
79+
return converted;
80+
}
81+
82+
throw new IllegalArgumentException(
83+
"Argument is of an illegal type: " + arg.getClass().getName());
84+
}
85+
86+
private static List<Object> arrayToList(Object array) {
87+
List<Object> list = new ArrayList<>();
88+
for (int i = 0; i < Array.getLength(array); i++) {
89+
list.add(Array.get(array, i));
90+
}
91+
return list;
92+
}
93+
}

java/src/org/openqa/selenium/remote/codec/w3c/W3CHttpCommandCodec.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@
8888
import java.util.stream.Stream;
8989
import org.openqa.selenium.InvalidSelectorException;
9090
import org.openqa.selenium.WebDriverException;
91+
import org.openqa.selenium.remote.WebElementToJsonConverter;
9192
import org.openqa.selenium.remote.codec.AbstractHttpCommandCodec;
92-
import org.openqa.selenium.remote.internal.WebElementToJsonConverter;
9393

9494
/**
9595
* A command codec that adheres to the W3C's WebDriver wire protocol.

java/src/org/openqa/selenium/remote/internal/WebElementToJsonConverter.java

Lines changed: 6 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -17,75 +17,12 @@
1717

1818
package org.openqa.selenium.remote.internal;
1919

20-
import static java.util.stream.Collectors.toList;
21-
22-
import java.lang.reflect.Array;
23-
import java.util.ArrayList;
24-
import java.util.Collection;
25-
import java.util.HashMap;
26-
import java.util.List;
27-
import java.util.Map;
28-
import java.util.function.Function;
29-
import org.openqa.selenium.WrapsElement;
30-
import org.openqa.selenium.remote.Dialect;
31-
import org.openqa.selenium.remote.RemoteWebElement;
32-
3320
/**
34-
* Converts {@link RemoteWebElement} objects, which may be {@link WrapsElement wrapped}, into their
35-
* JSON representation as defined by the WebDriver wire protocol. This class will recursively
36-
* convert Lists and Maps to catch nested references.
21+
* {@inheritDoc}
3722
*
38-
* @see <a
39-
* href="https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#webelement-json-object">
40-
* WebDriver JSON Wire Protocol</a>
23+
* @deprecated This class has moved to a {@link org.openqa.selenium.remote.WebElementToJsonConverter
24+
* new location}.
4125
*/
42-
public class WebElementToJsonConverter implements Function<Object, Object> {
43-
@Override
44-
public Object apply(Object arg) {
45-
if (arg == null || arg instanceof String || arg instanceof Boolean || arg instanceof Number) {
46-
return arg;
47-
}
48-
49-
while (arg instanceof WrapsElement) {
50-
arg = ((WrapsElement) arg).getWrappedElement();
51-
}
52-
53-
if (arg instanceof RemoteWebElement) {
54-
return Map.of(Dialect.W3C.getEncodedElementKey(), ((RemoteWebElement) arg).getId());
55-
}
56-
57-
if (arg.getClass().isArray()) {
58-
arg = arrayToList(arg);
59-
}
60-
61-
if (arg instanceof Collection<?>) {
62-
Collection<?> args = (Collection<?>) arg;
63-
return args.stream().map(this).collect(toList());
64-
}
65-
66-
if (arg instanceof Map<?, ?>) {
67-
Map<?, ?> args = (Map<?, ?>) arg;
68-
Map<String, Object> converted = new HashMap<>(args.size());
69-
for (Map.Entry<?, ?> entry : args.entrySet()) {
70-
Object key = entry.getKey();
71-
if (!(key instanceof String)) {
72-
throw new IllegalArgumentException(
73-
"All keys in Map script arguments must be strings: " + key.getClass().getName());
74-
}
75-
converted.put((String) key, apply(entry.getValue()));
76-
}
77-
return converted;
78-
}
79-
80-
throw new IllegalArgumentException(
81-
"Argument is of an illegal type: " + arg.getClass().getName());
82-
}
83-
84-
private static List<Object> arrayToList(Object array) {
85-
List<Object> list = new ArrayList<>();
86-
for (int i = 0; i < Array.getLength(array); i++) {
87-
list.add(Array.get(array, i));
88-
}
89-
return list;
90-
}
91-
}
26+
@Deprecated
27+
public class WebElementToJsonConverter
28+
extends org.openqa.selenium.remote.WebElementToJsonConverter {}

java/test/org/openqa/selenium/remote/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ java_test_suite(
2929
"//java/src/org/openqa/selenium/json",
3030
"//java/src/org/openqa/selenium/remote",
3131
"//java/src/org/openqa/selenium/support",
32+
"//java/test/org/openqa/selenium:helpers",
3233
"//java/test/org/openqa/selenium/testing:annotations",
3334
artifact("org.assertj:assertj-core"),
3435
artifact("com.google.guava:guava"),

java/test/org/openqa/selenium/remote/internal/WebElementToJsonConverterTest.java renamed to java/test/org/openqa/selenium/remote/WebElementToJsonConverterTest.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
// specific language governing permissions and limitations
1616
// under the License.
1717

18-
package org.openqa.selenium.remote.internal;
18+
package org.openqa.selenium.remote;
1919

2020
import static java.util.Arrays.asList;
2121
import static org.assertj.core.api.Assertions.assertThat;
@@ -27,10 +27,10 @@
2727
import java.util.List;
2828
import java.util.Map;
2929
import org.junit.jupiter.api.Test;
30+
import org.openqa.selenium.Capabilities;
31+
import org.openqa.selenium.ImmutableCapabilities;
3032
import org.openqa.selenium.WebElement;
3133
import org.openqa.selenium.WrappedWebElement;
32-
import org.openqa.selenium.remote.Dialect;
33-
import org.openqa.selenium.remote.RemoteWebElement;
3434

3535
class WebElementToJsonConverterTest {
3636

@@ -218,6 +218,15 @@ void convertsAnArrayWithAWebElement() {
218218
ImmutableMap.of(Dialect.W3C.getEncodedElementKey(), "abc123"));
219219
}
220220

221+
@Test
222+
void shouldConvertShadowRoots() {
223+
ShadowRoot context = new ShadowRoot(createIdleDriver(), "abc123");
224+
Object value = CONVERTER.apply(new Object[] {context});
225+
assertContentsInOrder(
226+
new ArrayList<>((Collection<?>) value),
227+
ImmutableMap.of(Dialect.W3C.getShadowRootElementKey(), "abc123"));
228+
}
229+
221230
private static WrappedWebElement wrapElement(WebElement element) {
222231
return new WrappedWebElement(element);
223232
}
@@ -235,4 +244,13 @@ private static void assertContentsInOrder(List<?> list, Object... expectedConten
235244
List<Object> expected = asList(expectedContents);
236245
assertThat(list).isEqualTo(expected);
237246
}
247+
248+
private static RemoteWebDriver createIdleDriver() {
249+
return new RemoteWebDriver(cmd -> new Response(), new ImmutableCapabilities()) {
250+
@Override
251+
protected void startSession(Capabilities capabilities) {
252+
// Do nothing
253+
}
254+
};
255+
}
238256
}

java/test/org/openqa/selenium/remote/internal/BUILD.bazel

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
load("@rules_jvm_external//:defs.bzl", "artifact")
2-
load("//java:defs.bzl", "JUNIT5_DEPS", "java_library", "java_test_suite")
2+
load("//java:defs.bzl", "JUNIT5_DEPS", "java_library")
33

44
java_library(
55
name = "test-lib",
@@ -30,22 +30,3 @@ java_library(
3030
artifact("io.netty:netty-transport"),
3131
] + JUNIT5_DEPS,
3232
)
33-
34-
java_test_suite(
35-
name = "SmallTests",
36-
size = "small",
37-
srcs = glob(["*Test.java"]),
38-
tags = [
39-
"no-sandbox",
40-
],
41-
deps = [
42-
":test-lib",
43-
"//java/src/org/openqa/selenium:core",
44-
"//java/src/org/openqa/selenium/remote",
45-
"//java/src/org/openqa/selenium/remote/http",
46-
"//java/test/org/openqa/selenium:helpers",
47-
artifact("org.assertj:assertj-core"),
48-
artifact("com.google.guava:guava"),
49-
artifact("org.junit.jupiter:junit-jupiter-api"),
50-
] + JUNIT5_DEPS,
51-
)

java/test/org/openqa/selenium/support/pagefactory/UsingPageFactoryTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import org.openqa.selenium.WebDriver;
2828
import org.openqa.selenium.WebElement;
2929
import org.openqa.selenium.remote.RemoteWebElement;
30-
import org.openqa.selenium.remote.internal.WebElementToJsonConverter;
30+
import org.openqa.selenium.remote.WebElementToJsonConverter;
3131
import org.openqa.selenium.support.ByIdOrName;
3232
import org.openqa.selenium.support.CacheLookup;
3333
import org.openqa.selenium.support.FindBy;

0 commit comments

Comments
 (0)