Skip to content

Commit 1182189

Browse files
committed
[bidi][java] Listen to channel message
1 parent c020b03 commit 1182189

File tree

4 files changed

+252
-1
lines changed

4 files changed

+252
-1
lines changed

java/src/org/openqa/selenium/bidi/Script.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package org.openqa.selenium.bidi;
1919

20+
import java.io.Closeable;
2021
import java.io.StringReader;
2122
import java.util.Collections;
2223
import java.util.HashMap;
@@ -25,6 +26,7 @@
2526
import java.util.Map;
2627
import java.util.Optional;
2728
import java.util.Set;
29+
import java.util.function.Consumer;
2830
import java.util.function.Function;
2931
import org.openqa.selenium.WebDriver;
3032
import org.openqa.selenium.bidi.script.ChannelValue;
@@ -33,6 +35,7 @@
3335
import org.openqa.selenium.bidi.script.EvaluateResultSuccess;
3436
import org.openqa.selenium.bidi.script.ExceptionDetails;
3537
import org.openqa.selenium.bidi.script.LocalValue;
38+
import org.openqa.selenium.bidi.script.Message;
3639
import org.openqa.selenium.bidi.script.RealmInfo;
3740
import org.openqa.selenium.bidi.script.RealmType;
3841
import org.openqa.selenium.bidi.script.RemoteValue;
@@ -42,7 +45,7 @@
4245
import org.openqa.selenium.json.JsonInput;
4346
import org.openqa.selenium.json.TypeToken;
4447

