feat: support exposeBinding/exposeFunction
This commit is contained in:
@@ -531,6 +531,22 @@ class Interface extends TypeDefinition {
|
||||
output.add(offset + " return height;");
|
||||
output.add(offset + " }");
|
||||
output.add(offset + "}");
|
||||
output.add("");
|
||||
|
||||
output.add(offset + "interface Function {");
|
||||
output.add(offset + " Object call(Object... args);");
|
||||
output.add(offset + "}");
|
||||
output.add("");
|
||||
|
||||
output.add(offset + "interface Binding {");
|
||||
output.add(offset + " interface Source {");
|
||||
output.add(offset + " BrowserContext context();");
|
||||
output.add(offset + " Page page();");
|
||||
output.add(offset + " Frame frame();");
|
||||
output.add(offset + " }");
|
||||
output.add("");
|
||||
output.add(offset + " Object call(Source source, Object... args);");
|
||||
output.add(offset + "}");
|
||||
break;
|
||||
}
|
||||
case "BrowserContext": {
|
||||
|
||||
@@ -152,20 +152,19 @@ class Types {
|
||||
|
||||
|
||||
// js functions are always passed as text in java.
|
||||
add("BrowserContext.exposeBinding.playwrightBinding", "function", "String");
|
||||
add("BrowserContext.exposeFunction.playwrightFunction", "function", "String");
|
||||
add("Page.$eval.pageFunction", "function(Element)", "String");
|
||||
add("Page.$$eval.pageFunction", "function(Array<Element>)", "String");
|
||||
add("Page.exposeBinding.playwrightBinding", "function", "String");
|
||||
add("Page.exposeFunction.playwrightFunction", "function", "String");
|
||||
add("Frame.$eval.pageFunction", "function(Element)", "String");
|
||||
add("Frame.$$eval.pageFunction", "function(Array<Element>)", "String");
|
||||
add("ElementHandle.$eval.pageFunction", "function(Element)", "String");
|
||||
add("ElementHandle.$$eval.pageFunction", "function(Array<Element>)", "String");
|
||||
add("ElementHandle.evaluate.pageFunction", "function", "String");
|
||||
add("JSHandle.evaluate.pageFunction", "function", "String");
|
||||
add("ChromiumBrowserContext.exposeBinding.playwrightBinding", "function", "String");
|
||||
add("ChromiumBrowserContext.exposeFunction.playwrightFunction", "function", "String");
|
||||
|
||||
add("BrowserContext.exposeBinding.playwrightBinding", "function", "Page.Binding");
|
||||
add("BrowserContext.exposeFunction.playwrightFunction", "function", "Page.Function");
|
||||
add("Page.exposeBinding.playwrightBinding", "function", "Binding");
|
||||
add("Page.exposeFunction.playwrightFunction", "function", "Function");
|
||||
|
||||
add("BrowserContext.addInitScript.script", "function|string|Object", "String");
|
||||
add("Page.addInitScript.script", "function|string|Object", "String");
|
||||
|
||||
@@ -78,8 +78,8 @@ public interface BrowserContext {
|
||||
return cookies(null);
|
||||
}
|
||||
List<Object> cookies(String urls);
|
||||
void exposeBinding(String name, String playwrightBinding);
|
||||
void exposeFunction(String name, String playwrightFunction);
|
||||
void exposeBinding(String name, Page.Binding playwrightBinding);
|
||||
void exposeFunction(String name, Page.Function playwrightFunction);
|
||||
default void grantPermissions(List<String> permissions) {
|
||||
grantPermissions(permissions, null);
|
||||
}
|
||||
|
||||
@@ -38,6 +38,20 @@ public interface Page {
|
||||
}
|
||||
}
|
||||
|
||||
interface Function {
|
||||
Object call(Object... args);
|
||||
}
|
||||
|
||||
interface Binding {
|
||||
interface Source {
|
||||
BrowserContext context();
|
||||
Page page();
|
||||
Frame frame();
|
||||
}
|
||||
|
||||
Object call(Source source, Object... args);
|
||||
}
|
||||
|
||||
enum LoadState { DOMCONTENTLOADED, LOAD, NETWORKIDLE }
|
||||
class CloseOptions {
|
||||
public Boolean runBeforeUnload;
|
||||
@@ -789,8 +803,8 @@ public interface Page {
|
||||
return evaluateHandle(pageFunction, null);
|
||||
}
|
||||
JSHandle evaluateHandle(String pageFunction, Object arg);
|
||||
void exposeBinding(String name, String playwrightBinding);
|
||||
void exposeFunction(String name, String playwrightFunction);
|
||||
void exposeBinding(String name, Binding playwrightBinding);
|
||||
void exposeFunction(String name, Function playwrightFunction);
|
||||
default void fill(String selector, String value) {
|
||||
fill(selector, value, null);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed 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 com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.BrowserContext;
|
||||
import com.microsoft.playwright.Frame;
|
||||
import com.microsoft.playwright.Page;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.microsoft.playwright.impl.Serialization.*;
|
||||
|
||||
class BindingCall extends ChannelOwner {
|
||||
private static class SourceImpl implements Page.Binding.Source {
|
||||
private final Frame frame;
|
||||
|
||||
public SourceImpl(Frame frame) {
|
||||
this.frame = frame;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BrowserContext context() {
|
||||
return page().context();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page page() {
|
||||
return frame.page();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frame frame() {
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
|
||||
BindingCall(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
}
|
||||
|
||||
String name() {
|
||||
return initializer.get("name").getAsString();
|
||||
}
|
||||
|
||||
void call(Page.Binding binding) {
|
||||
try {
|
||||
Frame frame = connection.getExistingObject(initializer.getAsJsonObject("frame").get("guid").getAsString());
|
||||
Page.Binding.Source source = new SourceImpl(frame);
|
||||
List<Object> args = new ArrayList<>();
|
||||
for (JsonElement arg : initializer.getAsJsonArray("args")) {
|
||||
args.add(deserialize(new Gson().fromJson(arg, SerializedValue.class)));
|
||||
}
|
||||
Object result = binding.call(source, args.toArray());
|
||||
|
||||
JsonObject params = new JsonObject();
|
||||
params.add("result", new Gson().toJsonTree(serializeArgument(result)));
|
||||
sendMessage("resolve", params);
|
||||
} catch (RuntimeException exception) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.add("error", new Gson().toJsonTree(serializeError(exception)));
|
||||
sendMessage("reject", params);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,18 +21,22 @@ import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.microsoft.playwright.impl.Utils.globToRegex;
|
||||
import static com.microsoft.playwright.impl.Utils.isFunctionBody;
|
||||
|
||||
class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
private final List<PageImpl> pages = new ArrayList<>();
|
||||
private List<RouteInfo> routes = new ArrayList<>();
|
||||
final Map<String, Page.Binding> bindings = new HashMap<String, Page.Binding>();
|
||||
|
||||
private class RouteInfo {
|
||||
private String url;
|
||||
private BiConsumer<Route, Request> handler;
|
||||
@@ -61,7 +65,13 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
|
||||
@Override
|
||||
public void addInitScript(String script, Object arg) {
|
||||
|
||||
// TODO: serialize arg
|
||||
JsonObject params = new JsonObject();
|
||||
if (isFunctionBody(script)) {
|
||||
script = "(" + script + ")()";
|
||||
}
|
||||
params.addProperty("source", script);
|
||||
sendMessage("addInitScript", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -85,13 +95,24 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exposeBinding(String name, String playwrightBinding) {
|
||||
public void exposeBinding(String name, Page.Binding playwrightBinding) {
|
||||
if (bindings.containsKey(name)) {
|
||||
throw new RuntimeException("Function " + name + " has already been registered");
|
||||
}
|
||||
for (PageImpl page : pages) {
|
||||
if (page.bindings.containsKey(name))
|
||||
throw new Error("Function " + name + " has already been registered in one of the pages");
|
||||
}
|
||||
bindings.put(name, playwrightBinding);
|
||||
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("name", name);
|
||||
sendMessage("exposeBinding", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exposeFunction(String name, String playwrightFunction) {
|
||||
|
||||
public void exposeFunction(String name, Page.Function playwrightFunction) {
|
||||
exposeBinding(name, (Page.Binding.Source source, Object... args) -> playwrightFunction.call(args));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -191,6 +212,15 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
}
|
||||
}
|
||||
route.continue_();
|
||||
} else if ("page".equals(event)) {
|
||||
PageImpl page = connection.getExistingObject(params.getAsJsonObject("page").get("guid").getAsString());
|
||||
pages.add(page);
|
||||
} else if ("bindingCall".equals(event)) {
|
||||
BindingCall bindingCall = connection.getExistingObject(params.getAsJsonObject("binding").get("guid").getAsString());
|
||||
Page.Binding binding = bindings.get(bindingCall.name());
|
||||
if (binding != null) {
|
||||
bindingCall.call(binding);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,6 +174,9 @@ public class Connection {
|
||||
ChannelOwner result = null;
|
||||
// initializer = this._replaceGuidsWithChannels(initializer);
|
||||
switch (type) {
|
||||
case "BindingCall":
|
||||
result = new BindingCall(parent, type, guid, initializer);
|
||||
break;
|
||||
case "BrowserType":
|
||||
result = new BrowserTypeImpl(parent, type, guid, initializer);
|
||||
break;
|
||||
|
||||
@@ -23,10 +23,11 @@ import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static com.microsoft.playwright.Frame.LoadState.*;
|
||||
import static com.microsoft.playwright.impl.Helpers.isFunctionBody;
|
||||
import static com.microsoft.playwright.impl.Serialization.deserialize;
|
||||
import static com.microsoft.playwright.impl.Serialization.serializeArgument;
|
||||
import static com.microsoft.playwright.impl.Utils.isFunctionBody;
|
||||
|
||||
public class FrameImpl extends ChannelOwner implements Frame {
|
||||
PageImpl page;
|
||||
@@ -49,99 +50,6 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
}
|
||||
|
||||
private static SerializedValue serializeValue(Object value) {
|
||||
SerializedValue result = new SerializedValue();
|
||||
if (value == null)
|
||||
result.v = "undefined";
|
||||
else if (value instanceof Double) {
|
||||
double d = ((Double) value).doubleValue();
|
||||
if (d == Double.POSITIVE_INFINITY)
|
||||
result.v = "Infinity";
|
||||
else if (d == Double.NEGATIVE_INFINITY)
|
||||
result.v = "-Infinity";
|
||||
else if (d == -0)
|
||||
result.v = "-0";
|
||||
else if (Double.isNaN(d))
|
||||
result.v="NaN";
|
||||
else
|
||||
result.n = d;
|
||||
}
|
||||
// if (value instanceof Date)
|
||||
else if (value instanceof Boolean)
|
||||
result.b = (Boolean) value;
|
||||
else if (value instanceof Integer)
|
||||
result.n = (Integer) value;
|
||||
else if (value instanceof String)
|
||||
result.s = (String) value;
|
||||
else if (value instanceof List) {
|
||||
List<SerializedValue> list = new ArrayList<>();
|
||||
for (Object o : (List) value)
|
||||
list.add(serializeValue(o));
|
||||
result.a = list.toArray(new SerializedValue[0]);
|
||||
} else if (value instanceof Map) {
|
||||
List<SerializedValue.O> list = new ArrayList<>();
|
||||
Map<String, Object> map = (Map<String, Object>) value;
|
||||
for (Map.Entry<String, Object> e : map.entrySet()) {
|
||||
SerializedValue.O o = new SerializedValue.O();
|
||||
o.k = e.getKey();
|
||||
o.v = serializeValue(e.getValue());
|
||||
list.add(o);
|
||||
}
|
||||
result.o = list.toArray(new SerializedValue.O[0]);
|
||||
} else
|
||||
throw new RuntimeException("Unsupported type of argument: " + value);
|
||||
return result;
|
||||
}
|
||||
private static SerializedArgument serializeArgument(Object arg) {
|
||||
SerializedArgument result = new SerializedArgument();
|
||||
result.value = serializeValue(arg);
|
||||
result.handles = new Channel[0];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private static <T> T deserialize(SerializedValue value) {
|
||||
if (value.n != null) {
|
||||
if (value.n.doubleValue() == (double) value.n.intValue())
|
||||
return (T) Integer.valueOf(value.n.intValue());
|
||||
return (T) Double.valueOf(value.n.doubleValue());
|
||||
}
|
||||
if (value.b != null)
|
||||
return (T) value.b;
|
||||
if (value.s != null)
|
||||
return (T) value.s;
|
||||
if (value.v != null) {
|
||||
switch (value.v) {
|
||||
case "undefined":
|
||||
case "null":
|
||||
return null;
|
||||
case "Infinity":
|
||||
return (T) Double.valueOf(Double.POSITIVE_INFINITY);
|
||||
case "-Infinity":
|
||||
return (T) Double.valueOf(Double.NEGATIVE_INFINITY);
|
||||
case "-0":
|
||||
return (T) Double.valueOf(-0);
|
||||
case "NaN":
|
||||
return (T) Double.valueOf(Double.NaN);
|
||||
default:
|
||||
throw new RuntimeException("Unexpected value: " + value.v);
|
||||
}
|
||||
}
|
||||
if (value.a != null) {
|
||||
List list = new ArrayList();
|
||||
for (SerializedValue v : value.a)
|
||||
list.add(deserialize(v));
|
||||
return (T) list;
|
||||
}
|
||||
if (value.o != null) {
|
||||
Map map = new LinkedHashMap<>();
|
||||
for (SerializedValue.O o : value.o)
|
||||
map.put(o.k, deserialize(o.v));
|
||||
return (T) map;
|
||||
}
|
||||
throw new RuntimeException("Unexpected result: " + new Gson().toJson(value));
|
||||
}
|
||||
|
||||
public <T> T evalTyped(String expression) {
|
||||
return (T) evaluate(expression, null, false);
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed 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 com.microsoft.playwright.impl;
|
||||
|
||||
class Helpers {
|
||||
static boolean isFunctionBody(String expression) {
|
||||
expression = expression.trim();
|
||||
return expression.startsWith("function") ||
|
||||
expression.startsWith("async ") ||
|
||||
expression.contains("=>");
|
||||
}
|
||||
}
|
||||
@@ -16,15 +16,13 @@
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -32,14 +30,17 @@ import static com.microsoft.playwright.impl.Utils.convertViaJson;
|
||||
|
||||
|
||||
public class PageImpl extends ChannelOwner implements Page {
|
||||
private final BrowserContextImpl browserContext;
|
||||
private final FrameImpl mainFrame;
|
||||
private final KeyboardImpl keyboard;
|
||||
private final MouseImpl mouse;
|
||||
private final List<DialogHandler> dialogHandlers = new ArrayList<>();
|
||||
private final List<Listener<ConsoleMessage>> consoleListeners = new ArrayList<>();
|
||||
final Map<String, Binding> bindings = new HashMap<String, Binding>();
|
||||
|
||||
PageImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
browserContext = (BrowserContextImpl) parent;
|
||||
mainFrame = connection.getExistingObject(initializer.getAsJsonObject("mainFrame").get("guid").getAsString());
|
||||
mainFrame.page = this;
|
||||
keyboard = new KeyboardImpl(this);
|
||||
@@ -202,13 +203,23 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exposeBinding(String name, String playwrightBinding) {
|
||||
public void exposeBinding(String name, Binding playwrightBinding) {
|
||||
if (bindings.containsKey(name)) {
|
||||
throw new RuntimeException("Function " + name + " has already been registered");
|
||||
}
|
||||
if (browserContext.bindings.containsKey(name)) {
|
||||
throw new RuntimeException("Function " + name + " has already been registered in the browser context");
|
||||
}
|
||||
bindings.put(name, playwrightBinding);
|
||||
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("name", name);
|
||||
sendMessage("exposeBinding", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exposeFunction(String name, String playwrightFunction) {
|
||||
|
||||
public void exposeFunction(String name, Function playwrightFunction) {
|
||||
exposeBinding(name, (Binding.Source source, Object... args) -> playwrightFunction.call(args));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed 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 com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
class Serialization {
|
||||
static SerializedError serializeError(Throwable e) {
|
||||
SerializedError result = new SerializedError();
|
||||
result.error = new SerializedError.Error();
|
||||
result.error.message = e.getMessage();
|
||||
result.error.name = e.getClass().getName();
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
e.printStackTrace(new PrintStream(out));
|
||||
result.error.stack = new String(out.toByteArray());
|
||||
return result;
|
||||
}
|
||||
|
||||
private static SerializedValue serializeValue(Object value) {
|
||||
SerializedValue result = new SerializedValue();
|
||||
if (value == null)
|
||||
result.v = "undefined";
|
||||
else if (value instanceof Double) {
|
||||
double d = ((Double) value).doubleValue();
|
||||
if (d == Double.POSITIVE_INFINITY)
|
||||
result.v = "Infinity";
|
||||
else if (d == Double.NEGATIVE_INFINITY)
|
||||
result.v = "-Infinity";
|
||||
else if (d == -0)
|
||||
result.v = "-0";
|
||||
else if (Double.isNaN(d))
|
||||
result.v="NaN";
|
||||
else
|
||||
result.n = d;
|
||||
}
|
||||
else if (value instanceof Boolean)
|
||||
result.b = (Boolean) value;
|
||||
else if (value instanceof Integer)
|
||||
result.n = (Integer) value;
|
||||
else if (value instanceof String)
|
||||
result.s = (String) value;
|
||||
else if (value instanceof List) {
|
||||
List<SerializedValue> list = new ArrayList<>();
|
||||
for (Object o : (List) value)
|
||||
list.add(serializeValue(o));
|
||||
result.a = list.toArray(new SerializedValue[0]);
|
||||
} else if (value instanceof Map) {
|
||||
List<SerializedValue.O> list = new ArrayList<>();
|
||||
Map<String, Object> map = (Map<String, Object>) value;
|
||||
for (Map.Entry<String, Object> e : map.entrySet()) {
|
||||
SerializedValue.O o = new SerializedValue.O();
|
||||
o.k = e.getKey();
|
||||
o.v = serializeValue(e.getValue());
|
||||
list.add(o);
|
||||
}
|
||||
result.o = list.toArray(new SerializedValue.O[0]);
|
||||
} else
|
||||
throw new RuntimeException("Unsupported type of argument: " + value);
|
||||
return result;
|
||||
}
|
||||
|
||||
static SerializedArgument serializeArgument(Object arg) {
|
||||
SerializedArgument result = new SerializedArgument();
|
||||
result.value = serializeValue(arg);
|
||||
result.handles = new Channel[0];
|
||||
return result;
|
||||
}
|
||||
|
||||
static <T> T deserialize(SerializedValue value) {
|
||||
if (value.n != null) {
|
||||
if (value.n.doubleValue() == (double) value.n.intValue())
|
||||
return (T) Integer.valueOf(value.n.intValue());
|
||||
return (T) Double.valueOf(value.n.doubleValue());
|
||||
}
|
||||
if (value.b != null)
|
||||
return (T) value.b;
|
||||
if (value.s != null)
|
||||
return (T) value.s;
|
||||
if (value.v != null) {
|
||||
switch (value.v) {
|
||||
case "undefined":
|
||||
case "null":
|
||||
return null;
|
||||
case "Infinity":
|
||||
return (T) Double.valueOf(Double.POSITIVE_INFINITY);
|
||||
case "-Infinity":
|
||||
return (T) Double.valueOf(Double.NEGATIVE_INFINITY);
|
||||
case "-0":
|
||||
return (T) Double.valueOf(-0);
|
||||
case "NaN":
|
||||
return (T) Double.valueOf(Double.NaN);
|
||||
default:
|
||||
throw new RuntimeException("Unexpected value: " + value.v);
|
||||
}
|
||||
}
|
||||
if (value.a != null) {
|
||||
List list = new ArrayList();
|
||||
for (SerializedValue v : value.a)
|
||||
list.add(deserialize(v));
|
||||
return (T) list;
|
||||
}
|
||||
if (value.o != null) {
|
||||
Map map = new LinkedHashMap<>();
|
||||
for (SerializedValue.O o : value.o)
|
||||
map.put(o.k, deserialize(o.v));
|
||||
return (T) map;
|
||||
}
|
||||
throw new RuntimeException("Unexpected result: " + new Gson().toJson(value));
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,13 @@ class Utils {
|
||||
return new Gson().fromJson(json, t);
|
||||
}
|
||||
|
||||
static boolean isFunctionBody(String expression) {
|
||||
expression = expression.trim();
|
||||
return expression.startsWith("function") ||
|
||||
expression.startsWith("async ") ||
|
||||
expression.contains("=>");
|
||||
}
|
||||
|
||||
static Set<Character> escapeGlobChars = new HashSet<>(Arrays.asList('/', '$', '^', '+', '.', '(', ')', '=', '!', '|'));
|
||||
|
||||
static String globToRegex(String glob) {
|
||||
@@ -83,5 +90,4 @@ class Utils {
|
||||
tokens.append('$');
|
||||
return tokens.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -196,4 +196,73 @@ public class TestPopup {
|
||||
assertEquals(mapOf("width", 600, "height", 300), size);
|
||||
assertEquals(mapOf("width", 500, "height", 400), resized);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_respect_routes_from_browser_context_with_window_open() {
|
||||
BrowserContext context = browser.newContext();
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
boolean[] intercepted = {false};
|
||||
context.route("**/empty.html", (route, request) -> {
|
||||
route.continue_();
|
||||
intercepted[0] = true;
|
||||
});
|
||||
Deferred<Page> popupEvent = page.waitForPopup();
|
||||
page.evaluate("url => window['__popup'] = window.open(url)", server.EMPTY_PAGE);
|
||||
popupEvent.get();
|
||||
assertTrue(intercepted[0]);
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void BrowserContext_addInitScript_should_apply_to_an_in_process_popup() {
|
||||
BrowserContext context = browser.newContext();
|
||||
context.addInitScript("() => window['injected'] = 123");
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Object injected = page.evaluate("() => {\n" +
|
||||
" const win = window.open('about:blank');\n" +
|
||||
" return win['injected'];\n" +
|
||||
"}");
|
||||
context.close();
|
||||
assertEquals(123, injected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void BrowserContext_addInitScript_should_apply_to_a_cross_process_popup() {
|
||||
BrowserContext context = browser.newContext();
|
||||
context.addInitScript("() => window['injected'] = 123");
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Page> popupEvent = page.waitForPopup();
|
||||
page.evaluate("url => window.open(url)", server.CROSS_PROCESS_PREFIX + "/title.html");
|
||||
Page popup = popupEvent.get();
|
||||
assertEquals(123, popup.evaluate("injected"));
|
||||
|
||||
popup.reload();
|
||||
|
||||
assertEquals(123, popup.evaluate("injected"));
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_expose_function_from_browser_context() {
|
||||
BrowserContext context = browser.newContext();
|
||||
List<String> messages = new ArrayList<>();
|
||||
context.exposeFunction("add", args -> {
|
||||
messages.add("binding");
|
||||
return (int) args[0] + (int) args[1];
|
||||
});
|
||||
Page page = context.newPage();
|
||||
// context.on("page", () => messages.push('page'));
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Object added = page.evaluate("async () => {\n" +
|
||||
" const win = window.open('about:blank');\n" +
|
||||
" return win['add'](9, 4);\n" +
|
||||
"}");
|
||||
context.close();
|
||||
assertEquals(13, added);
|
||||
// assertEquals(messages.join("|"), "page|binding");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user