Skip to content

Commit

Permalink
[bidi][java] Listen to channel message
Browse files Browse the repository at this point in the history
  • Loading branch information
pujagani committed Nov 3, 2023
1 parent c020b03 commit 1182189
Show file tree
Hide file tree
Showing 4 changed files with 252 additions and 1 deletion.
28 changes: 27 additions & 1 deletion java/src/org/openqa/selenium/bidi/Script.java
Expand Up @@ -17,6 +17,7 @@

package org.openqa.selenium.bidi;

import java.io.Closeable;
import java.io.StringReader;
import java.util.Collections;
import java.util.HashMap;
Expand All @@ -25,6 +26,7 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.bidi.script.ChannelValue;
Expand All @@ -33,6 +35,7 @@
import org.openqa.selenium.bidi.script.EvaluateResultSuccess;
import org.openqa.selenium.bidi.script.ExceptionDetails;
import org.openqa.selenium.bidi.script.LocalValue;
import org.openqa.selenium.bidi.script.Message;
import org.openqa.selenium.bidi.script.RealmInfo;
import org.openqa.selenium.bidi.script.RealmType;
import org.openqa.selenium.bidi.script.RemoteValue;
Expand All @@ -42,7 +45,7 @@
import org.openqa.selenium.json.JsonInput;
import org.openqa.selenium.json.TypeToken;

public class Script {
public class Script implements Closeable {
private final Set<String> browsingContextIds;

private static final Json JSON = new Json();
Expand All @@ -61,6 +64,16 @@ public class Script {
}
};

private final Event<Message> messageEvent =
new Event<>(
"script.message",
params -> {
try (StringReader reader = new StringReader(JSON.toJson(params));
JsonInput input = JSON.newInput(reader)) {
return input.read(Message.class);
}
});

public Script(WebDriver driver) {
this(new HashSet<>(), driver);
}
Expand Down Expand Up @@ -293,6 +306,14 @@ public void removePreloadScript(String id) {
this.bidi.send(new Command<>("script.removePreloadScript", Map.of("script", id)));
}

public void onMessage(Consumer<Message> consumer) {
if (browsingContextIds.isEmpty()) {
this.bidi.addListener(messageEvent, consumer);
} else {
this.bidi.addListener(browsingContextIds, messageEvent, consumer);
}
}

private Map<String, Object> getCallFunctionParams(
String targetType,
String id,
Expand Down Expand Up @@ -376,4 +397,9 @@ private EvaluateResult createEvaluateResult(Map<String, Object> response) {

return evaluateResult;
}

@Override
public void close() {
this.bidi.clearListener(messageEvent);
}
}
73 changes: 73 additions & 0 deletions java/src/org/openqa/selenium/bidi/script/Message.java
@@ -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.bidi.script;

import org.openqa.selenium.json.JsonInput;

public class Message {
private final String channel;
private final RemoteValue data;
private final Source source;

public Message(String channel, RemoteValue data, Source source) {
this.channel = channel;
this.data = data;
this.source = source;
}

public static Message fromJson(JsonInput input) {
String channel = null;
RemoteValue data = null;
Source source = null;

while (input.hasNext()) {
switch (input.nextName()) {
case "channel":
channel = input.read(String.class);
break;

case "data":
data = input.read(RemoteValue.class);
break;

case "source":
source = input.read(Source.class);
break;

default:
input.skipValue();
break;
}
}

input.endObject();

return new Message(channel, data, source);
}

public String getChannel() {
return channel;
}

public RemoteValue getData() {
return data;
}

public Source getSource() {
return source;
}
}
64 changes: 64 additions & 0 deletions java/src/org/openqa/selenium/bidi/script/Source.java
@@ -0,0 +1,64 @@
// 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.bidi.script;

import java.util.Optional;
import org.openqa.selenium.json.JsonInput;

public class Source {
private final String realm;
private final Optional<String> browsingContext;

private Source(String realm, Optional<String> browsingContext) {
this.realm = realm;
this.browsingContext = browsingContext;
}

public static Source fromJson(JsonInput input) {
String realm = null;
Optional<String> browsingContext = Optional.empty();

input.beginObject();
while (input.hasNext()) {
switch (input.nextName()) {
case "realm":
realm = input.read(String.class);
break;

case "context":
browsingContext = Optional.ofNullable(input.read(String.class));
break;

default:
input.skipValue();
break;
}
}

input.endObject();

return new Source(realm, browsingContext);
}

public String getRealm() {
return realm;
}

public Optional<String> getBrowsingContext() {
return browsingContext;
}
}
88 changes: 88 additions & 0 deletions java/test/org/openqa/selenium/bidi/script/ScriptEventsTest.java
@@ -0,0 +1,88 @@
// 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.bidi.script;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.openqa.selenium.testing.Safely.safelyCall;
import static org.openqa.selenium.testing.drivers.Browser.CHROME;
import static org.openqa.selenium.testing.drivers.Browser.EDGE;
import static org.openqa.selenium.testing.drivers.Browser.IE;
import static org.openqa.selenium.testing.drivers.Browser.SAFARI;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.bidi.Script;
import org.openqa.selenium.environment.webserver.AppServer;
import org.openqa.selenium.environment.webserver.NettyAppServer;
import org.openqa.selenium.testing.JupiterTestBase;
import org.openqa.selenium.testing.NotYetImplemented;

public class ScriptEventsTest extends JupiterTestBase {
private AppServer server;

@BeforeEach
public void setUp() {
server = new NettyAppServer();
server.start();
}

@Test
@NotYetImplemented(SAFARI)
@NotYetImplemented(IE)
@NotYetImplemented(EDGE)
@NotYetImplemented(CHROME)
void canAddPreloadScriptWithChannelOptions()
throws ExecutionException, InterruptedException, TimeoutException {
try (Script script = new Script(driver)) {
CompletableFuture<Message> future = new CompletableFuture<>();
script.onMessage(future::complete);

script.callFunctionInBrowsingContext(
driver.getWindowHandle(),
"(channel) => channel('foo')",
false,
Optional.of(List.of(LocalValue.channelValue("channel_name"))),
Optional.empty(),
Optional.empty());

Message message = future.get(5, TimeUnit.SECONDS);
assertThat(message.getChannel()).isEqualTo("channel_name");
assertThat(message.getData().getType()).isEqualTo("string");
assertThat(message.getData().getValue().isPresent()).isTrue();
assertThat(message.getData().getValue().get()).isEqualTo("foo");
assertThat(message.getSource().getRealm()).isNotNull();
assertThat(message.getSource().getBrowsingContext().isPresent()).isTrue();
assertThat(message.getSource().getBrowsingContext().get())
.isEqualTo(driver.getWindowHandle());
}
}

@AfterEach
public void quitDriver() {
if (driver != null) {
driver.quit();
}
safelyCall(server::stop);
}
}

0 comments on commit 1182189

Please sign in to comment.