45-
public class Script {
48+
public class Script implements Closeable {
4649
private final Set<String> browsingContextIds;
4750

4851
private static final Json JSON = new Json();
@@ -61,6 +64,16 @@ public class Script {
6164
}
6265
};
6366

67+
private final Event<Message> messageEvent =
68+
new Event<>(
69+
"script.message",
70+
params -> {
71+
try (StringReader reader = new StringReader(JSON.toJson(params));
72+
JsonInput input = JSON.newInput(reader)) {
73+
return input.read(Message.class);
74+
}
75+
});
76+
6477
public Script(WebDriver driver) {
6578
this(new HashSet<>(), driver);
6679
}
@@ -293,6 +306,14 @@ public void removePreloadScript(String id) {
293306
this.bidi.send(new Command<>("script.removePreloadScript", Map.of("script", id)));
294307
}
295308

309+
public void onMessage(Consumer<Message> consumer) {
310+
if (browsingContextIds.isEmpty()) {
311+
this.bidi.addListener(messageEvent, consumer);
312+
} else {
313+
this.bidi.addListener(browsingContextIds, messageEvent, consumer);
314+
}
315+
}
316+
296317
private Map<String, Object> getCallFunctionParams(
297318
String targetType,
298319
String id,
@@ -376,4 +397,9 @@ private EvaluateResult createEvaluateResult(Map<String, Object> response) {
376397

377398
return evaluateResult;
378399
}
400+
401+
@Override
402+
public void close() {
403+
this.bidi.clearListener(messageEvent);
404+
}
379405
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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+
package org.openqa.selenium.bidi.script;
18+
19+
import org.openqa.selenium.json.JsonInput;
20+
21+
public class Message {
22+
private final String channel;
23+
private final RemoteValue data;
24+
private final Source source;
25+
26+
public Message(String channel, RemoteValue data, Source source) {
27+
this.channel = channel;
28+
this.data = data;
29+
this.source = source;
30+
}
31+
32+
public static Message fromJson(JsonInput input) {
33+
String channel = null;
34+
RemoteValue data = null;
35+
Source source = null;
36+
37+
while (input.hasNext()) {
38+
switch (input.nextName()) {
39+
case "channel":
40+
channel = input.read(String.class);
41+
break;
42+
43+
case "data":
44+
data = input.read(RemoteValue.class);
45+
break;
46+
47+
case "source":
48+
source = input.read(Source.class);
49+
break;
50+
51+
default:
52+
input.skipValue();
53+
break;
54+
}
55+
}
56+
57+
input.endObject();
58+
59+
return new Message(channel, data, source);
60+
}
61+
62+
public String getChannel() {
63+
return channel;
64+
}
65+
66+
public RemoteValue getData() {
67+
return data;
68+
}
69+
70+
public Source getSource() {
71+
return source;
72+
}
73+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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+
package org.openqa.selenium.bidi.script;
18+
19+
import java.util.Optional;
20+
import org.openqa.selenium.json.JsonInput;
21+
22+
public class Source {
23+
private final String realm;
24+
private final Optional<String> browsingContext;
25+
26+
private Source(String realm, Optional<String> browsingContext) {
27+
this.realm = realm;
28+
this.browsingContext = browsingContext;
29+
}
30+
31+
public static Source fromJson(JsonInput input) {
32+
String realm = null;
33+
Optional<String> browsingContext = Optional.empty();
34+
35+
input.beginObject();
36+
while (input.hasNext()) {
37+
switch (input.nextName()) {
38+
case "realm":
39+
realm = input.read(String.class);
40+
break;
41+
42+
case "context":
43+
browsingContext = Optional.ofNullable(input.read(String.class));
44+
break;
45+
46+
default:
47+
input.skipValue();
48+
break;
49+
}
50+
}
51+
52+
input.endObject();
53+
54+
return new Source(realm, browsingContext);
55+
}
56+
57+
public String getRealm() {
58+
return realm;
59+
}
60+
61+
public Optional<String> getBrowsingContext() {
62+
return browsingContext;
63+
}
64+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
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+
package org.openqa.selenium.bidi.script;
18+
19+
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
20+
import static org.openqa.selenium.testing.Safely.safelyCall;
21+
import static org.openqa.selenium.testing.drivers.Browser.CHROME;
22+
import static org.openqa.selenium.testing.drivers.Browser.EDGE;
23+
import static org.openqa.selenium.testing.drivers.Browser.IE;
24+
import static org.openqa.selenium.testing.drivers.Browser.SAFARI;
25+
26+
import java.util.List;
27+
import java.util.Optional;
28+
import java.util.concurrent.CompletableFuture;
29+
import java.util.concurrent.ExecutionException;
30+
import java.util.concurrent.TimeUnit;
31+
import java.util.concurrent.TimeoutException;
32+
import org.junit.jupiter.api.AfterEach;
33+
import org.junit.jupiter.api.BeforeEach;
34+
import org.junit.jupiter.api.Test;
35+
import org.openqa.selenium.bidi.Script;
36+
import org.openqa.selenium.environment.webserver.AppServer;
37+
import org.openqa.selenium.environment.webserver.NettyAppServer;
38+
import org.openqa.selenium.testing.JupiterTestBase;
39+
import org.openqa.selenium.testing.NotYetImplemented;
40+
41+
public class ScriptEventsTest extends JupiterTestBase {
42+
private AppServer server;
43+
44+
@BeforeEach
45+
public void setUp() {
46+
server = new NettyAppServer();
47+
server.start();
48+
}
49+
50+
@Test
51+
@NotYetImplemented(SAFARI)
52+
@NotYetImplemented(IE)
53+
@NotYetImplemented(EDGE)
54+
@NotYetImplemented(CHROME)
55+
void canAddPreloadScriptWithChannelOptions()
56+
throws ExecutionException, InterruptedException, TimeoutException {
57+
try (Script script = new Script(driver)) {
58+
CompletableFuture<Message> future = new CompletableFuture<>();
59+
script.onMessage(future::complete);
60+
61+
script.callFunctionInBrowsingContext(
62+
driver.getWindowHandle(),
63+
"(channel) => channel('foo')",
64+
false,
65+
Optional.of(List.of(LocalValue.channelValue("channel_name"))),
66+
Optional.empty(),
67+
Optional.empty());
68+
69+
Message message = future.get(5, TimeUnit.SECONDS);
70+
assertThat(message.getChannel()).isEqualTo("channel_name");
71+
assertThat(message.getData().getType()).isEqualTo("string");
72+
assertThat(message.getData().getValue().isPresent()).isTrue();
73+
assertThat(message.getData().getValue().get()).isEqualTo("foo");
74+
assertThat(message.getSource().getRealm()).isNotNull();
75+
assertThat(message.getSource().getBrowsingContext().isPresent()).isTrue();
76+
assertThat(message.getSource().getBrowsingContext().get())
77+
.isEqualTo(driver.getWindowHandle());
78+
}
79+
}
80+
81+
@AfterEach
82+
public void quitDriver() {
83+
if (driver != null) {
84+
driver.quit();
85+
}
86+
safelyCall(server::stop);
87+
}
88+
}

0 commit comments

Comments
 (0)