Skip to content

Commit bd1110c

Browse files
committed
[grid] Adding fallback locators for ById and ByName
1 parent 2e2ec56 commit bd1110c

File tree

5 files changed

+135
-8
lines changed

5 files changed

+135
-8
lines changed

java/server/src/org/openqa/selenium/grid/node/BUILD.bazel

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ java_library(
1818
"//java/client/src/org/openqa/selenium/remote",
1919
"//java/server/src/org/openqa/selenium/grid/component",
2020
"//java/server/src/org/openqa/selenium/grid/data",
21+
"//java/server/src/org/openqa/selenium/grid/node/locators",
2122
"//java/server/src/org/openqa/selenium/grid/security",
2223
"//java/server/src/org/openqa/selenium/grid/web",
2324
"//java/server/src/org/openqa/selenium/status",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
load("//java:defs.bzl", "java_library")
2+
3+
java_library(
4+
name = "locators",
5+
srcs = glob(["*.java"]),
6+
visibility = [
7+
"//java/server/src/org/openqa/selenium/grid/node:__pkg__",
8+
"//java/server/src/org/openqa/selenium/grid/node/locators:__pkg__",
9+
"//java/server/test/org/openqa/selenium/grid:__subpackages__",
10+
],
11+
deps = [
12+
"//java:auto-service",
13+
"//java/client/src/org/openqa/selenium:core",
14+
"//java/client/src/org/openqa/selenium/remote",
15+
],
16+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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.grid.node.locators;
19+
20+
import static java.util.stream.Collectors.joining;
21+
22+
import com.google.auto.service.AutoService;
23+
24+
import org.openqa.selenium.By;
25+
import org.openqa.selenium.remote.locators.CustomLocator;
26+
27+
import java.util.stream.Stream;
28+
29+
public class FallbackLocators {
30+
31+
@AutoService(CustomLocator.class)
32+
public static class ById extends CustomLocator {
33+
@Override
34+
public String getLocatorName() {
35+
return "id";
36+
}
37+
38+
@Override
39+
public By createBy(Object usingParameter) {
40+
String id = Stream.of(
41+
String.valueOf(usingParameter)
42+
.split("\\s+")).map(str -> "#" + str).collect(joining(" "));
43+
return By.cssSelector(id);
44+
}
45+
}
46+
47+
@AutoService(CustomLocator.class)
48+
public static class ByName extends CustomLocator {
49+
@Override
50+
public String getLocatorName() {
51+
return "name";
52+
}
53+
54+
@Override
55+
public By createBy(Object usingParameter) {
56+
String name = String.valueOf(usingParameter).replace("'", "\\'");
57+
return By.cssSelector(String.format("*[name='%s']", name));
58+
}
59+
}
60+
61+
62+
// asJson.put("value", String.format("*[name='%s']", name.replace("'", "\\'")));
63+
}

java/server/test/org/openqa/selenium/grid/node/BUILD.bazel

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ java_test_suite(
1919
"//java/server/src/org/openqa/selenium/grid/data",
2020
"//java/server/src/org/openqa/selenium/grid/node",
2121
"//java/server/src/org/openqa/selenium/grid/node/local",
22+
"//java/server/src/org/openqa/selenium/grid/node/locators",
2223
"//java/server/src/org/openqa/selenium/grid/node/remote",
2324
"//java/server/src/org/openqa/selenium/grid/security",
2425
"//java/server/src/org/openqa/selenium/grid/web",

java/server/test/org/openqa/selenium/grid/node/CustomLocatorHandlerTest.java

+54-8
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.openqa.selenium.events.local.GuavaEventBus;
3333
import org.openqa.selenium.grid.data.Session;
3434
import org.openqa.selenium.grid.node.local.LocalNode;
35+
import org.openqa.selenium.grid.node.locators.FallbackLocators;
3536
import org.openqa.selenium.grid.security.Secret;
3637
import org.openqa.selenium.grid.testing.TestSessionFactory;
3738
import org.openqa.selenium.grid.web.ErrorFilter;
@@ -91,8 +92,7 @@ public void partiallyBuildNode() {
9192
public void shouldRequireInputToHaveAUsingParameter() {
9293
Node node = nodeBuilder.build();
9394

94-
HttpHandler handler = new org.openqa.selenium.grid.node.CustomLocatorHandler(
95-
node, registrationSecret, emptySet());
95+
HttpHandler handler = new CustomLocatorHandler(node, registrationSecret, emptySet());
9696

9797
HttpResponse res = handler.execute(
9898
new HttpRequest(POST, "/session/1234/element")
@@ -106,8 +106,7 @@ public void shouldRequireInputToHaveAUsingParameter() {
106106
public void shouldRequireInputToHaveAValueParameter() {
107107
Node node = nodeBuilder.build();
108108

109-
HttpHandler handler = new org.openqa.selenium.grid.node.CustomLocatorHandler(
110-
node, registrationSecret, emptySet());
109+
HttpHandler handler = new CustomLocatorHandler(node, registrationSecret, emptySet());
111110

112111
HttpResponse res = handler.execute(
113112
new HttpRequest(POST, "/session/1234/element")
@@ -121,8 +120,7 @@ public void shouldRequireInputToHaveAValueParameter() {
121120
public void shouldRejectRequestWithAnUnknownLocatorMechanism() {
122121
Node node = nodeBuilder.build();
123122

124-
HttpHandler handler = new org.openqa.selenium.grid.node.CustomLocatorHandler(
125-
node, registrationSecret, emptySet());
123+
HttpHandler handler = new CustomLocatorHandler(node, registrationSecret, emptySet());
126124

127125
HttpResponse res = handler.execute(
128126
new HttpRequest(POST, "/session/1234/element")
@@ -142,7 +140,7 @@ public void shouldCallTheGivenLocatorForALocator() {
142140
new TestSessionFactory((id, c) -> new Session(id, nodeUri, caps, c, Instant.now())))
143141
.build();
144142

145-
HttpHandler handler = new org.openqa.selenium.grid.node.CustomLocatorHandler(
143+
HttpHandler handler = new CustomLocatorHandler(
146144
node,
147145
registrationSecret,
148146
singleton(new CustomLocator() {
@@ -183,7 +181,7 @@ public void shouldBeAbleToUseNodeAsWebDriver() {
183181
.setContent(Contents.asJson(singletonMap(
184182
"value", singletonList(singletonMap(Dialect.W3C.getEncodedElementKey(), elementId))))));
185183

186-
HttpHandler handler = new org.openqa.selenium.grid.node.CustomLocatorHandler(
184+
HttpHandler handler = new CustomLocatorHandler(
187185
node,
188186
registrationSecret,
189187
singleton(new CustomLocator() {
@@ -249,6 +247,54 @@ public By createBy(Object usingParameter) {
249247
assertThat(seenId).isEqualTo(elementId);
250248
}
251249

250+
@Test
251+
public void shouldNotFindLocatorStrategyForId() {
252+
Capabilities caps = new ImmutableCapabilities("browserName", "cheesefox");
253+
Node node = nodeBuilder.add(
254+
caps,
255+
new TestSessionFactory((id, c) -> new Session(id, nodeUri, caps, c, Instant.now())))
256+
.build();
257+
258+
HttpHandler handler = new CustomLocatorHandler(node, registrationSecret, emptySet());
259+
260+
HttpResponse res = handler.with(new ErrorFilter()).execute(
261+
new HttpRequest(POST, "/session/1234/element")
262+
.setContent(Contents.asJson(ImmutableMap.of(
263+
"using", "id",
264+
"value", "tasty"))));
265+
266+
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(() -> Values.get(res, WebElement.class));
267+
}
268+
269+
@Test
270+
public void shouldFallbackToUseById() {
271+
String elementId = UUID.randomUUID().toString();
272+
273+
Node node = Mockito.mock(Node.class);
274+
when(node.executeWebDriverCommand(argThat(matchesUri("/session/{sessionId}/elements"))))
275+
.thenReturn(
276+
new HttpResponse()
277+
.addHeader("Content-Type", Json.JSON_UTF_8)
278+
.setContent(Contents.asJson(singletonMap(
279+
"value", singletonList(singletonMap(Dialect.W3C.getEncodedElementKey(), elementId))))));
280+
281+
HttpHandler handler = new CustomLocatorHandler(
282+
node,
283+
registrationSecret,
284+
singleton(new FallbackLocators.ById()));
285+
286+
HttpResponse res = handler.execute(
287+
new HttpRequest(POST, "/session/1234/elements")
288+
.setContent(Contents.asJson(ImmutableMap.of(
289+
"using", "id",
290+
"value", "tasty"))));
291+
292+
List<Map<String, Object>> elements = Values.get(res, new TypeToken<List<Map<String, Object>>>(){}.getType());
293+
assertThat(elements).hasSize(1);
294+
Object seenId = elements.get(0).get(Dialect.W3C.getEncodedElementKey());
295+
assertThat(seenId).isEqualTo(elementId);
296+
}
297+
252298
private ArgumentMatcher<HttpRequest> matchesUri(String template) {
253299
UrlTemplate ut = new UrlTemplate(template);
254300

0 commit comments

Comments
 (0)