fix: change listener interface, introduce event enum (#6)
This commit is contained in:
@@ -537,10 +537,8 @@ class Interface extends TypeDefinition {
|
||||
output.add("public interface " + jsonName + implementsClause + " {");
|
||||
offset = " ";
|
||||
writeSharedTypes(output, offset);
|
||||
writeEvents(output, offset);
|
||||
super.writeTo(output, offset);
|
||||
for (Event e : events) {
|
||||
e.writeTo(output, offset);
|
||||
}
|
||||
for (Method m : methods) {
|
||||
m.writeTo(output, offset);
|
||||
}
|
||||
@@ -552,7 +550,26 @@ class Interface extends TypeDefinition {
|
||||
output.add("\n");
|
||||
}
|
||||
|
||||
void writeSharedTypes(List<String> output, String offset) {
|
||||
private void writeEvents(List<String> output, String offset) {
|
||||
if (events.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
output.add(offset + "enum EventType {");
|
||||
// TODO: fix api.json to not miss this event.
|
||||
if ("Page".equals(jsonName)) {
|
||||
output.add(offset + " CLOSE,");
|
||||
}
|
||||
for (int i = 0; i < events.size(); i++) {
|
||||
String comma = i == events.size() ? "" : ",";
|
||||
output.add(offset + " " + events.get(i).jsonName.toUpperCase() + comma);
|
||||
}
|
||||
output.add(offset + "}");
|
||||
output.add("");
|
||||
output.add(offset + "void addListener(EventType type, Listener<EventType> listener);");
|
||||
output.add(offset + "void removeListener(EventType type, Listener<EventType> listener);");
|
||||
}
|
||||
|
||||
private void writeSharedTypes(List<String> output, String offset) {
|
||||
switch (jsonName) {
|
||||
case "Mouse": {
|
||||
output.add(offset + "enum Button { LEFT, MIDDLE, RIGHT }");
|
||||
|
||||
@@ -93,20 +93,12 @@ class Types {
|
||||
add("Mouse.down.options.button", "\"left\"|\"middle\"|\"right\"", "Button", new Empty());
|
||||
add("Mouse.up.options.button", "\"left\"|\"middle\"|\"right\"", "Button", new Empty());
|
||||
add("BrowserType.launchPersistentContext.options.colorScheme", "\"dark\"|\"light\"|\"no-preference\"", "ColorScheme");
|
||||
add("ChromiumBrowser.newContext.options.colorScheme", "\"dark\"|\"light\"|\"no-preference\"", "ColorScheme");
|
||||
add("ChromiumBrowser.newPage.options.colorScheme", "\"dark\"|\"light\"|\"no-preference\"", "ColorScheme");
|
||||
add("FirefoxBrowser.newContext.options.colorScheme", "\"dark\"|\"light\"|\"no-preference\"", "ColorScheme");
|
||||
add("FirefoxBrowser.newPage.options.colorScheme", "\"dark\"|\"light\"|\"no-preference\"", "ColorScheme");
|
||||
add("WebKitBrowser.newContext.options.colorScheme", "\"dark\"|\"light\"|\"no-preference\"", "ColorScheme");
|
||||
add("WebKitBrowser.newPage.options.colorScheme", "\"dark\"|\"light\"|\"no-preference\"", "ColorScheme");
|
||||
|
||||
// Route
|
||||
add("BrowserContext.route.handler", "function(Route, Request)", "BiConsumer<Route, Request>");
|
||||
add("BrowserContext.unroute.handler", "function(Route, Request)", "BiConsumer<Route, Request>");
|
||||
add("Page.route.handler", "function(Route, Request)", "BiConsumer<Route, Request>");
|
||||
add("Page.unroute.handler", "function(Route, Request)", "BiConsumer<Route, Request>");
|
||||
add("ChromiumBrowserContext.route.handler", "function(Route, Request)", "BiConsumer<Route, Request>");
|
||||
add("ChromiumBrowserContext.unroute.handler", "function(Route, Request)", "BiConsumer<Route, Request>");
|
||||
|
||||
// Viewport size.
|
||||
add("Browser.newContext.options.viewport", "null|Object", "Page.Viewport", new Empty());
|
||||
@@ -114,12 +106,6 @@ class Types {
|
||||
add("Page.setViewportSize.viewportSize", "Object", "Viewport", new Empty());
|
||||
add("Page.viewportSize", "null|Object", "Viewport", new Empty());
|
||||
add("BrowserType.launchPersistentContext.options.viewport", "null|Object", "Page.Viewport", new Empty());
|
||||
add("ChromiumBrowser.newContext.options.viewport", "null|Object", "Page.Viewport", new Empty());
|
||||
add("ChromiumBrowser.newPage.options.viewport", "null|Object", "Page.Viewport", new Empty());
|
||||
add("FirefoxBrowser.newContext.options.viewport", "null|Object", "Page.Viewport", new Empty());
|
||||
add("FirefoxBrowser.newPage.options.viewport", "null|Object", "Page.Viewport", new Empty());
|
||||
add("WebKitBrowser.newContext.options.viewport", "null|Object", "Page.Viewport", new Empty());
|
||||
add("WebKitBrowser.newPage.options.viewport", "null|Object", "Page.Viewport", new Empty());
|
||||
|
||||
// HTTP credentials.
|
||||
add("Browser.newContext.options.httpCredentials", "Object", "BrowserContext.HTTPCredentials", new Empty());
|
||||
@@ -179,8 +165,6 @@ class Types {
|
||||
add("Selectors.register.script", "function|string|Object", "String");
|
||||
add("Worker.evaluate.pageFunction", "function|string", "String");
|
||||
add("Worker.evaluateHandle.pageFunction", "function|string", "String");
|
||||
add("ChromiumBrowserContext.addInitScript.script", "function|string|Object", "String");
|
||||
|
||||
|
||||
// Return structures
|
||||
add("ConsoleMessage.location", "Object", "Location");
|
||||
@@ -204,14 +188,18 @@ class Types {
|
||||
add("BrowserContext.cookies.urls", "string|Array<string>", "String");
|
||||
add("BrowserContext.route.url", "string|RegExp|function(URL):boolean", "String");
|
||||
add("BrowserContext.unroute.url", "string|RegExp|function(URL):boolean", "String");
|
||||
add("BrowserContext.waitForEvent.event", "string", "EventType", new Empty());
|
||||
add("BrowserContext.waitForEvent.optionsOrPredicate", "Function|Object", "String");
|
||||
add("BrowserContext.waitForEvent", "Promise<Object>", "Deferred<Event<EventType>>", new Empty());
|
||||
add("Page.waitForNavigation.options.url", "string|RegExp|Function", "String");
|
||||
add("Page.frame.options", "string|Object", "FrameOptions", new Empty());
|
||||
add("Page.route.url", "string|RegExp|function(URL):boolean", "String");
|
||||
add("Page.selectOption.values", "null|string|ElementHandle|Array<string>|Object|Array<ElementHandle>|Array<Object>", "String");
|
||||
add("Page.setInputFiles.files", "string|Array<string>|Object|Array<Object>", "String");
|
||||
add("Page.unroute.url", "string|RegExp|function(URL):boolean", "String");
|
||||
add("Page.waitForEvent.event", "string", "EventType", new Empty());
|
||||
add("Page.waitForEvent.optionsOrPredicate", "Function|Object", "String");
|
||||
add("Page.waitForEvent", "Promise<Object>", "Deferred<Event<EventType>>", new Empty());
|
||||
add("Page.waitForRequest.urlOrPredicate", "string|RegExp|Function", "String");
|
||||
add("Page.waitForResponse.urlOrPredicate", "string|RegExp|Function", "String");
|
||||
add("Frame.waitForNavigation.options.url", "string|RegExp|Function", "String");
|
||||
@@ -231,10 +219,6 @@ class Types {
|
||||
add("BrowserType.launchServer.options.firefoxUserPrefs", "Object<string, string|number|boolean>", "String");
|
||||
add("BrowserType.launchServer.options.env", "Object<string, string|number|boolean>", "String");
|
||||
add("Logger.log.message", "string|Error", "String");
|
||||
add("ChromiumBrowserContext.cookies.urls", "string|Array<string>", "String");
|
||||
add("ChromiumBrowserContext.route.url", "string|RegExp|function(URL):boolean", "String");
|
||||
add("ChromiumBrowserContext.unroute.url", "string|RegExp|function(URL):boolean", "String");
|
||||
add("ChromiumBrowserContext.waitForEvent.optionsOrPredicate", "Function|Object", "String");
|
||||
|
||||
add("Browser.newContext.options.geolocation.latitude", "number", "double");
|
||||
add("Browser.newContext.options.geolocation.longitude", "number", "double");
|
||||
@@ -245,24 +229,6 @@ class Types {
|
||||
add("BrowserType.launchPersistentContext.options.geolocation.latitude", "number", "double");
|
||||
add("BrowserType.launchPersistentContext.options.geolocation.longitude", "number", "double");
|
||||
add("BrowserType.launchPersistentContext.options.geolocation.accuracy", "number", "double");
|
||||
add("ChromiumBrowser.newContext.options.geolocation.latitude", "number", "double");
|
||||
add("ChromiumBrowser.newContext.options.geolocation.longitude", "number", "double");
|
||||
add("ChromiumBrowser.newContext.options.geolocation.accuracy", "number", "double");
|
||||
add("ChromiumBrowser.newPage.options.geolocation.latitude", "number", "double");
|
||||
add("ChromiumBrowser.newPage.options.geolocation.longitude", "number", "double");
|
||||
add("ChromiumBrowser.newPage.options.geolocation.accuracy", "number", "double");
|
||||
add("FirefoxBrowser.newContext.options.geolocation.latitude", "number", "double");
|
||||
add("FirefoxBrowser.newContext.options.geolocation.longitude", "number", "double");
|
||||
add("FirefoxBrowser.newContext.options.geolocation.accuracy", "number", "double");
|
||||
add("FirefoxBrowser.newPage.options.geolocation.latitude", "number", "double");
|
||||
add("FirefoxBrowser.newPage.options.geolocation.longitude", "number", "double");
|
||||
add("FirefoxBrowser.newPage.options.geolocation.accuracy", "number", "double");
|
||||
add("WebKitBrowser.newContext.options.geolocation.latitude", "number", "double");
|
||||
add("WebKitBrowser.newContext.options.geolocation.longitude", "number", "double");
|
||||
add("WebKitBrowser.newContext.options.geolocation.accuracy", "number", "double");
|
||||
add("WebKitBrowser.newPage.options.geolocation.latitude", "number", "double");
|
||||
add("WebKitBrowser.newPage.options.geolocation.longitude", "number", "double");
|
||||
add("WebKitBrowser.newPage.options.geolocation.accuracy", "number", "double");
|
||||
|
||||
add("BrowserContext.setGeolocation.geolocation", "null|Object", "Geolocation");
|
||||
|
||||
@@ -282,7 +248,6 @@ class Types {
|
||||
|
||||
// JSON type
|
||||
add("BrowserContext.addInitScript.arg", "Serializable", "Object");
|
||||
add("ChromiumBrowserContext.addInitScript.arg", "Serializable", "Object");
|
||||
add("Page.$eval", "Promise<Serializable>", "Object");
|
||||
add("Page.$$eval", "Promise<Serializable>", "Object");
|
||||
add("Page.addInitScript.arg", "Serializable", "Object");
|
||||
|
||||
@@ -19,6 +19,12 @@ package com.microsoft.playwright;
|
||||
import java.util.*;
|
||||
|
||||
public interface Browser {
|
||||
enum EventType {
|
||||
DISCONNECTED,
|
||||
}
|
||||
|
||||
void addListener(EventType type, Listener<EventType> listener);
|
||||
void removeListener(EventType type, Listener<EventType> listener);
|
||||
class NewContextOptions {
|
||||
public enum ColorScheme { DARK, LIGHT, NO_PREFERENCE }
|
||||
public class Geolocation {
|
||||
|
||||
@@ -40,6 +40,12 @@ public interface BrowserContext {
|
||||
}
|
||||
}
|
||||
|
||||
enum EventType {
|
||||
PAGE,
|
||||
}
|
||||
|
||||
void addListener(EventType type, Listener<EventType> listener);
|
||||
void removeListener(EventType type, Listener<EventType> listener);
|
||||
class GrantPermissionsOptions {
|
||||
public String origin;
|
||||
|
||||
@@ -66,7 +72,6 @@ public interface BrowserContext {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
Deferred<Page> waitForPage();
|
||||
void close();
|
||||
void addCookies(List<Object> cookies);
|
||||
default void addInitScript(String script) {
|
||||
@@ -103,9 +108,9 @@ public interface BrowserContext {
|
||||
void unroute(String url, BiConsumer<Route, Request> handler);
|
||||
void unroute(Pattern url, BiConsumer<Route, Request> handler);
|
||||
void unroute(Predicate<String> url, BiConsumer<Route, Request> handler);
|
||||
default Object waitForEvent(String event) {
|
||||
default Deferred<Event<EventType>> waitForEvent(EventType event) {
|
||||
return waitForEvent(event, null);
|
||||
}
|
||||
Object waitForEvent(String event, String optionsOrPredicate);
|
||||
Deferred<Event<EventType>> waitForEvent(EventType event, String optionsOrPredicate);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,13 @@ package com.microsoft.playwright;
|
||||
import java.util.*;
|
||||
|
||||
public interface ChromiumBrowserContext extends BrowserContext {
|
||||
enum EventType {
|
||||
BACKGROUNDPAGE,
|
||||
SERVICEWORKER,
|
||||
}
|
||||
|
||||
void addListener(EventType type, Listener<EventType> listener);
|
||||
void removeListener(EventType type, Listener<EventType> listener);
|
||||
List<Page> backgroundPages();
|
||||
CDPSession newCDPSession(Page page);
|
||||
List<Worker> serviceWorkers();
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
public interface Event<EventType> {
|
||||
EventType type();
|
||||
Object data();
|
||||
}
|
||||
@@ -16,6 +16,6 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
public interface Listener<T> {
|
||||
void handle(T event);
|
||||
public interface Listener<EventType> {
|
||||
void handle(Event<EventType> event);
|
||||
}
|
||||
|
||||
@@ -78,6 +78,29 @@ public interface Page {
|
||||
}
|
||||
}
|
||||
|
||||
enum EventType {
|
||||
CLOSE,
|
||||
CONSOLE,
|
||||
CRASH,
|
||||
DIALOG,
|
||||
DOMCONTENTLOADED,
|
||||
DOWNLOAD,
|
||||
FILECHOOSER,
|
||||
FRAMEATTACHED,
|
||||
FRAMEDETACHED,
|
||||
FRAMENAVIGATED,
|
||||
LOAD,
|
||||
PAGEERROR,
|
||||
POPUP,
|
||||
REQUEST,
|
||||
REQUESTFAILED,
|
||||
REQUESTFINISHED,
|
||||
RESPONSE,
|
||||
WORKER,
|
||||
}
|
||||
|
||||
void addListener(EventType type, Listener<EventType> listener);
|
||||
void removeListener(EventType type, Listener<EventType> listener);
|
||||
enum LoadState { DOMCONTENTLOADED, LOAD, NETWORKIDLE }
|
||||
class CloseOptions {
|
||||
public Boolean runBeforeUnload;
|
||||
@@ -767,11 +790,6 @@ public interface Page {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
void addConsoleListener(Listener<ConsoleMessage> listener);
|
||||
void removeConsoleListener(Listener<ConsoleMessage> listener);
|
||||
void addDialogListener(Listener<Dialog> listener);
|
||||
void removeDialogListener(Listener<Dialog> listener);
|
||||
Deferred<Page> waitForPopup();
|
||||
default void close() {
|
||||
close(null);
|
||||
}
|
||||
@@ -926,10 +944,10 @@ public interface Page {
|
||||
void unroute(Predicate<String> url, BiConsumer<Route, Request> handler);
|
||||
String url();
|
||||
Viewport viewportSize();
|
||||
default Object waitForEvent(String event) {
|
||||
default Deferred<Event<EventType>> waitForEvent(EventType event) {
|
||||
return waitForEvent(event, null);
|
||||
}
|
||||
Object waitForEvent(String event, String optionsOrPredicate);
|
||||
Deferred<Event<EventType>> waitForEvent(EventType event, String optionsOrPredicate);
|
||||
default JSHandle waitForFunction(String pageFunction, Object arg) {
|
||||
return waitForFunction(pageFunction, arg, null);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,12 @@ package com.microsoft.playwright;
|
||||
import java.util.*;
|
||||
|
||||
public interface Worker {
|
||||
enum EventType {
|
||||
CLOSE,
|
||||
}
|
||||
|
||||
void addListener(EventType type, Listener<EventType> listener);
|
||||
void removeListener(EventType type, Listener<EventType> listener);
|
||||
default Object evaluate(String pageFunction) {
|
||||
return evaluate(pageFunction, null);
|
||||
}
|
||||
|
||||
@@ -38,12 +38,23 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
private boolean isClosedOrClosing;
|
||||
final Map<String, Page.Binding> bindings = new HashMap<String, Page.Binding>();
|
||||
PageImpl ownerPage;
|
||||
private final ListenerCollection<EventType> listeners = new ListenerCollection<>();
|
||||
|
||||
protected BrowserContextImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
browser = (BrowserImpl) parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(EventType type, Listener<EventType> listener) {
|
||||
listeners.add(type, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(EventType type, Listener<EventType> listener) {
|
||||
listeners.remove(type, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (isClosedOrClosing) {
|
||||
@@ -203,6 +214,11 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
unroute(new UrlMatcher(url), handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Deferred<Event<EventType>> waitForEvent(EventType event, String optionsOrPredicate) {
|
||||
return listeners.waitForEvent(event, connection);
|
||||
}
|
||||
|
||||
private void unroute(UrlMatcher matcher, BiConsumer<Route, Request> handler) {
|
||||
routes.remove(matcher, handler);
|
||||
if (routes.size() == 0) {
|
||||
@@ -212,12 +228,6 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object waitForEvent(String event, String optionsOrPredicate) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Deferred<Page> waitForPage() {
|
||||
CompletableFuture<JsonObject> pageFuture = futureForEvent("page");
|
||||
return () -> {
|
||||
@@ -238,6 +248,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
}
|
||||
} else if ("page".equals(event)) {
|
||||
PageImpl page = connection.getExistingObject(params.getAsJsonObject("page").get("guid").getAsString());
|
||||
listeners.notify(EventType.PAGE, page);
|
||||
pages.add(page);
|
||||
} else if ("bindingCall".equals(event)) {
|
||||
BindingCall bindingCall = connection.getExistingObject(params.getAsJsonObject("binding").get("guid").getAsString());
|
||||
|
||||
@@ -20,10 +20,7 @@ import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.Browser;
|
||||
import com.microsoft.playwright.BrowserContext;
|
||||
import com.microsoft.playwright.Deferred;
|
||||
import com.microsoft.playwright.Page;
|
||||
import com.microsoft.playwright.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -31,11 +28,22 @@ import static com.microsoft.playwright.impl.Utils.convertViaJson;
|
||||
|
||||
class BrowserImpl extends ChannelOwner implements Browser {
|
||||
final Set<BrowserContext> contexts = new HashSet<>();
|
||||
private final ListenerCollection<EventType> listeners = new ListenerCollection<>();
|
||||
|
||||
BrowserImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(EventType type, Listener<EventType> listener) {
|
||||
listeners.add(type, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(EventType type, Listener<EventType> listener) {
|
||||
listeners.remove(type, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
sendMessage("close", new JsonObject());
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* 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.microsoft.playwright.Deferred;
|
||||
import com.microsoft.playwright.Event;
|
||||
import com.microsoft.playwright.Listener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
class ListenerCollection <EventType> {
|
||||
private final HashMap<EventType, List<Listener<EventType>>> listeners = new HashMap<>();
|
||||
|
||||
void notify(EventType eventType, Object param) {
|
||||
List<Listener<EventType>> list = listeners.get(eventType);
|
||||
if (list == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Event event = new Event() {
|
||||
@Override
|
||||
public EventType type() {
|
||||
return eventType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object data() {
|
||||
return param;
|
||||
}
|
||||
};
|
||||
|
||||
for (Listener<EventType> listener: new ArrayList<>(list)) {
|
||||
listener.handle(event);
|
||||
}
|
||||
}
|
||||
|
||||
void add(EventType type, Listener listener) {
|
||||
List<Listener<EventType>> list = listeners.get(type);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
listeners.put(type, list);
|
||||
}
|
||||
list.add(listener);
|
||||
}
|
||||
|
||||
void remove(EventType type, Listener listener) {
|
||||
List<Listener<EventType>> list = listeners.get(type);
|
||||
if (list == null) {
|
||||
return;
|
||||
}
|
||||
list.removeAll(Collections.singleton(listener));
|
||||
if (list.isEmpty()) {
|
||||
listeners.remove(type);
|
||||
}
|
||||
}
|
||||
|
||||
private class DeferredEvent implements Listener<EventType>, Deferred<Event<EventType>> {
|
||||
private final EventType type;
|
||||
private final Connection connection;
|
||||
private Event event;
|
||||
|
||||
DeferredEvent(EventType type, Connection connection) {
|
||||
add(type, this);
|
||||
this.type = type;
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Event e) {
|
||||
event = e;
|
||||
remove(type, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event get() {
|
||||
while (event == null) {
|
||||
connection.processOneMessage();
|
||||
}
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
||||
Deferred<Event<EventType>> waitForEvent(EventType event, Connection connection) {
|
||||
return new DeferredEvent(event, connection);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -39,9 +39,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
private final Router routes = new Router();
|
||||
// TODO: do not rely on the frame order in the tests
|
||||
private final Set<FrameImpl> frames = new LinkedHashSet<>();
|
||||
private final List<Listener<ConsoleMessage>> consoleListeners = new ArrayList<>();
|
||||
private final List<Listener<Dialog>> dialogListeners = new ArrayList<>();
|
||||
private final List<Listener<Page>> closeListeners = new ArrayList<>();
|
||||
private final ListenerCollection<EventType> listeners = new ListenerCollection<>();
|
||||
private final List<WaitEventHelper> eventHelpers = new ArrayList<>();
|
||||
final Map<String, Binding> bindings = new HashMap<String, Binding>();
|
||||
BrowserContextImpl ownedContext;
|
||||
@@ -57,35 +55,6 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
frames.add(mainFrame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addConsoleListener(Listener<ConsoleMessage> listener) {
|
||||
consoleListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeConsoleListener(Listener<ConsoleMessage> listener) {
|
||||
consoleListeners.remove(listener);
|
||||
}
|
||||
|
||||
public void addCloseListener(Listener<Page> listener) {
|
||||
closeListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeCloseListener(Listener<Page> listener) {
|
||||
closeListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDialogListener(Listener<Dialog> listener) {
|
||||
dialogListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeDialogListener(Listener<Dialog> listener) {
|
||||
dialogListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Deferred<Page> waitForPopup() {
|
||||
CompletableFuture<JsonObject> popupFuture = futureForEvent("popup");
|
||||
return () -> {
|
||||
@@ -95,25 +64,23 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
};
|
||||
}
|
||||
|
||||
private static <T> void notifyListeners(List<Listener<T>> listeners, T subject) {
|
||||
for (Listener<T> listener: new ArrayList<>(listeners)) {
|
||||
listener.handle(subject);
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleEvent(String event, JsonObject params) {
|
||||
if ("dialog".equals(event)) {
|
||||
String guid = params.getAsJsonObject("dialog").get("guid").getAsString();
|
||||
DialogImpl dialog = connection.getExistingObject(guid);
|
||||
notifyListeners(dialogListeners, dialog);
|
||||
listeners.notify(EventType.DIALOG, dialog);
|
||||
// If no action taken dismiss dialog to not hang.
|
||||
if (!dialog.isHandled()) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
} else if ("popup".equals(event)) {
|
||||
String guid = params.getAsJsonObject("page").get("guid").getAsString();
|
||||
PageImpl popup = connection.getExistingObject(guid);
|
||||
listeners.notify(EventType.POPUP, popup);
|
||||
} else if ("console".equals(event)) {
|
||||
String guid = params.getAsJsonObject("message").get("guid").getAsString();
|
||||
ConsoleMessageImpl message = connection.getExistingObject(guid);
|
||||
notifyListeners(consoleListeners, message);
|
||||
listeners.notify(EventType.CONSOLE, message);
|
||||
} else if ("frameAttached".equals(event)) {
|
||||
String guid = params.getAsJsonObject("frame").get("guid").getAsString();
|
||||
FrameImpl frame = connection.getExistingObject(guid);
|
||||
@@ -122,6 +89,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
if (frame.parentFrame != null) {
|
||||
frame.parentFrame.childFrames.add(frame);
|
||||
}
|
||||
listeners.notify(EventType.FRAMEATTACHED, frame);
|
||||
} else if ("frameDetached".equals(event)) {
|
||||
String guid = params.getAsJsonObject("frame").get("guid").getAsString();
|
||||
FrameImpl frame = connection.getExistingObject(guid);
|
||||
@@ -130,6 +98,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
if (frame.parentFrame != null) {
|
||||
frame.parentFrame.childFrames.remove(frame);
|
||||
}
|
||||
listeners.notify(EventType.FRAMEDETACHED, frame);
|
||||
} else if ("route".equals(event)) {
|
||||
Route route = connection.getExistingObject(params.getAsJsonObject("route").get("guid").getAsString());
|
||||
Request request = connection.getExistingObject(params.getAsJsonObject("request").get("guid").getAsString());
|
||||
@@ -143,13 +112,23 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
} else if ("close".equals(event)) {
|
||||
isClosed = true;
|
||||
browserContext.pages.remove(this);
|
||||
notifyListeners(closeListeners, this);
|
||||
listeners.notify(EventType.CLOSE, this);
|
||||
}
|
||||
for (WaitEventHelper h : new ArrayList<>(eventHelpers)) {
|
||||
h.handleEvent(event, params);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(EventType type, Listener<EventType> listener) {
|
||||
listeners.add(type, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(EventType type, Listener<EventType> listener) {
|
||||
listeners.remove(type, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(CloseOptions options) {
|
||||
JsonObject params = options == null ? new JsonObject() : new Gson().toJsonTree(options).getAsJsonObject();
|
||||
@@ -512,9 +491,8 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object waitForEvent(String event, String optionsOrPredicate) {
|
||||
// TODO: do we want to keep this method ?
|
||||
return null;
|
||||
public Deferred<Event<EventType>> waitForEvent(EventType event, String optionsOrPredicate) {
|
||||
return listeners.waitForEvent(event, connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.util.List;
|
||||
|
||||
import static com.microsoft.playwright.Keyboard.Modifier.SHIFT;
|
||||
import static com.microsoft.playwright.Mouse.Button.RIGHT;
|
||||
import static com.microsoft.playwright.Page.EventType.CONSOLE;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestClick {
|
||||
@@ -172,7 +173,7 @@ public class TestClick {
|
||||
void shouldClickOffscreenButtons() {
|
||||
page.navigate(server.PREFIX + "/offscreenbuttons.html");
|
||||
List<String> messages = new ArrayList<>();
|
||||
page.addConsoleListener(msg -> messages.add(msg.text()));
|
||||
page.addListener(CONSOLE, event -> messages.add(((ConsoleMessage) event.data()).text()));
|
||||
for (int i = 0; i < 11; ++i) {
|
||||
// We might've scrolled to click a button - reset to (0, 0).
|
||||
page.evaluate("() => window.scrollTo(0, 0)");
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.junit.jupiter.api.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static com.microsoft.playwright.Page.EventType.DIALOG;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
@@ -64,7 +65,8 @@ public class TestDialog {
|
||||
|
||||
@Test
|
||||
void shouldFire() {
|
||||
page.addDialogListener(dialog -> {
|
||||
page.addListener(DIALOG, event -> {
|
||||
Dialog dialog = (Dialog) event.data();
|
||||
assertEquals( "alert", dialog.type());
|
||||
assertEquals( "", dialog.defaultValue());
|
||||
assertEquals( "yo", dialog.message());
|
||||
@@ -75,7 +77,8 @@ public class TestDialog {
|
||||
|
||||
@Test
|
||||
void shouldAllowAcceptingPrompts() {
|
||||
page.addDialogListener(dialog -> {
|
||||
page.addListener(DIALOG, event -> {
|
||||
Dialog dialog = (Dialog) event.data();
|
||||
assertEquals("prompt", dialog.type());
|
||||
assertEquals("yes.", dialog.defaultValue());
|
||||
assertEquals("question?", dialog.message());
|
||||
@@ -87,7 +90,8 @@ public class TestDialog {
|
||||
|
||||
@Test
|
||||
void shouldDismissThePrompt() {
|
||||
page.addDialogListener(dialog -> {
|
||||
page.addListener(DIALOG, event -> {
|
||||
Dialog dialog = (Dialog) event.data();
|
||||
dialog.dismiss();
|
||||
});
|
||||
Object result = page.evaluate("() => prompt('question?')");
|
||||
@@ -96,7 +100,8 @@ public class TestDialog {
|
||||
|
||||
@Test
|
||||
void shouldAcceptTheConfirmPrompt() {
|
||||
page.addDialogListener(dialog -> {
|
||||
page.addListener(DIALOG, event -> {
|
||||
Dialog dialog = (Dialog) event.data();
|
||||
dialog.accept();
|
||||
});
|
||||
Object result = page.evaluate("() => confirm('boolean?')");
|
||||
@@ -105,7 +110,8 @@ public class TestDialog {
|
||||
|
||||
@Test
|
||||
void shouldDismissTheConfirmPrompt() {
|
||||
page.addDialogListener(dialog -> {
|
||||
page.addListener(DIALOG, event -> {
|
||||
Dialog dialog = (Dialog) event.data();
|
||||
dialog.dismiss();
|
||||
});
|
||||
Object result = page.evaluate("() => confirm('boolean?')");
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.microsoft.playwright.Page.EventType.*;
|
||||
import static com.microsoft.playwright.Page.LoadState.DOMCONTENTLOADED;
|
||||
import static com.microsoft.playwright.Page.LoadState.LOAD;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
@@ -100,8 +101,9 @@ public class TestPageBasic {
|
||||
// fire.
|
||||
newPage.click("body");
|
||||
boolean[] didShowDialog = {false};
|
||||
newPage.addDialogListener(dialog -> {
|
||||
newPage.addListener(DIALOG, event -> {
|
||||
didShowDialog[0] = true;
|
||||
Dialog dialog = (Dialog) event.data();
|
||||
assertEquals("beforeunload", dialog.type());
|
||||
assertEquals("", dialog.defaultValue());
|
||||
if (isChromium) {
|
||||
@@ -126,7 +128,7 @@ public class TestPageBasic {
|
||||
// fire.
|
||||
newPage.click("body");
|
||||
boolean[] didShowDialog = {false};
|
||||
newPage.addDialogListener(dialog -> didShowDialog[0] = true);
|
||||
newPage.addListener(DIALOG, event -> didShowDialog[0] = true);
|
||||
newPage.close();
|
||||
assertFalse(didShowDialog[0]);
|
||||
}
|
||||
@@ -181,17 +183,18 @@ public class TestPageBasic {
|
||||
|
||||
@Test
|
||||
void shouldProvideAccessToTheOpenerPage() {
|
||||
Deferred<Page> popupEvent = page.waitForPopup();
|
||||
Deferred<Event<Page.EventType>> popupEvent = page.waitForEvent(POPUP);
|
||||
page.evaluate("() => window.open('about:blank')");
|
||||
Page opener = popupEvent.get().opener();
|
||||
Page popup = (Page) popupEvent.get().data();
|
||||
Page opener = popup.opener();
|
||||
assertEquals(page, opener);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnNullIfParentPageHasBeenClosed() {
|
||||
Deferred<Page> popupEvent = page.waitForPopup();
|
||||
Deferred<Event<Page.EventType>> popupEvent = page.waitForEvent(POPUP);
|
||||
page.evaluate("() => window.open('about:blank')");
|
||||
Page popup = popupEvent.get();
|
||||
Page popup = (Page) popupEvent.get().data();
|
||||
page.close();
|
||||
Page opener = popup.opener();
|
||||
assertEquals(null, opener);
|
||||
@@ -232,9 +235,9 @@ public class TestPageBasic {
|
||||
|
||||
@Test
|
||||
void pageCloseShouldWorkWithWindowClose() {
|
||||
Deferred<Page> newPagePromise = page.waitForPopup();
|
||||
Deferred<Event<Page.EventType>> newPagePromise = page.waitForEvent(POPUP);
|
||||
page.evaluate("() => window['newPage'] = window.open('about:blank')");
|
||||
Page newPage = newPagePromise.get();
|
||||
Page newPage = (Page) newPagePromise.get().data();
|
||||
Deferred<Void> closedPromise = newPage.waitForClose();
|
||||
page.evaluate("() => window['newPage'].close()");
|
||||
closedPromise.get();
|
||||
@@ -310,7 +313,7 @@ public class TestPageBasic {
|
||||
void pagePressShouldWorkForEnter() {
|
||||
page.setContent("<input onkeypress='console.log(\"press\")'></input>");
|
||||
List<ConsoleMessage> messages = new ArrayList<>();
|
||||
page.addConsoleListener(message -> messages.add(message));
|
||||
page.addListener(CONSOLE, event -> messages.add((ConsoleMessage) event.data()));
|
||||
page.press("input", "Enter");
|
||||
assertEquals("press", messages.get(0).text());
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.*;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import static com.microsoft.playwright.Page.EventType.POPUP;
|
||||
import static com.microsoft.playwright.Page.LoadState.DOMCONTENTLOADED;
|
||||
import static com.microsoft.playwright.Utils.mapOf;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
@@ -73,9 +74,9 @@ public class TestPopup {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
page.setContent("<a target=_blank rel=noopener href='/popup/popup.html'>link</a>");
|
||||
Future<Server.Request> requestPromise = server.waitForRequest("/popup/popup.html");
|
||||
Deferred<Page> popupPromise = context.waitForPage();
|
||||
Deferred<Event<BrowserContext.EventType>> popupEvent = context.waitForEvent(BrowserContext.EventType.PAGE);
|
||||
page.click("a");
|
||||
Page popup = popupPromise.get();
|
||||
Page popup = (Page) popupEvent.get().data();
|
||||
popup.waitForLoadState(DOMCONTENTLOADED);
|
||||
String userAgent = (String) popup.evaluate("() => window['initialUserAgent']");
|
||||
Server.Request request = requestPromise.get();
|
||||
@@ -95,7 +96,7 @@ public class TestPopup {
|
||||
route.continue_();
|
||||
intercepted[0] = true;
|
||||
});
|
||||
Deferred<Page> popup = context.waitForPage();
|
||||
Deferred<Event<BrowserContext.EventType>> popup = context.waitForEvent(BrowserContext.EventType.PAGE);
|
||||
page.click("a");
|
||||
popup.get();
|
||||
|
||||
@@ -137,10 +138,11 @@ public class TestPopup {
|
||||
.withHttpCredentials("user", "pass"));
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Page> popup = page.waitForPopup();
|
||||
Deferred<Event<Page.EventType>> popupEvent = page.waitForEvent(POPUP);
|
||||
page.evaluate("url => window['_popup'] = window.open(url)", server.PREFIX + "/title.html");
|
||||
popup.get().waitForLoadState(DOMCONTENTLOADED);
|
||||
assertEquals("Woof-Woof", popup.get().title());
|
||||
Page popup = (Page) popupEvent.get().data();
|
||||
popup.waitForLoadState(DOMCONTENTLOADED);
|
||||
assertEquals("Woof-Woof", popup.title());
|
||||
context.close();
|
||||
}
|
||||
|
||||
@@ -179,12 +181,12 @@ public class TestPopup {
|
||||
.withViewport(700, 700));
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Page> popupEvent = page.waitForPopup();
|
||||
Deferred<Event<Page.EventType>> popupEvent = page.waitForEvent(POPUP);
|
||||
Object size = page.evaluate("() => {\n" +
|
||||
" const win = window.open(window.location.href, 'Title', 'toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=600,height=300,top=0,left=0');\n" +
|
||||
" return { width: win.innerWidth, height: win.innerHeight };\n" +
|
||||
"}");
|
||||
Page popup = popupEvent.get();
|
||||
Page popup = (Page) popupEvent.get().data();
|
||||
popup.setViewportSize(500, 400);
|
||||
popup.waitForLoadState();
|
||||
Object resized = popup.evaluate("() => ({ width: window.innerWidth, height: window.innerHeight })");
|
||||
@@ -203,7 +205,7 @@ public class TestPopup {
|
||||
route.continue_();
|
||||
intercepted[0] = true;
|
||||
});
|
||||
Deferred<Page> popupEvent = page.waitForPopup();
|
||||
Deferred<Event<Page.EventType>> popupEvent = page.waitForEvent(POPUP);
|
||||
page.evaluate("url => window['__popup'] = window.open(url)", server.EMPTY_PAGE);
|
||||
popupEvent.get();
|
||||
assertTrue(intercepted[0]);
|
||||
@@ -230,9 +232,9 @@ public class TestPopup {
|
||||
context.addInitScript("() => window['injected'] = 123");
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Page> popupEvent = page.waitForPopup();
|
||||
Deferred<Event<Page.EventType>> popupEvent = page.waitForEvent(POPUP);
|
||||
page.evaluate("url => window.open(url)", server.CROSS_PROCESS_PREFIX + "/title.html");
|
||||
Page popup = popupEvent.get();
|
||||
Page popup = (Page) popupEvent.get().data();
|
||||
assertEquals(123, popup.evaluate("injected"));
|
||||
|
||||
popup.reload();
|
||||
|
||||
Reference in New Issue
Block a user