fix(api): delete Deferred interface, use waitFor* with callback (#218)
This commit is contained in:
@@ -54,6 +54,11 @@ public interface Browser {
|
||||
|
||||
void addListener(EventType type, Listener<EventType> listener);
|
||||
void removeListener(EventType type, Listener<EventType> listener);
|
||||
|
||||
void onDisconnected(Runnable handler);
|
||||
void offDisconnected(Runnable handler);
|
||||
|
||||
|
||||
class NewContextOptions {
|
||||
public class Proxy {
|
||||
/**
|
||||
|
||||
@@ -94,19 +94,6 @@ public interface BrowserContext {
|
||||
}
|
||||
}
|
||||
|
||||
class FutureEventOptions {
|
||||
public Double timeout;
|
||||
public Predicate<Event<EventType>> predicate;
|
||||
public FutureEventOptions withTimeout(double millis) {
|
||||
timeout = millis;
|
||||
return this;
|
||||
}
|
||||
public FutureEventOptions withPredicate(Predicate<Event<EventType>> predicate) {
|
||||
this.predicate = predicate;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
enum EventType {
|
||||
CLOSE,
|
||||
PAGE,
|
||||
@@ -114,6 +101,24 @@ public interface BrowserContext {
|
||||
|
||||
void addListener(EventType type, Listener<EventType> listener);
|
||||
void removeListener(EventType type, Listener<EventType> listener);
|
||||
|
||||
void onClose(Runnable handler);
|
||||
void offClose(Runnable handler);
|
||||
|
||||
void onPage(Consumer<Page> handler);
|
||||
void offPage(Consumer<Page> handler);
|
||||
|
||||
|
||||
class WaitForPageOptions {
|
||||
public Double timeout;
|
||||
public WaitForPageOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
Page waitForPage(Runnable code, WaitForPageOptions options);
|
||||
default Page waitForPage(Runnable code) { return waitForPage(code, null); }
|
||||
|
||||
class AddCookie {
|
||||
/**
|
||||
* **required**
|
||||
@@ -465,21 +470,5 @@ public interface BrowserContext {
|
||||
* @param handler Optional handler function used to register a routing with [{@code method: BrowserContext.route}].
|
||||
*/
|
||||
void unroute(Predicate<String> url, Consumer<Route> handler);
|
||||
default Deferred<Event<EventType>> futureEvent(EventType event) {
|
||||
return futureEvent(event, (FutureEventOptions) null);
|
||||
}
|
||||
default Deferred<Event<EventType>> futureEvent(EventType event, Predicate<Event<EventType>> predicate) {
|
||||
FutureEventOptions options = new FutureEventOptions();
|
||||
options.predicate = predicate;
|
||||
return futureEvent(event, options);
|
||||
}
|
||||
/**
|
||||
* Waits for event to fire and passes its value into the predicate function. Returns when the predicate returns truthy
|
||||
* value. Will throw an error if the context closes before the event is fired. Returns the event data value.
|
||||
*
|
||||
*
|
||||
* @param event Event name, same one would pass into {@code browserContext.on(event)}.
|
||||
*/
|
||||
Deferred<Event<EventType>> futureEvent(EventType event, FutureEventOptions options);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* 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 Deferred<T> {
|
||||
T get();
|
||||
}
|
||||
@@ -705,7 +705,7 @@ public interface Frame {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class FutureNavigationOptions {
|
||||
class WaitForNavigationOptions {
|
||||
/**
|
||||
* Maximum operation time in milliseconds, defaults to 30 seconds, pass {@code 0} to disable timeout. The default value can be
|
||||
* changed by using the [{@code method: BrowserContext.setDefaultNavigationTimeout}],
|
||||
@@ -727,23 +727,23 @@ public interface Frame {
|
||||
*/
|
||||
public LoadState waitUntil;
|
||||
|
||||
public FutureNavigationOptions withTimeout(double timeout) {
|
||||
public WaitForNavigationOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
public FutureNavigationOptions withUrl(String glob) {
|
||||
public WaitForNavigationOptions withUrl(String glob) {
|
||||
this.glob = glob;
|
||||
return this;
|
||||
}
|
||||
public FutureNavigationOptions withUrl(Pattern pattern) {
|
||||
public WaitForNavigationOptions withUrl(Pattern pattern) {
|
||||
this.pattern = pattern;
|
||||
return this;
|
||||
}
|
||||
public FutureNavigationOptions withUrl(Predicate<String> predicate) {
|
||||
public WaitForNavigationOptions withUrl(Predicate<String> predicate) {
|
||||
this.predicate = predicate;
|
||||
return this;
|
||||
}
|
||||
public FutureNavigationOptions withWaitUntil(LoadState waitUntil) {
|
||||
public WaitForNavigationOptions withWaitUntil(LoadState waitUntil) {
|
||||
this.waitUntil = waitUntil;
|
||||
return this;
|
||||
}
|
||||
@@ -1338,9 +1338,7 @@ public interface Frame {
|
||||
* - {@code 'networkidle'} - wait until there are no network connections for at least {@code 500} ms.
|
||||
*/
|
||||
void waitForLoadState(LoadState state, WaitForLoadStateOptions options);
|
||||
default Deferred<Response> futureNavigation() {
|
||||
return futureNavigation(null);
|
||||
}
|
||||
default Response waitForNavigation(Runnable code) { return waitForNavigation(code, null); }
|
||||
/**
|
||||
* Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the
|
||||
* last redirect. In case of navigation to a different anchor or navigation due to History API usage, the navigation will
|
||||
@@ -1352,7 +1350,7 @@ public interface Frame {
|
||||
* <p> <strong>NOTE</strong> Usage of the [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API) to change the URL is
|
||||
* considered a navigation.
|
||||
*/
|
||||
Deferred<Response> futureNavigation(FutureNavigationOptions options);
|
||||
Response waitForNavigation(Runnable code, WaitForNavigationOptions options);
|
||||
default ElementHandle waitForSelector(String selector) {
|
||||
return waitForSelector(selector, null);
|
||||
}
|
||||
|
||||
@@ -74,19 +74,6 @@ public interface Page {
|
||||
String stack();
|
||||
}
|
||||
|
||||
class FutureEventOptions {
|
||||
public Double timeout;
|
||||
public Predicate<Event<EventType>> predicate;
|
||||
public FutureEventOptions withTimeout(double millis) {
|
||||
timeout = millis;
|
||||
return this;
|
||||
}
|
||||
public FutureEventOptions withPredicate(Predicate<Event<EventType>> predicate) {
|
||||
this.predicate = predicate;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
enum EventType {
|
||||
CLOSE,
|
||||
CONSOLE,
|
||||
@@ -111,6 +98,195 @@ public interface Page {
|
||||
|
||||
void addListener(EventType type, Listener<EventType> listener);
|
||||
void removeListener(EventType type, Listener<EventType> listener);
|
||||
|
||||
void onClose(Runnable handler);
|
||||
void offClose(Runnable handler);
|
||||
|
||||
void onConsole(Consumer<ConsoleMessage> handler);
|
||||
void offConsole(Consumer<ConsoleMessage> handler);
|
||||
|
||||
void onCrash(Runnable handler);
|
||||
void offCrash(Runnable handler);
|
||||
|
||||
void onDialog(Consumer<Dialog> handler);
|
||||
void offDialog(Consumer<Dialog> handler);
|
||||
|
||||
void onDomContentLoaded(Runnable handler);
|
||||
void offDomContentLoaded(Runnable handler);
|
||||
|
||||
void onDownload(Consumer<Download> handler);
|
||||
void offDownload(Consumer<Download> handler);
|
||||
|
||||
void onFileChooser(Consumer<FileChooser> handler);
|
||||
void offFileChooser(Consumer<FileChooser> handler);
|
||||
|
||||
void onFrameAttached(Consumer<Frame> handler);
|
||||
void offFrameAttached(Consumer<Frame> handler);
|
||||
|
||||
void onFrameDetached(Consumer<Frame> handler);
|
||||
void offFrameDetached(Consumer<Frame> handler);
|
||||
|
||||
void onFrameNavigated(Consumer<Frame> handler);
|
||||
void offFrameNavigated(Consumer<Frame> handler);
|
||||
|
||||
void onLoad(Runnable handler);
|
||||
void offLoad(Runnable handler);
|
||||
|
||||
void onPageError(Consumer<Error> handler);
|
||||
void offPageError(Consumer<Error> handler);
|
||||
|
||||
void onPopup(Consumer<Page> handler);
|
||||
void offPopup(Consumer<Page> handler);
|
||||
|
||||
void onRequest(Consumer<Request> handler);
|
||||
void offRequest(Consumer<Request> handler);
|
||||
|
||||
void onRequestFailed(Consumer<Request> handler);
|
||||
void offRequestFailed(Consumer<Request> handler);
|
||||
|
||||
void onRequestFinished(Consumer<Request> handler);
|
||||
void offRequestFinished(Consumer<Request> handler);
|
||||
|
||||
void onResponse(Consumer<Response> handler);
|
||||
void offResponse(Consumer<Response> handler);
|
||||
|
||||
void onWebSocket(Consumer<WebSocket> handler);
|
||||
void offWebSocket(Consumer<WebSocket> handler);
|
||||
|
||||
void onWorker(Consumer<Worker> handler);
|
||||
void offWorker(Consumer<Worker> handler);
|
||||
|
||||
|
||||
class WaitForCloseOptions {
|
||||
public Double timeout;
|
||||
public WaitForCloseOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
Page waitForClose(Runnable code, WaitForCloseOptions options);
|
||||
default Page waitForClose(Runnable code) { return waitForClose(code, null); }
|
||||
|
||||
class WaitForConsoleOptions {
|
||||
public Double timeout;
|
||||
public WaitForConsoleOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
ConsoleMessage waitForConsole(Runnable code, WaitForConsoleOptions options);
|
||||
default ConsoleMessage waitForConsole(Runnable code) { return waitForConsole(code, null); }
|
||||
|
||||
class WaitForDownloadOptions {
|
||||
public Double timeout;
|
||||
public WaitForDownloadOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
Download waitForDownload(Runnable code, WaitForDownloadOptions options);
|
||||
default Download waitForDownload(Runnable code) { return waitForDownload(code, null); }
|
||||
|
||||
class WaitForFileChooserOptions {
|
||||
public Double timeout;
|
||||
public WaitForFileChooserOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
FileChooser waitForFileChooser(Runnable code, WaitForFileChooserOptions options);
|
||||
default FileChooser waitForFileChooser(Runnable code) { return waitForFileChooser(code, null); }
|
||||
|
||||
class WaitForFrameAttachedOptions {
|
||||
public Double timeout;
|
||||
public WaitForFrameAttachedOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
Frame waitForFrameAttached(Runnable code, WaitForFrameAttachedOptions options);
|
||||
default Frame waitForFrameAttached(Runnable code) { return waitForFrameAttached(code, null); }
|
||||
|
||||
class WaitForFrameDetachedOptions {
|
||||
public Double timeout;
|
||||
public WaitForFrameDetachedOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
Frame waitForFrameDetached(Runnable code, WaitForFrameDetachedOptions options);
|
||||
default Frame waitForFrameDetached(Runnable code) { return waitForFrameDetached(code, null); }
|
||||
|
||||
class WaitForFrameNavigatedOptions {
|
||||
public Double timeout;
|
||||
public WaitForFrameNavigatedOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
Frame waitForFrameNavigated(Runnable code, WaitForFrameNavigatedOptions options);
|
||||
default Frame waitForFrameNavigated(Runnable code) { return waitForFrameNavigated(code, null); }
|
||||
|
||||
class WaitForPageErrorOptions {
|
||||
public Double timeout;
|
||||
public WaitForPageErrorOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
Error waitForPageError(Runnable code, WaitForPageErrorOptions options);
|
||||
default Error waitForPageError(Runnable code) { return waitForPageError(code, null); }
|
||||
|
||||
class WaitForPopupOptions {
|
||||
public Double timeout;
|
||||
public WaitForPopupOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
Page waitForPopup(Runnable code, WaitForPopupOptions options);
|
||||
default Page waitForPopup(Runnable code) { return waitForPopup(code, null); }
|
||||
|
||||
class WaitForRequestFailedOptions {
|
||||
public Double timeout;
|
||||
public WaitForRequestFailedOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
Request waitForRequestFailed(Runnable code, WaitForRequestFailedOptions options);
|
||||
default Request waitForRequestFailed(Runnable code) { return waitForRequestFailed(code, null); }
|
||||
|
||||
class WaitForRequestFinishedOptions {
|
||||
public Double timeout;
|
||||
public WaitForRequestFinishedOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
Request waitForRequestFinished(Runnable code, WaitForRequestFinishedOptions options);
|
||||
default Request waitForRequestFinished(Runnable code) { return waitForRequestFinished(code, null); }
|
||||
|
||||
class WaitForWebSocketOptions {
|
||||
public Double timeout;
|
||||
public WaitForWebSocketOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
WebSocket waitForWebSocket(Runnable code, WaitForWebSocketOptions options);
|
||||
default WebSocket waitForWebSocket(Runnable code) { return waitForWebSocket(code, null); }
|
||||
|
||||
class WaitForWorkerOptions {
|
||||
public Double timeout;
|
||||
public WaitForWorkerOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
Worker waitForWorker(Runnable code, WaitForWorkerOptions options);
|
||||
default Worker waitForWorker(Runnable code) { return waitForWorker(code, null); }
|
||||
|
||||
enum LoadState { LOAD, DOMCONTENTLOADED, NETWORKIDLE }
|
||||
class AddScriptTagParams {
|
||||
/**
|
||||
@@ -1167,7 +1343,7 @@ public interface Page {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class FutureNavigationOptions {
|
||||
class WaitForNavigationOptions {
|
||||
/**
|
||||
* Maximum operation time in milliseconds, defaults to 30 seconds, pass {@code 0} to disable timeout. The default value can be
|
||||
* changed by using the [{@code method: BrowserContext.setDefaultNavigationTimeout}],
|
||||
@@ -1189,47 +1365,47 @@ public interface Page {
|
||||
*/
|
||||
public Frame.LoadState waitUntil;
|
||||
|
||||
public FutureNavigationOptions withTimeout(double timeout) {
|
||||
public WaitForNavigationOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
public FutureNavigationOptions withUrl(String glob) {
|
||||
public WaitForNavigationOptions withUrl(String glob) {
|
||||
this.glob = glob;
|
||||
return this;
|
||||
}
|
||||
public FutureNavigationOptions withUrl(Pattern pattern) {
|
||||
public WaitForNavigationOptions withUrl(Pattern pattern) {
|
||||
this.pattern = pattern;
|
||||
return this;
|
||||
}
|
||||
public FutureNavigationOptions withUrl(Predicate<String> predicate) {
|
||||
public WaitForNavigationOptions withUrl(Predicate<String> predicate) {
|
||||
this.predicate = predicate;
|
||||
return this;
|
||||
}
|
||||
public FutureNavigationOptions withWaitUntil(Frame.LoadState waitUntil) {
|
||||
public WaitForNavigationOptions withWaitUntil(Frame.LoadState waitUntil) {
|
||||
this.waitUntil = waitUntil;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class FutureRequestOptions {
|
||||
class WaitForRequestOptions {
|
||||
/**
|
||||
* Maximum wait time in milliseconds, defaults to 30 seconds, pass {@code 0} to disable the timeout. The default value can be
|
||||
* changed by using the [{@code method: Page.setDefaultTimeout}] method.
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
public FutureRequestOptions withTimeout(double timeout) {
|
||||
public WaitForRequestOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class FutureResponseOptions {
|
||||
class WaitForResponseOptions {
|
||||
/**
|
||||
* Maximum wait time in milliseconds, defaults to 30 seconds, pass {@code 0} to disable the timeout. The default value can be
|
||||
* changed by using the [{@code method: BrowserContext.setDefaultTimeout}] or [{@code method: Page.setDefaultTimeout}] methods.
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
public FutureResponseOptions withTimeout(double timeout) {
|
||||
public WaitForResponseOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
@@ -2044,23 +2220,6 @@ public interface Page {
|
||||
*/
|
||||
Video video();
|
||||
Viewport viewportSize();
|
||||
default Deferred<Event<EventType>> futureEvent(EventType event) {
|
||||
return futureEvent(event, (FutureEventOptions) null);
|
||||
}
|
||||
default Deferred<Event<EventType>> futureEvent(EventType event, Predicate<Event<EventType>> predicate) {
|
||||
FutureEventOptions options = new FutureEventOptions();
|
||||
options.predicate = predicate;
|
||||
return futureEvent(event, options);
|
||||
}
|
||||
/**
|
||||
* Returns the event data value.
|
||||
*
|
||||
* <p> Waits for event to fire and passes its value into the predicate function. Returns when the predicate returns truthy
|
||||
* value. Will throw an error if the page is closed before the event is fired.
|
||||
*
|
||||
* @param event Event name, same one would pass into {@code page.on(event)}.
|
||||
*/
|
||||
Deferred<Event<EventType>> futureEvent(EventType event, FutureEventOptions options);
|
||||
default JSHandle waitForFunction(String pageFunction, Object arg) {
|
||||
return waitForFunction(pageFunction, arg, null);
|
||||
}
|
||||
@@ -2101,9 +2260,7 @@ public interface Page {
|
||||
* - {@code 'networkidle'} - wait until there are no network connections for at least {@code 500} ms.
|
||||
*/
|
||||
void waitForLoadState(LoadState state, WaitForLoadStateOptions options);
|
||||
default Deferred<Response> futureNavigation() {
|
||||
return futureNavigation(null);
|
||||
}
|
||||
default Response waitForNavigation(Runnable code) { return waitForNavigation(code, null); }
|
||||
/**
|
||||
* Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the
|
||||
* last redirect. In case of navigation to a different anchor or navigation due to History API usage, the navigation will
|
||||
@@ -2118,19 +2275,21 @@ public interface Page {
|
||||
*
|
||||
* <p> Shortcut for main frame's [{@code method: Frame.waitForNavigation}].
|
||||
*/
|
||||
Deferred<Response> futureNavigation(FutureNavigationOptions options);
|
||||
default Deferred<Request> futureRequest(String urlGlob) { return futureRequest(urlGlob, null); }
|
||||
default Deferred<Request> futureRequest(Pattern urlPattern) { return futureRequest(urlPattern, null); }
|
||||
default Deferred<Request> futureRequest(Predicate<String> urlPredicate) { return futureRequest(urlPredicate, null); }
|
||||
Deferred<Request> futureRequest(String urlGlob, FutureRequestOptions options);
|
||||
Deferred<Request> futureRequest(Pattern urlPattern, FutureRequestOptions options);
|
||||
Deferred<Request> futureRequest(Predicate<String> urlPredicate, FutureRequestOptions options);
|
||||
default Deferred<Response> futureResponse(String urlGlob) { return futureResponse(urlGlob, null); }
|
||||
default Deferred<Response> futureResponse(Pattern urlPattern) { return futureResponse(urlPattern, null); }
|
||||
default Deferred<Response> futureResponse(Predicate<String> urlPredicate) { return futureResponse(urlPredicate, null); }
|
||||
Deferred<Response> futureResponse(String urlGlob, FutureResponseOptions options);
|
||||
Deferred<Response> futureResponse(Pattern urlPattern, FutureResponseOptions options);
|
||||
Deferred<Response> futureResponse(Predicate<String> urlPredicate, FutureResponseOptions options);
|
||||
Response waitForNavigation(Runnable code, WaitForNavigationOptions options);
|
||||
Request waitForRequest(Runnable code);
|
||||
default Request waitForRequest(Runnable code, String urlGlob) { return waitForRequest(code, urlGlob, null); }
|
||||
default Request waitForRequest(Runnable code, Pattern urlPattern) { return waitForRequest(code, urlPattern, null); }
|
||||
default Request waitForRequest(Runnable code, Predicate<String> urlPredicate) { return waitForRequest(code, urlPredicate, null); }
|
||||
Request waitForRequest(Runnable code, String urlGlob, WaitForRequestOptions options);
|
||||
Request waitForRequest(Runnable code, Pattern urlPattern, WaitForRequestOptions options);
|
||||
Request waitForRequest(Runnable code, Predicate<String> urlPredicate, WaitForRequestOptions options);
|
||||
Response waitForResponse(Runnable code);
|
||||
default Response waitForResponse(Runnable code, String urlGlob) { return waitForResponse(code, urlGlob, null); }
|
||||
default Response waitForResponse(Runnable code, Pattern urlPattern) { return waitForResponse(code, urlPattern, null); }
|
||||
default Response waitForResponse(Runnable code, Predicate<String> urlPredicate) { return waitForResponse(code, urlPredicate, null); }
|
||||
Response waitForResponse(Runnable code, String urlGlob, WaitForResponseOptions options);
|
||||
Response waitForResponse(Runnable code, Pattern urlPattern, WaitForResponseOptions options);
|
||||
Response waitForResponse(Runnable code, Predicate<String> urlPredicate, WaitForResponseOptions options);
|
||||
default ElementHandle waitForSelector(String selector) {
|
||||
return waitForSelector(selector, null);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
@@ -28,19 +29,6 @@ public interface WebSocket {
|
||||
String text();
|
||||
}
|
||||
|
||||
class FutureEventOptions {
|
||||
public Double timeout;
|
||||
public Predicate<Event<EventType>> predicate;
|
||||
public FutureEventOptions withTimeout(double millis) {
|
||||
timeout = millis;
|
||||
return this;
|
||||
}
|
||||
public FutureEventOptions withPredicate(Predicate<Event<EventType>> predicate) {
|
||||
this.predicate = predicate;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
enum EventType {
|
||||
CLOSE,
|
||||
FRAMERECEIVED,
|
||||
@@ -50,6 +38,50 @@ public interface WebSocket {
|
||||
|
||||
void addListener(EventType type, Listener<EventType> listener);
|
||||
void removeListener(EventType type, Listener<EventType> listener);
|
||||
|
||||
void onClose(Runnable handler);
|
||||
void offClose(Runnable handler);
|
||||
|
||||
void onFrameReceived(Consumer<FrameData> handler);
|
||||
void offFrameReceived(Consumer<FrameData> handler);
|
||||
|
||||
void onFrameSent(Consumer<FrameData> handler);
|
||||
void offFrameSent(Consumer<FrameData> handler);
|
||||
|
||||
void onSocketError(Consumer<String> handler);
|
||||
void offSocketError(Consumer<String> handler);
|
||||
|
||||
|
||||
class WaitForFrameReceivedOptions {
|
||||
public Double timeout;
|
||||
public WaitForFrameReceivedOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
FrameData waitForFrameReceived(Runnable code, WaitForFrameReceivedOptions options);
|
||||
default FrameData waitForFrameReceived(Runnable code) { return waitForFrameReceived(code, null); }
|
||||
|
||||
class WaitForFrameSentOptions {
|
||||
public Double timeout;
|
||||
public WaitForFrameSentOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
FrameData waitForFrameSent(Runnable code, WaitForFrameSentOptions options);
|
||||
default FrameData waitForFrameSent(Runnable code) { return waitForFrameSent(code, null); }
|
||||
|
||||
class WaitForSocketErrorOptions {
|
||||
public Double timeout;
|
||||
public WaitForSocketErrorOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
String waitForSocketError(Runnable code, WaitForSocketErrorOptions options);
|
||||
default String waitForSocketError(Runnable code) { return waitForSocketError(code, null); }
|
||||
|
||||
/**
|
||||
* Indicates that the web socket has been closed.
|
||||
*/
|
||||
@@ -58,22 +90,5 @@ public interface WebSocket {
|
||||
* Contains the URL of the WebSocket.
|
||||
*/
|
||||
String url();
|
||||
default Deferred<Event<EventType>> futureEvent(EventType event) {
|
||||
return futureEvent(event, (FutureEventOptions) null);
|
||||
}
|
||||
default Deferred<Event<EventType>> futureEvent(EventType event, Predicate<Event<EventType>> predicate) {
|
||||
FutureEventOptions options = new FutureEventOptions();
|
||||
options.predicate = predicate;
|
||||
return futureEvent(event, options);
|
||||
}
|
||||
/**
|
||||
* Returns the event data value.
|
||||
*
|
||||
* <p> Waits for event to fire and passes its value into the predicate function. Returns when the predicate returns truthy
|
||||
* value. Will throw an error if the webSocket is closed before the event is fired.
|
||||
*
|
||||
* @param event Event name, same one would pass into {@code webSocket.on(event)}.
|
||||
*/
|
||||
Deferred<Event<EventType>> futureEvent(EventType event, FutureEventOptions options);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* The Worker class represents a [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API). {@code worker}
|
||||
@@ -30,6 +31,21 @@ public interface Worker {
|
||||
|
||||
void addListener(EventType type, Listener<EventType> listener);
|
||||
void removeListener(EventType type, Listener<EventType> listener);
|
||||
|
||||
void onClose(Consumer<Worker> handler);
|
||||
void offClose(Consumer<Worker> handler);
|
||||
|
||||
|
||||
class WaitForCloseOptions {
|
||||
public Double timeout;
|
||||
public WaitForCloseOptions withTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
Worker waitForClose(Runnable code, WaitForCloseOptions options);
|
||||
default Worker waitForClose(Runnable code) { return waitForClose(code, null); }
|
||||
|
||||
default Object evaluate(String pageFunction) {
|
||||
return evaluate(pageFunction, null);
|
||||
}
|
||||
@@ -64,6 +80,5 @@ public interface Worker {
|
||||
*/
|
||||
JSHandle evaluateHandle(String pageFunction, Object arg);
|
||||
String url();
|
||||
Deferred<Event<EventType>> futureEvent(EventType event);
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,43 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
listeners.remove(type, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(Runnable handler) {
|
||||
listeners.add(EventType.CLOSE, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offClose(Runnable handler) {
|
||||
listeners.remove(EventType.CLOSE, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPage(Consumer<Page> handler) {
|
||||
listeners.add(EventType.PAGE, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offPage(Consumer<Page> handler) {
|
||||
listeners.remove(EventType.PAGE, handler);
|
||||
}
|
||||
|
||||
private <T> T waitForEventWithTimeout(EventType eventType, Runnable code, Double timeout) {
|
||||
List<Waitable<T>> waitables = new ArrayList<>();
|
||||
waitables.add(new WaitableEvent<>(listeners, eventType)
|
||||
.apply(event -> (T) event.data()));
|
||||
waitables.add(new WaitableContextClose<>());
|
||||
waitables.add(timeoutSettings.createWaitable(timeout));
|
||||
return runUntil(code, new WaitableRace<>(waitables));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page waitForPage(Runnable code, WaitForPageOptions options) {
|
||||
if (options == null) {
|
||||
options = new WaitForPageOptions();
|
||||
}
|
||||
return waitForEventWithTimeout(EventType.PAGE, code, options.timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
withLogging("BrowserContext.close", () -> closeImpl());
|
||||
@@ -351,18 +388,6 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Deferred<Event<EventType>> futureEvent(EventType event, FutureEventOptions options) {
|
||||
if (options == null) {
|
||||
options = new FutureEventOptions();
|
||||
}
|
||||
List<Waitable<Event<EventType>>> waitables = new ArrayList<>();
|
||||
waitables.add(new WaitableEvent<>(listeners, event, options.predicate));
|
||||
waitables.add(new WaitableContextClose<>());
|
||||
waitables.add(timeoutSettings.createWaitable(options.timeout));
|
||||
return toDeferred(new WaitableRace<>(waitables));
|
||||
}
|
||||
|
||||
private void unroute(UrlMatcher matcher, Consumer<Route> handler) {
|
||||
withLogging("BrowserContext.unroute", () -> {
|
||||
routes.remove(matcher, handler);
|
||||
|
||||
@@ -51,6 +51,16 @@ class BrowserImpl extends ChannelOwner implements Browser {
|
||||
listeners.remove(type, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnected(Runnable handler) {
|
||||
listeners.add(EventType.DISCONNECTED, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offDisconnected(Runnable handler) {
|
||||
listeners.remove(EventType.DISCONNECTED, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
withLogging("Browser.close", () -> closeImpl());
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.Deferred;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -80,26 +79,16 @@ class ChannelOwner extends LoggingSupport {
|
||||
return connection.sendMessage(guid, method, params);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
<T> Deferred<T> toDeferred(Waitable<T> waitable) {
|
||||
return new Deferred<T>() {
|
||||
Exception constructionStackTrace = new Exception();
|
||||
@Override
|
||||
public T get() {
|
||||
constructionStackTrace = null;
|
||||
while (!waitable.isDone()) {
|
||||
connection.processOneMessage();
|
||||
}
|
||||
return (T) waitable.get();
|
||||
<T> T runUntil(Runnable code, Waitable<T> waitable) {
|
||||
try {
|
||||
code.run();
|
||||
while (!waitable.isDone()) {
|
||||
connection.processOneMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() {
|
||||
if (constructionStackTrace != null) {
|
||||
connection.addUnusedDeferredObject(constructionStackTrace);
|
||||
}
|
||||
}
|
||||
};
|
||||
return waitable.get();
|
||||
} finally {
|
||||
waitable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
void handleEvent(String event, JsonObject parameters) {
|
||||
|
||||
@@ -54,7 +54,6 @@ public class Connection {
|
||||
private final Root root;
|
||||
private int lastId = 0;
|
||||
private final Map<Integer, WaitableResult<JsonElement>> callbacks = new HashMap<>();
|
||||
private final Deque<Exception> unusedDeferredObjects = new ArrayDeque<>();
|
||||
|
||||
class Root extends ChannelOwner {
|
||||
Root(Connection connection) {
|
||||
@@ -72,7 +71,7 @@ public class Connection {
|
||||
}
|
||||
|
||||
public JsonElement sendMessage(String guid, String method, JsonObject params) {
|
||||
return root.toDeferred(sendMessageAsync(guid, method, params)).get();
|
||||
return root.runUntil(() -> {}, sendMessageAsync(guid, method, params));
|
||||
}
|
||||
|
||||
public WaitableResult<JsonElement> sendMessageAsync(String guid, String method, JsonObject params) {
|
||||
@@ -254,26 +253,4 @@ public class Connection {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void addUnusedDeferredObject(Exception exception) {
|
||||
unusedDeferredObjects.add(exception);
|
||||
if (unusedDeferredObjects.size() > 10) {
|
||||
unusedDeferredObjects.removeLast();
|
||||
}
|
||||
}
|
||||
|
||||
void checkNoUnusedDeferredObjects() {
|
||||
if (unusedDeferredObjects.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<String> chunks = new ArrayList<>();
|
||||
chunks.add("Method get() has not been called on some Deferred<> objects. This indicates a " +
|
||||
"bug in the client code. Here are some stack traces where such objects were constructed");
|
||||
for (Exception e : unusedDeferredObjects) {
|
||||
StringWriter writer = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(writer));
|
||||
chunks.add(writer.toString());
|
||||
}
|
||||
throw new PlaywrightException(String.join("\n", chunks));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,16 +16,13 @@
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.Deferred;
|
||||
import com.microsoft.playwright.ElementHandle;
|
||||
import com.microsoft.playwright.FileChooser;
|
||||
import com.microsoft.playwright.Frame;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
|
||||
@@ -16,13 +16,11 @@
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
@@ -674,7 +672,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
waitables.add(new WaitForLoadStateHelper(state));
|
||||
waitables.add(page.createWaitForCloseHelper());
|
||||
waitables.add(page.createWaitableTimeout(options.timeout));
|
||||
toDeferred(new WaitableRace<>(waitables)).get();
|
||||
runUntil(() -> {}, new WaitableRace<>(waitables));
|
||||
}
|
||||
|
||||
private class WaitForLoadStateHelper implements Waitable<Void>, Listener<InternalEventType> {
|
||||
@@ -712,7 +710,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
}
|
||||
|
||||
private class FutureNavigationHelper implements Waitable<Response>, Listener<InternalEventType> {
|
||||
private class WaitForNavigationHelper implements Waitable<Response>, Listener<InternalEventType> {
|
||||
private final UrlMatcher matcher;
|
||||
private final LoadState expectedLoadState;
|
||||
private WaitForLoadStateHelper loadStateHelper;
|
||||
@@ -720,7 +718,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
private RequestImpl request;
|
||||
private RuntimeException exception;
|
||||
|
||||
FutureNavigationHelper(UrlMatcher matcher, LoadState expectedLoadState) {
|
||||
WaitForNavigationHelper(UrlMatcher matcher, LoadState expectedLoadState) {
|
||||
this.matcher = matcher;
|
||||
this.expectedLoadState = expectedLoadState;
|
||||
internalListeners.add(InternalEventType.NAVIGATED, this);
|
||||
@@ -780,13 +778,13 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Deferred<Response> futureNavigation(FutureNavigationOptions options) {
|
||||
return withLoggingDeferred("Frame.futureNavigation", () -> futureNavigationImpl(options));
|
||||
public Response waitForNavigation(Runnable code, WaitForNavigationOptions options) {
|
||||
return withLogging("Frame.waitForNavigation", () -> waitForNavigationImpl(code, options));
|
||||
}
|
||||
|
||||
Deferred<Response> futureNavigationImpl(FutureNavigationOptions options) {
|
||||
Response waitForNavigationImpl(Runnable code, WaitForNavigationOptions options) {
|
||||
if (options == null) {
|
||||
options = new FutureNavigationOptions();
|
||||
options = new WaitForNavigationOptions();
|
||||
}
|
||||
if (options.waitUntil == null) {
|
||||
options.waitUntil = LOAD;
|
||||
@@ -794,11 +792,11 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
List<Waitable<Response>> waitables = new ArrayList<>();
|
||||
UrlMatcher matcher = UrlMatcher.forOneOf(options.glob, options.pattern, options.predicate);
|
||||
waitables.add(new FutureNavigationHelper(matcher, options.waitUntil));
|
||||
waitables.add(new WaitForNavigationHelper(matcher, options.waitUntil));
|
||||
waitables.add(page.createWaitForCloseHelper());
|
||||
waitables.add(page.createWaitableFrameDetach(this));
|
||||
waitables.add(page.createWaitableNavigationTimeout(options.timeout));
|
||||
return toDeferred(new WaitableRace<>(waitables));
|
||||
return runUntil(code, new WaitableRace<>(waitables));
|
||||
}
|
||||
|
||||
private static String toProtocol(WaitForSelectorOptions.State state) {
|
||||
@@ -834,13 +832,13 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
|
||||
void waitForTimeoutImpl(double timeout) {
|
||||
toDeferred(new WaitableTimeout<Void>(timeout) {
|
||||
runUntil(() -> {}, new WaitableTimeout<Void>(timeout) {
|
||||
@Override
|
||||
public Void get() {
|
||||
// Override to not throw.
|
||||
return null;
|
||||
}
|
||||
}).get();
|
||||
});
|
||||
}
|
||||
|
||||
protected void handleEvent(String event, JsonObject params) {
|
||||
|
||||
@@ -16,14 +16,11 @@
|
||||
|
||||
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;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
class ListenerCollection <EventType> {
|
||||
private final HashMap<EventType, List<Listener<EventType>>> listeners = new HashMap<>();
|
||||
@@ -51,6 +48,71 @@ class ListenerCollection <EventType> {
|
||||
}
|
||||
}
|
||||
|
||||
private static class RunnableWrapper<EventType> implements Listener<EventType> {
|
||||
final Runnable callback;
|
||||
|
||||
private RunnableWrapper(Runnable callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Event<EventType> event) {
|
||||
callback.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
RunnableWrapper<?> that = (RunnableWrapper<?>) o;
|
||||
return Objects.equals(callback, that.callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(callback);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConsumerWrapper<EventType> implements Listener<EventType> {
|
||||
final Consumer<?> callback;
|
||||
|
||||
private ConsumerWrapper(Consumer<?> callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Event<EventType> event) {
|
||||
((Consumer<Object>) callback).accept(event.data());
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
RunnableWrapper<?> that = (RunnableWrapper<?>) o;
|
||||
return Objects.equals(callback, that.callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(callback);
|
||||
}
|
||||
}
|
||||
|
||||
void add(EventType type, Runnable listener) {
|
||||
add(type, new RunnableWrapper<>(listener));
|
||||
}
|
||||
void remove(EventType type, Runnable listener) {
|
||||
remove(type, new RunnableWrapper<>(listener));
|
||||
}
|
||||
|
||||
void add(EventType type, Consumer listener) {
|
||||
add(type, new ConsumerWrapper<>(listener));
|
||||
}
|
||||
void remove(EventType type, Consumer listener) {
|
||||
remove(type, new ConsumerWrapper<>(listener));
|
||||
}
|
||||
|
||||
void add(EventType type, Listener<EventType> listener) {
|
||||
List<Listener<EventType>> list = listeners.get(type);
|
||||
if (list == null) {
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.microsoft.playwright.Deferred;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
@@ -60,25 +58,6 @@ class LoggingSupport {
|
||||
}
|
||||
}
|
||||
|
||||
<T> Deferred<T> withLoggingDeferred(String apiName, Supplier<Deferred<T>> code) {
|
||||
if (isEnabled) {
|
||||
logApi("=> " + apiName + " started");
|
||||
}
|
||||
Deferred<T> deferred = code.get();
|
||||
return () -> {
|
||||
boolean success = false;
|
||||
try {
|
||||
T result = deferred.get();
|
||||
success = true;
|
||||
return result;
|
||||
} finally {
|
||||
if (isEnabled) {
|
||||
logApi("<= " + apiName + (success ? " succeeded" : " failed"));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void logApi(String message) {
|
||||
// This matches log format produced by the server.
|
||||
String timestamp = timestampFormat.format(new Date());
|
||||
|
||||
@@ -44,7 +44,23 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
private Viewport viewport;
|
||||
private final Router routes = new Router();
|
||||
private final Set<FrameImpl> frames = new LinkedHashSet<>();
|
||||
private final ListenerCollection<EventType> listeners = new ListenerCollection<>();
|
||||
private final ListenerCollection<EventType> listeners = new ListenerCollection<EventType>() {
|
||||
@Override
|
||||
void add(EventType eventType, Listener<EventType> listener) {
|
||||
if (eventType == EventType.FILECHOOSER) {
|
||||
willAddFileChooserListener();
|
||||
}
|
||||
super.add(eventType, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
void remove(EventType eventType, Listener<EventType> listener) {
|
||||
super.remove(eventType, listener);
|
||||
if (eventType == EventType.FILECHOOSER) {
|
||||
didRemoveFileChooserListener();
|
||||
}
|
||||
}
|
||||
};
|
||||
final Map<String, Binding> bindings = new HashMap<>();
|
||||
BrowserContextImpl ownedContext;
|
||||
private boolean isClosed;
|
||||
@@ -203,18 +219,316 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public void addListener(EventType type, Listener<EventType> listener) {
|
||||
if (type == EventType.FILECHOOSER) {
|
||||
willAddFileChooserListener();
|
||||
}
|
||||
listeners.add(type, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(EventType type, Listener<EventType> listener) {
|
||||
listeners.remove(type, listener);
|
||||
if (type == EventType.FILECHOOSER) {
|
||||
didRemoveFileChooserListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(Runnable handler) {
|
||||
listeners.add(EventType.CLOSE, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offClose(Runnable handler) {
|
||||
listeners.remove(EventType.CLOSE, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConsole(Consumer<ConsoleMessage> handler) {
|
||||
listeners.add(EventType.CONSOLE, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offConsole(Consumer<ConsoleMessage> handler) {
|
||||
listeners.remove(EventType.CONSOLE, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCrash(Runnable handler) {
|
||||
listeners.add(EventType.CRASH, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offCrash(Runnable handler) {
|
||||
listeners.remove(EventType.CRASH, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDialog(Consumer<Dialog> handler) {
|
||||
listeners.add(EventType.DIALOG, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offDialog(Consumer<Dialog> handler) {
|
||||
listeners.remove(EventType.DIALOG, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDomContentLoaded(Runnable handler) {
|
||||
listeners.add(EventType.DOMCONTENTLOADED, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offDomContentLoaded(Runnable handler) {
|
||||
listeners.remove(EventType.DOMCONTENTLOADED, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDownload(Consumer<Download> handler) {
|
||||
listeners.add(EventType.DOWNLOAD, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offDownload(Consumer<Download> handler) {
|
||||
listeners.remove(EventType.DOWNLOAD, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileChooser(Consumer<FileChooser> handler) {
|
||||
listeners.add(EventType.FILECHOOSER, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offFileChooser(Consumer<FileChooser> handler) {
|
||||
listeners.remove(EventType.FILECHOOSER, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFrameAttached(Consumer<Frame> handler) {
|
||||
listeners.add(EventType.FRAMEATTACHED, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offFrameAttached(Consumer<Frame> handler) {
|
||||
listeners.remove(EventType.FRAMEATTACHED, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFrameDetached(Consumer<Frame> handler) {
|
||||
listeners.add(EventType.FRAMEDETACHED, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offFrameDetached(Consumer<Frame> handler) {
|
||||
listeners.remove(EventType.FRAMEDETACHED, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFrameNavigated(Consumer<Frame> handler) {
|
||||
listeners.add(EventType.FRAMENAVIGATED, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offFrameNavigated(Consumer<Frame> handler) {
|
||||
listeners.remove(EventType.FRAMENAVIGATED, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad(Runnable handler) {
|
||||
listeners.add(EventType.LOAD, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offLoad(Runnable handler) {
|
||||
listeners.remove(EventType.LOAD, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageError(Consumer<Error> handler) {
|
||||
listeners.add(EventType.PAGEERROR, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offPageError(Consumer<Error> handler) {
|
||||
listeners.remove(EventType.PAGEERROR, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPopup(Consumer<Page> handler) {
|
||||
listeners.add(EventType.POPUP, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offPopup(Consumer<Page> handler) {
|
||||
listeners.remove(EventType.POPUP, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequest(Consumer<Request> handler) {
|
||||
listeners.add(EventType.REQUEST, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offRequest(Consumer<Request> handler) {
|
||||
listeners.remove(EventType.REQUEST, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestFailed(Consumer<Request> handler) {
|
||||
listeners.add(EventType.REQUESTFAILED, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offRequestFailed(Consumer<Request> handler) {
|
||||
listeners.remove(EventType.REQUESTFAILED, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestFinished(Consumer<Request> handler) {
|
||||
listeners.add(EventType.REQUESTFINISHED, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offRequestFinished(Consumer<Request> handler) {
|
||||
listeners.remove(EventType.REQUESTFINISHED, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Consumer<Response> handler) {
|
||||
listeners.add(EventType.RESPONSE, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offResponse(Consumer<Response> handler) {
|
||||
listeners.remove(EventType.RESPONSE, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocket(Consumer<WebSocket> handler) {
|
||||
listeners.add(EventType.WEBSOCKET, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offWebSocket(Consumer<WebSocket> handler) {
|
||||
listeners.remove(EventType.WEBSOCKET, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWorker(Consumer<Worker> handler) {
|
||||
listeners.add(EventType.WORKER, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offWorker(Consumer<Worker> handler) {
|
||||
listeners.remove(EventType.WORKER, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page waitForClose(Runnable code, WaitForCloseOptions options) {
|
||||
if (options == null) {
|
||||
options = new WaitForCloseOptions();
|
||||
}
|
||||
return waitForEventWithTimeout(EventType.CLOSE, code, options.timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConsoleMessage waitForConsole(Runnable code, WaitForConsoleOptions options) {
|
||||
if (options == null) {
|
||||
options = new WaitForConsoleOptions();
|
||||
}
|
||||
return waitForEventWithTimeout(EventType.CONSOLE, code, options.timeout);
|
||||
}
|
||||
|
||||
private <T> T waitForEventWithTimeout(EventType eventType, Runnable code, Double timeout) {
|
||||
List<Waitable<T>> waitables = new ArrayList<>();
|
||||
waitables.add(new WaitableEvent<>(listeners, eventType)
|
||||
.apply(event -> (T) event.data()));
|
||||
waitables.add(createWaitForCloseHelper());
|
||||
waitables.add(createWaitableTimeout(timeout));
|
||||
return runUntil(code, new WaitableRace<>(waitables));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Download waitForDownload(Runnable code, WaitForDownloadOptions options) {
|
||||
if (options == null) {
|
||||
options = new WaitForDownloadOptions();
|
||||
}
|
||||
return waitForEventWithTimeout(EventType.DOWNLOAD, code, options.timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileChooser waitForFileChooser(Runnable code, WaitForFileChooserOptions options) {
|
||||
// TODO: enable/disable file chooser interception
|
||||
if (options == null) {
|
||||
options = new WaitForFileChooserOptions();
|
||||
}
|
||||
return waitForEventWithTimeout(EventType.FILECHOOSER, code, options.timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frame waitForFrameAttached(Runnable code, WaitForFrameAttachedOptions options) {
|
||||
if (options == null) {
|
||||
options = new WaitForFrameAttachedOptions();
|
||||
}
|
||||
return waitForEventWithTimeout(EventType.FRAMEATTACHED, code, options.timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frame waitForFrameDetached(Runnable code, WaitForFrameDetachedOptions options) {
|
||||
if (options == null) {
|
||||
options = new WaitForFrameDetachedOptions();
|
||||
}
|
||||
return waitForEventWithTimeout(EventType.FRAMEDETACHED, code, options.timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frame waitForFrameNavigated(Runnable code, WaitForFrameNavigatedOptions options) {
|
||||
if (options == null) {
|
||||
options = new WaitForFrameNavigatedOptions();
|
||||
}
|
||||
return waitForEventWithTimeout(EventType.FRAMENAVIGATED, code, options.timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Error waitForPageError(Runnable code, WaitForPageErrorOptions options) {
|
||||
if (options == null) {
|
||||
options = new WaitForPageErrorOptions();
|
||||
}
|
||||
return waitForEventWithTimeout(EventType.PAGEERROR, code, options.timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page waitForPopup(Runnable code, WaitForPopupOptions options) {
|
||||
if (options == null) {
|
||||
options = new WaitForPopupOptions();
|
||||
}
|
||||
return waitForEventWithTimeout(EventType.POPUP, code, options.timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request waitForRequestFailed(Runnable code, WaitForRequestFailedOptions options) {
|
||||
if (options == null) {
|
||||
options = new WaitForRequestFailedOptions();
|
||||
}
|
||||
return waitForEventWithTimeout(EventType.REQUESTFAILED, code, options.timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request waitForRequestFinished(Runnable code, WaitForRequestFinishedOptions options) {
|
||||
if (options == null) {
|
||||
options = new WaitForRequestFinishedOptions();
|
||||
}
|
||||
return waitForEventWithTimeout(EventType.REQUESTFINISHED, code, options.timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocket waitForWebSocket(Runnable code, WaitForWebSocketOptions options) {
|
||||
if (options == null) {
|
||||
options = new WaitForWebSocketOptions();
|
||||
}
|
||||
return waitForEventWithTimeout(EventType.WEBSOCKET, code, options.timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Worker waitForWorker(Runnable code, WaitForWorkerOptions options) {
|
||||
if (options == null) {
|
||||
options = new WaitForWorkerOptions();
|
||||
}
|
||||
return waitForEventWithTimeout(EventType.WORKER, code, options.timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -804,32 +1118,6 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
return timeoutSettings.createWaitable(timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Deferred<Event<EventType>> futureEvent(EventType event, FutureEventOptions options) {
|
||||
return withLogging("Page.futureEvent", () -> futureEventImpl(event, options));
|
||||
}
|
||||
|
||||
private Deferred<Event<EventType>> futureEventImpl(EventType event, FutureEventOptions options) {
|
||||
if (options == null) {
|
||||
options = new FutureEventOptions();
|
||||
}
|
||||
List<Waitable<Event<EventType>>> waitables = new ArrayList<>();
|
||||
if (event == EventType.FILECHOOSER) {
|
||||
willAddFileChooserListener();
|
||||
waitables.add(new WaitableEvent<EventType>(listeners, event, options.predicate) {
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
didRemoveFileChooserListener();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
waitables.add(new WaitableEvent<>(listeners, event, options.predicate));
|
||||
}
|
||||
waitables.add(createWaitableTimeout(options.timeout));
|
||||
return toDeferred(new WaitableRace<>(waitables));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSHandle waitForFunction(String pageFunction, Object arg, WaitForFunctionOptions options) {
|
||||
return withLogging("Page.waitForFunction",
|
||||
@@ -843,12 +1131,17 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Deferred<Response> futureNavigation(FutureNavigationOptions options) {
|
||||
return withLoggingDeferred("Page.futureNavigation", () -> futureNavigationImpl(options));
|
||||
public Response waitForNavigation(Runnable code, WaitForNavigationOptions options) {
|
||||
return withLogging("Page.waitForNavigation", () -> waitForNavigationImpl(code, options));
|
||||
}
|
||||
|
||||
Deferred<Response> futureNavigationImpl(FutureNavigationOptions options) {
|
||||
Frame.FutureNavigationOptions frameOptions = new Frame.FutureNavigationOptions();
|
||||
@Override
|
||||
public Request waitForRequest(Runnable code) {
|
||||
return waitForRequest(code, UrlMatcher.any(), null);
|
||||
}
|
||||
|
||||
Response waitForNavigationImpl(Runnable code, WaitForNavigationOptions options) {
|
||||
Frame.WaitForNavigationOptions frameOptions = new Frame.WaitForNavigationOptions();
|
||||
if (options != null) {
|
||||
frameOptions.timeout = options.timeout;
|
||||
frameOptions.waitUntil = options.waitUntil;
|
||||
@@ -856,7 +1149,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
frameOptions.pattern = options.pattern;
|
||||
frameOptions.predicate = options.predicate;
|
||||
}
|
||||
return mainFrame.futureNavigationImpl(frameOptions);
|
||||
return mainFrame.waitForNavigationImpl(code, frameOptions);
|
||||
}
|
||||
|
||||
void frameNavigated(FrameImpl frame) {
|
||||
@@ -887,8 +1180,8 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
}
|
||||
|
||||
private class WaitableFrameDetach extends WaitableEvent<EventType> {
|
||||
WaitableFrameDetach(Frame frame) {
|
||||
super(PageImpl.this.listeners, EventType.FRAMEDETACHED, event -> frame.equals(event.data()));
|
||||
WaitableFrameDetach(Frame frameArg) {
|
||||
super(PageImpl.this.listeners, EventType.FRAMEDETACHED, event -> frameArg.equals(event.data()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -949,65 +1242,70 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Deferred<Request> futureRequest(String urlGlob, FutureRequestOptions options) {
|
||||
return futureRequest(new UrlMatcher(urlGlob), options);
|
||||
public Request waitForRequest(Runnable code, String urlGlob, WaitForRequestOptions options) {
|
||||
return waitForRequest(code, new UrlMatcher(urlGlob), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Deferred<Request> futureRequest(Pattern urlPattern, FutureRequestOptions options) {
|
||||
return futureRequest(new UrlMatcher(urlPattern), options);
|
||||
public Request waitForRequest(Runnable code, Pattern urlPattern, WaitForRequestOptions options) {
|
||||
return waitForRequest(code, new UrlMatcher(urlPattern), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Deferred<Request> futureRequest(Predicate<String> urlPredicate, FutureRequestOptions options) {
|
||||
return futureRequest(new UrlMatcher(urlPredicate), options);
|
||||
public Request waitForRequest(Runnable code, Predicate<String> urlPredicate, WaitForRequestOptions options) {
|
||||
return waitForRequest(code, new UrlMatcher(urlPredicate), options);
|
||||
}
|
||||
|
||||
private Deferred<Request> futureRequest(UrlMatcher matcher, FutureRequestOptions options) {
|
||||
return withLoggingDeferred("Page.futureRequest", () -> futureRequestImpl(matcher, options));
|
||||
@Override
|
||||
public Response waitForResponse(Runnable code) {
|
||||
return waitForResponse(code, UrlMatcher.any(), null);
|
||||
}
|
||||
|
||||
private Deferred<Request> futureRequestImpl(UrlMatcher matcher, FutureRequestOptions options) {
|
||||
private Request waitForRequest(Runnable code, UrlMatcher matcher, WaitForRequestOptions options) {
|
||||
return withLogging("Page.waitForRequest", () -> waitForRequestImpl(code, matcher, options));
|
||||
}
|
||||
|
||||
private Request waitForRequestImpl(Runnable code, UrlMatcher matcher, WaitForRequestOptions options) {
|
||||
if (options == null) {
|
||||
options = new FutureRequestOptions();
|
||||
options = new WaitForRequestOptions();
|
||||
}
|
||||
List<Waitable<Request>> waitables = new ArrayList<>();
|
||||
waitables.add(new WaitableEvent<>(listeners, EventType.REQUEST, e -> matcher.test(((Request) e.data()).url()))
|
||||
.apply(event -> (Request) event.data()));
|
||||
waitables.add(createWaitForCloseHelper());
|
||||
waitables.add(createWaitableTimeout(options.timeout));
|
||||
return toDeferred(new WaitableRace<>(waitables));
|
||||
return runUntil(code, new WaitableRace<>(waitables));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Deferred<Response> futureResponse(String urlGlob, FutureResponseOptions options) {
|
||||
return futureResponse(new UrlMatcher(urlGlob), options);
|
||||
public Response waitForResponse(Runnable code, String urlGlob, WaitForResponseOptions options) {
|
||||
return waitForResponse(code, new UrlMatcher(urlGlob), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Deferred<Response> futureResponse(Pattern urlPattern, FutureResponseOptions options) {
|
||||
return futureResponse(new UrlMatcher(urlPattern), options);
|
||||
public Response waitForResponse(Runnable code, Pattern urlPattern, WaitForResponseOptions options) {
|
||||
return waitForResponse(code, new UrlMatcher(urlPattern), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Deferred<Response> futureResponse(Predicate<String> urlPredicate, FutureResponseOptions options) {
|
||||
return futureResponse(new UrlMatcher(urlPredicate), options);
|
||||
public Response waitForResponse(Runnable code, Predicate<String> urlPredicate, WaitForResponseOptions options) {
|
||||
return waitForResponse(code, new UrlMatcher(urlPredicate), options);
|
||||
}
|
||||
|
||||
private Deferred<Response> futureResponse(UrlMatcher matcher, FutureResponseOptions options) {
|
||||
return withLoggingDeferred("Page.futureResponse", () -> futureResponseImpl(matcher, options));
|
||||
private Response waitForResponse(Runnable code, UrlMatcher matcher, WaitForResponseOptions options) {
|
||||
return withLogging("Page.waitForResponse", () -> waitForonseImpl(code, matcher, options));
|
||||
}
|
||||
|
||||
private Deferred<Response> futureResponseImpl(UrlMatcher matcher, FutureResponseOptions options) {
|
||||
private Response waitForonseImpl(Runnable code, UrlMatcher matcher, WaitForResponseOptions options) {
|
||||
if (options == null) {
|
||||
options = new FutureResponseOptions();
|
||||
options = new WaitForResponseOptions();
|
||||
}
|
||||
List<Waitable<Response>> waitables = new ArrayList<>();
|
||||
waitables.add(new WaitableEvent<>(listeners, EventType.RESPONSE, e -> matcher.test(((Response) e.data()).url()))
|
||||
.apply(event -> (Response) event.data()));
|
||||
waitables.add(createWaitForCloseHelper());
|
||||
waitables.add(createWaitableTimeout(options.timeout));
|
||||
return toDeferred(new WaitableRace<>(waitables));
|
||||
return runUntil(code, new WaitableRace<>(waitables));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -107,7 +107,5 @@ public class PlaywrightImpl extends ChannelOwner implements Playwright {
|
||||
if (!didClose) {
|
||||
System.err.println("WARNING: Timed out while waiting for driver process to exit");
|
||||
}
|
||||
|
||||
connection.checkNoUnusedDeferredObjects();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
class WebSocketImpl extends ChannelOwner implements WebSocket {
|
||||
private final ListenerCollection<EventType> listeners = new ListenerCollection<>();
|
||||
@@ -45,6 +46,70 @@ class WebSocketImpl extends ChannelOwner implements WebSocket {
|
||||
listeners.remove(type, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(Runnable handler) {
|
||||
listeners.add(EventType.CLOSE, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offClose(Runnable handler) {
|
||||
listeners.remove(EventType.CLOSE, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFrameReceived(Consumer<FrameData> handler) {
|
||||
listeners.add(EventType.FRAMERECEIVED, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offFrameReceived(Consumer<FrameData> handler) {
|
||||
listeners.remove(EventType.FRAMERECEIVED, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFrameSent(Consumer<FrameData> handler) {
|
||||
listeners.add(EventType.FRAMESENT, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offFrameSent(Consumer<FrameData> handler) {
|
||||
listeners.remove(EventType.FRAMESENT, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSocketError(Consumer<String> handler) {
|
||||
listeners.add(EventType.SOCKETERROR, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offSocketError(Consumer<String> handler) {
|
||||
listeners.remove(EventType.SOCKETERROR, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FrameData waitForFrameReceived(Runnable code, WaitForFrameReceivedOptions options) {
|
||||
if (options == null) {
|
||||
options = new WaitForFrameReceivedOptions();
|
||||
}
|
||||
return waitForEventWithTimeout(EventType.FRAMERECEIVED, code, options.timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FrameData waitForFrameSent(Runnable code, WaitForFrameSentOptions options) {
|
||||
if (options == null) {
|
||||
options = new WaitForFrameSentOptions();
|
||||
}
|
||||
return waitForEventWithTimeout(EventType.FRAMESENT, code, options.timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String waitForSocketError(Runnable code, WaitForSocketErrorOptions options) {
|
||||
if (options == null) {
|
||||
options = new WaitForSocketErrorOptions();
|
||||
}
|
||||
return waitForEventWithTimeout(EventType.SOCKETERROR, code, options.timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return isClosed;
|
||||
@@ -96,21 +161,14 @@ class WebSocketImpl extends ChannelOwner implements WebSocket {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Deferred<Event<EventType>> futureEvent(EventType event, FutureEventOptions options) {
|
||||
return withLoggingDeferred("WebSocket.futureEvent", () -> futureEventImpl(event, options));
|
||||
}
|
||||
|
||||
private Deferred<Event<EventType>> futureEventImpl(EventType event, FutureEventOptions options) {
|
||||
if (options == null) {
|
||||
options = new FutureEventOptions();
|
||||
}
|
||||
List<Waitable<Event<EventType>>> waitables = new ArrayList<>();
|
||||
waitables.add(new WaitableEvent<>(listeners, event, options.predicate));
|
||||
private <T> T waitForEventWithTimeout(EventType eventType, Runnable code, Double timeout) {
|
||||
List<Waitable<T>> waitables = new ArrayList<>();
|
||||
waitables.add(new WaitableEvent<>(listeners, eventType)
|
||||
.apply(event -> (T) event.data()));
|
||||
waitables.add(new WaitableWebSocketError<>());
|
||||
waitables.add(page.createWaitForCloseHelper());
|
||||
waitables.add(page.createWaitableTimeout(options.timeout));
|
||||
return toDeferred(new WaitableRace<>(waitables));
|
||||
waitables.add(page.createWaitableTimeout(timeout));
|
||||
return runUntil(code, new WaitableRace<>(waitables));
|
||||
}
|
||||
|
||||
private static class FrameDataImpl implements FrameData {
|
||||
|
||||
@@ -21,6 +21,10 @@ import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static com.microsoft.playwright.impl.Serialization.*;
|
||||
import static com.microsoft.playwright.impl.Utils.isFunctionBody;
|
||||
|
||||
@@ -42,6 +46,33 @@ class WorkerImpl extends ChannelOwner implements Worker {
|
||||
listeners.remove(type, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(Consumer<Worker> handler) {
|
||||
listeners.add(EventType.CLOSE, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offClose(Consumer<Worker> handler) {
|
||||
listeners.remove(EventType.CLOSE, handler);
|
||||
}
|
||||
|
||||
private <T> T waitForEventWithTimeout(EventType eventType, Runnable code, Double timeout) {
|
||||
List<Waitable<T>> waitables = new ArrayList<>();
|
||||
waitables.add(new WaitableEvent<>(listeners, eventType)
|
||||
.apply(event -> (T) event.data()));
|
||||
waitables.add(page.createWaitForCloseHelper());
|
||||
waitables.add(page.createWaitableTimeout(timeout));
|
||||
return runUntil(code, new WaitableRace<>(waitables));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Worker waitForClose(Runnable code, WaitForCloseOptions options) {
|
||||
if (options == null) {
|
||||
options = new WaitForCloseOptions();
|
||||
}
|
||||
return waitForEventWithTimeout(EventType.CLOSE, code, options.timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate(String pageFunction, Object arg) {
|
||||
return withLogging("Worker.evaluate", () -> {
|
||||
@@ -72,11 +103,6 @@ class WorkerImpl extends ChannelOwner implements Worker {
|
||||
return initializer.get("url").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Deferred<Event<EventType>> futureEvent(EventType event) {
|
||||
return toDeferred(new WaitableEvent<>(listeners, event));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleEvent(String event, JsonObject params) {
|
||||
if ("close".equals(event)) {
|
||||
|
||||
@@ -44,9 +44,8 @@ public class TestBrowserContextBasic extends TestBase {
|
||||
BrowserContext context = browser.newContext();
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Event<Page.EventType>> popupEvent = page.futureEvent(POPUP);
|
||||
page.evaluate("url => window.open(url)", server.EMPTY_PAGE);
|
||||
Page popup = (Page) popupEvent.get().data();
|
||||
Page popup = page.waitForPopup(() ->
|
||||
page.evaluate("url => window.open(url)", server.EMPTY_PAGE));
|
||||
assertEquals(context, popup.context());
|
||||
context.close();
|
||||
}
|
||||
@@ -155,10 +154,8 @@ public class TestBrowserContextBasic extends TestBase {
|
||||
@Test
|
||||
void closeShouldAbortFutureEvent() {
|
||||
BrowserContext context = browser.newContext();
|
||||
Deferred<Event<BrowserContext.EventType>> pageEvent = context.futureEvent(PAGE);
|
||||
context.close();
|
||||
try {
|
||||
pageEvent.get();
|
||||
context.waitForPage(() -> context.close());
|
||||
fail("did not throw");
|
||||
} catch (PlaywrightException e) {
|
||||
assertTrue(e.getMessage().contains("Context closed"));
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.junit.jupiter.api.condition.EnabledIf;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static com.microsoft.playwright.Keyboard.Modifier.SHIFT;
|
||||
import static com.microsoft.playwright.Mouse.Button.RIGHT;
|
||||
@@ -104,9 +105,7 @@ public class TestClick extends TestBase {
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.PREFIX + "/wrappedlink.html");
|
||||
|
||||
Deferred<Response> navigationPromise = page.futureNavigation();
|
||||
page.click("a");
|
||||
navigationPromise.get();
|
||||
page.waitForNavigation(() -> page.click("a"));
|
||||
|
||||
assertEquals(server.PREFIX + "/wrappedlink.html#clicked", page.url());
|
||||
context.close();
|
||||
|
||||
@@ -1,56 +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;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public class TestDeferred extends TestBase {
|
||||
@Test
|
||||
void throwIfGetNotCalled() {
|
||||
page.futureNavigation();
|
||||
context.futureEvent(BrowserContext.EventType.PAGE);
|
||||
closeContext();
|
||||
closeBrowser();
|
||||
|
||||
AtomicBoolean didFinalize = new AtomicBoolean();
|
||||
new Object() {
|
||||
@Override
|
||||
protected void finalize() {
|
||||
didFinalize.set(true);
|
||||
}
|
||||
};
|
||||
while (!didFinalize.get()) {
|
||||
System.gc();
|
||||
}
|
||||
|
||||
Playwright p = playwright;
|
||||
playwright = null;
|
||||
try {
|
||||
p.close();
|
||||
fail("did not throw");
|
||||
} catch (Exception e) {
|
||||
assertTrue(e.getMessage().contains("com.microsoft.playwright.impl.PageImpl.futureNavigation"));
|
||||
assertTrue(e.getMessage().contains("com.microsoft.playwright.impl.BrowserContextImpl.futureEvent"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,9 +61,7 @@ public class TestDownload extends TestBase {
|
||||
@Test
|
||||
void shouldReportDownloadsWithAcceptDownloadsFalse() {
|
||||
page.setContent("<a href='" + server.PREFIX + "/downloadWithFilename'>download</a>");
|
||||
Deferred<Event<Page.EventType>> downloadEvent = page.futureEvent(DOWNLOAD);
|
||||
page.click("a");
|
||||
Download download = (Download) downloadEvent.get().data();
|
||||
Download download = page.waitForDownload(() -> page.click("a"));
|
||||
assertEquals(server.PREFIX + "/downloadWithFilename", download.url());
|
||||
assertEquals("file.txt", download.suggestedFilename());
|
||||
try {
|
||||
@@ -78,9 +76,7 @@ public class TestDownload extends TestBase {
|
||||
void shouldReportDownloadsWithAcceptDownloadsTrue() throws IOException {
|
||||
Page page = browser.newPage(new Browser.NewPageOptions().withAcceptDownloads(true));
|
||||
page.setContent("<a href='" + server.PREFIX + "/download'>download</a>");
|
||||
Deferred<Event<Page.EventType>> downloadEvent = page.futureEvent(DOWNLOAD);
|
||||
page.click("a");
|
||||
Download download = (Download) downloadEvent.get().data();
|
||||
Download download = page.waitForDownload(() -> page.click("a"));
|
||||
Path path = download.path();
|
||||
assertTrue(Files.exists(path));
|
||||
byte[] bytes = readAllBytes(path);
|
||||
@@ -92,9 +88,7 @@ public class TestDownload extends TestBase {
|
||||
void shouldSaveToUserSpecifiedPath() throws IOException {
|
||||
Page page = browser.newPage(new Browser.NewPageOptions().withAcceptDownloads(true));
|
||||
page.setContent("<a href='" + server.PREFIX + "/download'>download</a>");
|
||||
Deferred<Event<Page.EventType>> downloadEvent = page.futureEvent(DOWNLOAD);
|
||||
page.click("a");
|
||||
Download download = (Download) downloadEvent.get().data();
|
||||
Download download = page.waitForDownload(() -> page.click("a"));
|
||||
|
||||
Path userFile = Files.createTempFile("download-", ".txt");
|
||||
download.saveAs(userFile);
|
||||
@@ -108,9 +102,7 @@ public class TestDownload extends TestBase {
|
||||
void shouldSaveToUserSpecifiedPathWithoutUpdatingOriginalPath() throws IOException {
|
||||
Page page = browser.newPage(new Browser.NewPageOptions().withAcceptDownloads(true));
|
||||
page.setContent("<a href='" + server.PREFIX + "/download'>download</a>");
|
||||
Deferred<Event<Page.EventType>> downloadEvent = page.futureEvent(DOWNLOAD);
|
||||
page.click("a");
|
||||
Download download = (Download) downloadEvent.get().data();
|
||||
Download download = page.waitForDownload(() -> page.click("a"));
|
||||
|
||||
Path userFile = Files.createTempFile("download-", ".txt");
|
||||
download.saveAs(userFile);
|
||||
@@ -133,9 +125,7 @@ public class TestDownload extends TestBase {
|
||||
void shouldSaveToTwoDifferentPathsWithMultipleSaveAsCalls() throws IOException {
|
||||
Page page = browser.newPage(new Browser.NewPageOptions().withAcceptDownloads(true));
|
||||
page.setContent("<a href='" + server.PREFIX + "/download'>download</a>");
|
||||
Deferred<Event<Page.EventType>> downloadEvent = page.futureEvent(DOWNLOAD);
|
||||
page.click("a");
|
||||
Download download = (Download) downloadEvent.get().data();
|
||||
Download download = page.waitForDownload(() -> page.click("a"));
|
||||
{
|
||||
Path userFile = Files.createTempFile("download-", ".txt");
|
||||
download.saveAs(userFile);
|
||||
@@ -157,9 +147,7 @@ public class TestDownload extends TestBase {
|
||||
void shouldSaveToOverwrittenFilepath() throws IOException {
|
||||
Page page = browser.newPage(new Browser.NewPageOptions().withAcceptDownloads(true));
|
||||
page.setContent("<a href='" + server.PREFIX + "/download'>download</a>");
|
||||
Deferred<Event<Page.EventType>> downloadEvent = page.futureEvent(DOWNLOAD);
|
||||
page.click("a");
|
||||
Download download = (Download) downloadEvent.get().data();
|
||||
Download download = page.waitForDownload(() -> page.click("a"));
|
||||
Path userFile = Files.createTempFile("download-", ".txt");
|
||||
{
|
||||
download.saveAs(userFile);
|
||||
@@ -180,9 +168,7 @@ public class TestDownload extends TestBase {
|
||||
void shouldCreateSubdirectoriesWhenSavingToNonExistentUserSpecifiedPath() throws IOException {
|
||||
Page page = browser.newPage(new Browser.NewPageOptions().withAcceptDownloads(true));
|
||||
page.setContent("<a href='" + server.PREFIX + "/download'>download</a>");
|
||||
Deferred<Event<Page.EventType>> downloadEvent = page.futureEvent(DOWNLOAD);
|
||||
page.click("a");
|
||||
Download download = (Download) downloadEvent.get().data();
|
||||
Download download = page.waitForDownload(() -> page.click("a"));
|
||||
|
||||
Path downloads = Files.createTempDirectory("downloads");
|
||||
Path nestedPath = downloads.resolve(Paths.get("these", "are", "directories", "download.txt"));
|
||||
@@ -201,9 +187,7 @@ public class TestDownload extends TestBase {
|
||||
void shouldErrorWhenSavingWithDownloadsDisabled() throws IOException {
|
||||
Page page = browser.newPage(new Browser.NewPageOptions().withAcceptDownloads(false));
|
||||
page.setContent("<a href='" + server.PREFIX + "/download'>download</a>");
|
||||
Deferred<Event<Page.EventType>> downloadEvent = page.futureEvent(DOWNLOAD);
|
||||
page.click("a");
|
||||
Download download = (Download) downloadEvent.get().data();
|
||||
Download download = page.waitForDownload(() -> page.click("a"));
|
||||
|
||||
Path userPath = Files.createTempFile("download-", ".txt");
|
||||
try {
|
||||
@@ -219,9 +203,7 @@ public class TestDownload extends TestBase {
|
||||
void shouldErrorWhenSavingAfterDeletion() throws IOException {
|
||||
Page page = browser.newPage(new Browser.NewPageOptions().withAcceptDownloads(true));
|
||||
page.setContent("<a href='" + server.PREFIX + "/download'>download</a>");
|
||||
Deferred<Event<Page.EventType>> downloadEvent = page.futureEvent(DOWNLOAD);
|
||||
page.click("a");
|
||||
Download download = (Download) downloadEvent.get().data();
|
||||
Download download = page.waitForDownload(() -> page.click("a"));
|
||||
|
||||
Path userPath = Files.createTempFile("download-", ".txt");
|
||||
download.delete();
|
||||
@@ -252,9 +234,7 @@ public class TestDownload extends TestBase {
|
||||
Page page = browser.newPage(new Browser.NewPageOptions().withAcceptDownloads(true));
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
page.setContent("<a download='file.txt' href='" + server.PREFIX + "/download'>download</a>");
|
||||
Deferred<Event<Page.EventType>> downloadEvent = page.futureEvent(DOWNLOAD);
|
||||
page.click("a");
|
||||
Download download = (Download) downloadEvent.get().data();
|
||||
Download download = page.waitForDownload(() -> page.click("a"));
|
||||
|
||||
assertEquals("file.txt", download.suggestedFilename());
|
||||
Path path = download.path();
|
||||
@@ -320,9 +300,7 @@ public class TestDownload extends TestBase {
|
||||
});
|
||||
Page page = browser.newPage(new Browser.NewPageOptions().withAcceptDownloads(true));
|
||||
page.setContent("<a href='" + server.PREFIX + "/download'>download</a>");
|
||||
Deferred<Event<Page.EventType>> downloadEvent = page.futureEvent(DOWNLOAD);
|
||||
page.click("a", new Page.ClickOptions().withModifiers(ALT));
|
||||
Download download = (Download) downloadEvent.get().data();
|
||||
Download download = page.waitForDownload(() -> page.click("a", new Page.ClickOptions().withModifiers(ALT)));
|
||||
Path path = download.path();
|
||||
assertTrue(Files.exists(path));
|
||||
byte[] bytes = readAllBytes(path);
|
||||
@@ -343,9 +321,7 @@ public class TestDownload extends TestBase {
|
||||
// - WebKit doesn't close the popup page
|
||||
Page page = browser.newPage(new Browser.NewPageOptions().withAcceptDownloads(true));
|
||||
page.setContent("<a target=_blank href='" + server.PREFIX + "/download'>download</a>");
|
||||
Deferred<Event<Page.EventType>> downloadEvent = page.futureEvent(DOWNLOAD);
|
||||
page.click("a");
|
||||
Download download = (Download) downloadEvent.get().data();
|
||||
Download download = page.waitForDownload(() -> page.click("a"));
|
||||
Path path = download.path();
|
||||
assertTrue(Files.exists(path));
|
||||
byte[] bytes = readAllBytes(path);
|
||||
@@ -357,9 +333,7 @@ public class TestDownload extends TestBase {
|
||||
void shouldDeleteFile() {
|
||||
Page page = browser.newPage(new Browser.NewPageOptions().withAcceptDownloads(true));
|
||||
page.setContent("<a href='" + server.PREFIX + "/download'>download</a>");
|
||||
Deferred<Event<Page.EventType>> downloadEvent = page.futureEvent(DOWNLOAD);
|
||||
page.click("a");
|
||||
Download download = (Download) downloadEvent.get().data();
|
||||
Download download = page.waitForDownload(() -> page.click("a"));
|
||||
Path path = download.path();
|
||||
assertTrue(Files.exists(path));
|
||||
download.delete();
|
||||
@@ -371,9 +345,7 @@ public class TestDownload extends TestBase {
|
||||
void shouldExposeStream() throws IOException {
|
||||
Page page = browser.newPage(new Browser.NewPageOptions().withAcceptDownloads(true));
|
||||
page.setContent("<a href='" + server.PREFIX + "/download'>download</a>");
|
||||
Deferred<Event<Page.EventType>> downloadEvent = page.futureEvent(DOWNLOAD);
|
||||
page.click("a");
|
||||
Download download = (Download) downloadEvent.get().data();
|
||||
Download download = page.waitForDownload(() -> page.click("a"));
|
||||
|
||||
InputStream stream = download.createReadStream();
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
@@ -386,14 +358,8 @@ public class TestDownload extends TestBase {
|
||||
void shouldDeleteDownloadsOnContextDestruction() {
|
||||
Page page = browser.newPage(new Browser.NewPageOptions().withAcceptDownloads(true));
|
||||
page.setContent("<a href='" + server.PREFIX + "/download'>download</a>");
|
||||
Deferred<Event<Page.EventType>> downloadEvent1 = page.futureEvent(DOWNLOAD);
|
||||
page.click("a");
|
||||
Download download1 = (Download) downloadEvent1.get().data();
|
||||
|
||||
Deferred<Event<Page.EventType>> downloadEvent2 = page.futureEvent(DOWNLOAD);
|
||||
page.click("a");
|
||||
Download download2 = (Download) downloadEvent2.get().data();
|
||||
|
||||
Download download1 = page.waitForDownload(() -> page.click("a"));
|
||||
Download download2 = page.waitForDownload(() -> page.click("a"));
|
||||
Path path1 = download1.path();
|
||||
Path path2 = download2.path();
|
||||
assertTrue(Files.exists(path1));
|
||||
@@ -408,14 +374,8 @@ public class TestDownload extends TestBase {
|
||||
Browser browser = browserType.launch();
|
||||
Page page = browser.newPage(new Browser.NewPageOptions().withAcceptDownloads(true));
|
||||
page.setContent("<a href='" + server.PREFIX + "/download'>download</a>");
|
||||
Deferred<Event<Page.EventType>> downloadEvent1 = page.futureEvent(DOWNLOAD);
|
||||
page.click("a");
|
||||
Download download1 = (Download) downloadEvent1.get().data();
|
||||
|
||||
Deferred<Event<Page.EventType>> downloadEvent2 = page.futureEvent(DOWNLOAD);
|
||||
page.click("a");
|
||||
Download download2 = (Download) downloadEvent2.get().data();
|
||||
|
||||
Download download1 = page.waitForDownload(() -> page.click("a"));
|
||||
Download download2 = page.waitForDownload(() -> page.click("a"));
|
||||
Path path1 = download1.path();
|
||||
Path path2 = download2.path();
|
||||
assertTrue(Files.exists(path1));
|
||||
|
||||
@@ -96,15 +96,14 @@ public class TestElementHandleOwnerFrame extends TestBase {
|
||||
@Test
|
||||
void shouldWorkForAdoptedElements() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Event<Page.EventType>> popupEvent = page.futureEvent(Page.EventType.POPUP);
|
||||
page.evaluate("url => window['__popup'] = window.open(url)", server.EMPTY_PAGE);
|
||||
Page popup = page.waitForPopup(() ->
|
||||
page.evaluate("url => window['__popup'] = window.open(url)", server.EMPTY_PAGE));
|
||||
JSHandle divHandle = page.evaluateHandle("() => {\n" +
|
||||
" const div = document.createElement('div');\n" +
|
||||
" document.body.appendChild(div);\n" +
|
||||
" return div;\n" +
|
||||
"}");
|
||||
assertEquals(page.mainFrame(), divHandle.asElement().ownerFrame());
|
||||
Page popup = (Page) popupEvent.get().data();
|
||||
popup.waitForLoadState(Page.LoadState.DOMCONTENTLOADED);
|
||||
page.evaluate("() => {\n" +
|
||||
" const div = document.querySelector('div');\n" +
|
||||
|
||||
+2
-3
@@ -31,8 +31,8 @@ public class TestElementHandleQuerySelector extends TestBase {
|
||||
@Test
|
||||
void shouldWorkForAdoptedElements() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Event<Page.EventType>> popupEvent = page.futureEvent(Page.EventType.POPUP);
|
||||
page.evaluate("url => window['__popup'] = window.open(url)", server.EMPTY_PAGE);
|
||||
Page popup = page.waitForPopup(() -> page.evaluate(
|
||||
"url => window['__popup'] = window.open(url)", server.EMPTY_PAGE));
|
||||
// Test JSHandle
|
||||
JSHandle divHandle = page.evaluateHandle("() => {\n" +
|
||||
" const div = document.createElement('div');\n" +
|
||||
@@ -45,7 +45,6 @@ public class TestElementHandleQuerySelector extends TestBase {
|
||||
assertNotNull(divHandle.asElement().querySelector("span"));
|
||||
assertEquals("hello", divHandle.asElement().querySelector("span").evaluate( "e => e.textContent"));
|
||||
// Test Popup
|
||||
Page popup = (Page) popupEvent.get().data();
|
||||
popup.waitForLoadState(Page.LoadState.DOMCONTENTLOADED);
|
||||
page.evaluate("() => {\n" +
|
||||
" const div = document.querySelector('div');\n" +
|
||||
|
||||
@@ -120,19 +120,26 @@ public class TestGeolocation extends TestBase {
|
||||
" }, err => {});\n" +
|
||||
"}");
|
||||
{
|
||||
Deferred<Event<Page.EventType>> deferred = page.futureEvent(CONSOLE, event -> ((ConsoleMessage) event.data()).text().contains("lat=0 lng=10"));
|
||||
context.setGeolocation(new Geolocation(0, 10));
|
||||
deferred.get();
|
||||
ConsoleMessage message = page.waitForConsole(() -> context.setGeolocation(new Geolocation(0, 10)));
|
||||
// Location change events come several times so we loop until expected one is received.
|
||||
while (!message.text().contains("lat=0 lng=10")) {
|
||||
message = page.waitForConsole(() -> {});
|
||||
}
|
||||
assertTrue(message.text().contains("lat=0 lng=10"), message.text());
|
||||
}
|
||||
{
|
||||
Deferred<Event<Page.EventType>> deferred = page.futureEvent(CONSOLE, event -> ((ConsoleMessage) event.data()).text().contains("lat=20 lng=30"));
|
||||
context.setGeolocation(new Geolocation(20, 30));
|
||||
deferred.get();
|
||||
ConsoleMessage message = page.waitForConsole(() -> context.setGeolocation(new Geolocation(20, 30)));
|
||||
while (!message.text().contains("lat=20 lng=30")) {
|
||||
message = page.waitForConsole(() -> {});
|
||||
}
|
||||
assertTrue(message.text().contains("lat=20 lng=30"), message.text());
|
||||
}
|
||||
{
|
||||
Deferred<Event<Page.EventType>> deferred = page.futureEvent(CONSOLE, event -> ((ConsoleMessage) event.data()).text().contains("lat=40 lng=50"));
|
||||
context.setGeolocation(new Geolocation(40, 50));
|
||||
deferred.get();
|
||||
ConsoleMessage message = page.waitForConsole(() -> context.setGeolocation(new Geolocation(40, 50)));
|
||||
while (!message.text().contains("lat=40 lng=50")) {
|
||||
message = page.waitForConsole(() -> {});
|
||||
}
|
||||
assertTrue(message.text().contains("lat=40 lng=50"), message.text());
|
||||
}
|
||||
assertTrue(messages.contains("lat=0 lng=10"));
|
||||
assertTrue(messages.contains("lat=20 lng=30"));
|
||||
@@ -143,9 +150,8 @@ public class TestGeolocation extends TestBase {
|
||||
void shouldUseContextOptionsForPopup() {
|
||||
context.grantPermissions(asList("geolocation"));
|
||||
context.setGeolocation(new Geolocation(10, 10));
|
||||
Deferred<Event<Page.EventType>> popupEvent = page.futureEvent(POPUP);
|
||||
page.evaluate("url => window['_popup'] = window.open(url)", server.PREFIX + "/geolocation.html");
|
||||
Page popup = (Page) popupEvent.get().data();
|
||||
Page popup = page.waitForPopup(() -> page.evaluate(
|
||||
"url => window['_popup'] = window.open(url)", server.PREFIX + "/geolocation.html"));
|
||||
popup.waitForLoadState();
|
||||
Object geolocation = popup.evaluate("window['geolocationPromise']");
|
||||
assertEquals(mapOf("longitude", 10, "latitude", 10), geolocation);
|
||||
|
||||
@@ -132,13 +132,13 @@ public class TestNetworkRequest extends TestBase {
|
||||
writer.write("done");
|
||||
}
|
||||
});
|
||||
Deferred<Event<Page.EventType>> responsePromise = page.futureEvent(RESPONSE);
|
||||
Object text = page.evaluate("async url => {\n" +
|
||||
" const data = await fetch(url);\n" +
|
||||
" return data.text();\n" +
|
||||
"}", server.CROSS_PROCESS_PREFIX + "/something");
|
||||
assertEquals("done", text);
|
||||
Response response = (Response) responsePromise.get().data();
|
||||
Response response = page.waitForResponse(() -> {
|
||||
Object text = page.evaluate("async url => {\n" +
|
||||
" const data = await fetch(url);\n" +
|
||||
" return data.text();\n" +
|
||||
"}", server.CROSS_PROCESS_PREFIX + "/something");
|
||||
assertEquals("done", text);
|
||||
});
|
||||
Map<String, String> expectedHeaders = serverRequest.get().headers.entrySet().stream().collect(
|
||||
Collectors.toMap(e -> e.getKey().toLowerCase(), e -> e.getValue().get(0)));
|
||||
assertEquals(expectedHeaders, response.request().headers());
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.util.Arrays;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.microsoft.playwright.Page.EventType.REQUESTFINISHED;
|
||||
import static com.microsoft.playwright.Page.EventType.RESPONSE;
|
||||
@@ -105,11 +106,9 @@ public class TestNetworkResponse extends TestBase {
|
||||
requestFinished[0] |= ((Request) event.data()).url().contains("/get");
|
||||
});
|
||||
// send request and wait for server response
|
||||
Deferred<Event<Page.EventType>> responseEvent = page.futureEvent(RESPONSE);
|
||||
page.evaluate("() => fetch('./get', { method: 'GET'})");
|
||||
assertNotNull(responseEvent.get());
|
||||
Response pageResponse = page.waitForResponse(() -> page.evaluate("() => fetch('./get', { method: 'GET'})"));
|
||||
assertNotNull(pageResponse);
|
||||
responseWritten.acquire();
|
||||
Response pageResponse = (Response) responseEvent.get().data();
|
||||
assertEquals(200, pageResponse.status());
|
||||
assertEquals(false, requestFinished[0]);
|
||||
responseRead.release();
|
||||
|
||||
@@ -59,19 +59,28 @@ public class TestPageBasic extends TestBase {
|
||||
// We have to interact with a page so that "beforeunload" handlers
|
||||
// fire.
|
||||
newPage.click("body");
|
||||
Deferred<Event<Page.EventType>> event = newPage.futureEvent(DIALOG);
|
||||
boolean[] didShowDialog = {false};
|
||||
newPage.onDialog(dialog -> {
|
||||
didShowDialog[0] = true;
|
||||
assertEquals(Dialog.Type.BEFOREUNLOAD, dialog.type());
|
||||
assertEquals("", dialog.defaultValue());
|
||||
if (isChromium()) {
|
||||
assertEquals("", dialog.message());
|
||||
} else if (isWebKit()) {
|
||||
assertEquals("Leave?", dialog.message());
|
||||
} else {
|
||||
assertEquals("This page is asking you to confirm that you want to leave - data you have entered may not be saved.", dialog.message());
|
||||
}
|
||||
dialog.accept();
|
||||
});
|
||||
newPage.close(new Page.CloseOptions().withRunBeforeUnload(true));
|
||||
Dialog dialog = (Dialog) event.get().data();
|
||||
assertEquals(Dialog.Type.BEFOREUNLOAD, dialog.type());
|
||||
assertEquals("", dialog.defaultValue());
|
||||
if (isChromium()) {
|
||||
assertEquals("", dialog.message());
|
||||
} else if (isWebKit()) {
|
||||
assertEquals("Leave?", dialog.message());
|
||||
} else {
|
||||
assertEquals("This page is asking you to confirm that you want to leave - data you have entered may not be saved.", dialog.message());
|
||||
for (int i = 0; i < 300; i++) {
|
||||
if (didShowDialog[0]) {
|
||||
break;
|
||||
}
|
||||
page.waitForTimeout(100);
|
||||
}
|
||||
dialog.accept();
|
||||
assertTrue(didShowDialog[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -98,19 +107,17 @@ public class TestPageBasic extends TestBase {
|
||||
@Test
|
||||
void shouldTerminateNetworkWaiters() {
|
||||
Page newPage = context.newPage();
|
||||
Deferred<Request> request = newPage.futureRequest(server.EMPTY_PAGE);
|
||||
Deferred<Response> response = newPage.futureResponse(server.EMPTY_PAGE);
|
||||
newPage.close();
|
||||
try {
|
||||
request.get();
|
||||
fail("get() should throw");
|
||||
} catch (PlaywrightException e) {
|
||||
assertTrue(e.getMessage().contains("Page closed"));
|
||||
assertFalse(e.getMessage().contains("Timeout"));
|
||||
}
|
||||
try {
|
||||
response.get();
|
||||
fail("get() should throw");
|
||||
newPage.waitForResponse(() -> {
|
||||
try {
|
||||
newPage.waitForRequest(() -> newPage.close(), server.EMPTY_PAGE);
|
||||
fail("waitForRequest() should throw");
|
||||
} catch (PlaywrightException e) {
|
||||
assertTrue(e.getMessage().contains("Page closed"));
|
||||
assertFalse(e.getMessage().contains("Timeout"));
|
||||
}
|
||||
});
|
||||
fail("waitForResponse() should throw");
|
||||
} catch (PlaywrightException e) {
|
||||
assertTrue(e.getMessage().contains("Page closed"));
|
||||
assertFalse(e.getMessage().contains("Timeout"));
|
||||
@@ -137,18 +144,14 @@ public class TestPageBasic extends TestBase {
|
||||
|
||||
@Test
|
||||
void shouldProvideAccessToTheOpenerPage() {
|
||||
Deferred<Event<Page.EventType>> popupEvent = page.futureEvent(POPUP);
|
||||
page.evaluate("() => window.open('about:blank')");
|
||||
Page popup = (Page) popupEvent.get().data();
|
||||
Page popup = page.waitForPopup(() -> page.evaluate("() => window.open('about:blank')"));
|
||||
Page opener = popup.opener();
|
||||
assertEquals(page, opener);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnNullIfParentPageHasBeenClosed() {
|
||||
Deferred<Event<Page.EventType>> popupEvent = page.futureEvent(POPUP);
|
||||
page.evaluate("() => window.open('about:blank')");
|
||||
Page popup = (Page) popupEvent.get().data();
|
||||
Page popup = page.waitForPopup(() -> page.evaluate("() => window.open('about:blank')"));
|
||||
page.close();
|
||||
Page opener = popup.opener();
|
||||
assertEquals(null, opener);
|
||||
@@ -189,20 +192,15 @@ public class TestPageBasic extends TestBase {
|
||||
|
||||
@Test
|
||||
void pageCloseShouldWorkWithWindowClose() {
|
||||
Deferred<Event<Page.EventType>> newPagePromise = page.futureEvent(POPUP);
|
||||
page.evaluate("() => window['newPage'] = window.open('about:blank')");
|
||||
Page newPage = (Page) newPagePromise.get().data();
|
||||
Deferred<Event<Page.EventType>> closedPromise = newPage.futureEvent(CLOSE);
|
||||
page.evaluate("() => window['newPage'].close()");
|
||||
closedPromise.get();
|
||||
Page newPage = page.waitForPopup(() -> page.evaluate(
|
||||
"() => window['newPage'] = window.open('about:blank')"));
|
||||
newPage.waitForClose(() -> page.evaluate("() => window['newPage'].close()"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void pageCloseShouldWorkWithPageClose() {
|
||||
Page newPage = context.newPage();
|
||||
Deferred<Event<Page.EventType>> closedPromise = newPage.futureEvent(CLOSE);
|
||||
newPage.close();
|
||||
closedPromise.get();
|
||||
newPage.waitForClose(() -> newPage.close());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -86,9 +86,8 @@ public class TestPageEmulateMedia extends TestBase {
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions().withColorScheme(DARK));
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Event<Page.EventType>> popupEvent = page.futureEvent(POPUP);
|
||||
page.evaluate("url => { window.open(url); }", server.EMPTY_PAGE);
|
||||
Page popup = (Page) popupEvent.get().data();
|
||||
Page popup = page.waitForPopup(() ->
|
||||
page.evaluate("url => { window.open(url); }", server.EMPTY_PAGE));
|
||||
assertEquals(false, popup.evaluate("() => matchMedia('(prefers-color-scheme: light)').matches"));
|
||||
assertEquals(true, popup.evaluate("() => matchMedia('(prefers-color-scheme: dark)').matches"));
|
||||
context.close();
|
||||
@@ -96,9 +95,8 @@ public class TestPageEmulateMedia extends TestBase {
|
||||
{
|
||||
Page page = browser.newPage(new Browser.NewPageOptions().withColorScheme(LIGHT));
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Event<Page.EventType>> popupEvent = page.futureEvent(POPUP);
|
||||
page.evaluate("url => { window.open(url); }", server.EMPTY_PAGE);
|
||||
Page popup = (Page) popupEvent.get().data();
|
||||
Page popup = page.waitForPopup(() ->
|
||||
page.evaluate("url => { window.open(url); }", server.EMPTY_PAGE));
|
||||
assertEquals(true, popup.evaluate("() => matchMedia('(prefers-color-scheme: light)').matches"));
|
||||
assertEquals(false, popup.evaluate("() => matchMedia('(prefers-color-scheme: dark)').matches"));
|
||||
page.close();
|
||||
|
||||
@@ -435,19 +435,17 @@ public class TestPageEvaluate extends TestBase {
|
||||
|
||||
@Test
|
||||
void shouldThrowANiceErrorAfterANavigation() {
|
||||
Deferred<Response> navigation = page.futureNavigation();
|
||||
try {
|
||||
page.evaluate("() => {\n" +
|
||||
" const promise = new Promise(f => window['__resolve'] = f);\n" +
|
||||
" window.location.reload();\n" +
|
||||
" setTimeout(() => window['__resolve'](42), 1000);\n" +
|
||||
" return promise;\n" +
|
||||
"}");
|
||||
navigation.get();
|
||||
page.waitForNavigation(() -> {
|
||||
page.evaluate("() => {\n" +
|
||||
" const promise = new Promise(f => window['__resolve'] = f);\n" +
|
||||
" window.location.reload();\n" +
|
||||
" setTimeout(() => window['__resolve'](42), 1000);\n" +
|
||||
" return promise;\n" +
|
||||
"}");
|
||||
});
|
||||
} catch (PlaywrightException e) {
|
||||
assertTrue(e.getMessage().contains("navigation"));
|
||||
// The code may throw before navigation resolves, make sure .get() is called in that case too.
|
||||
navigation.get();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,10 +79,13 @@ public class TestPageEventNetwork extends TestBase {
|
||||
|
||||
@Test
|
||||
void PageEventsRequestFinished() {
|
||||
Deferred<Event<Page.EventType>> event = page.futureEvent(REQUESTFINISHED);
|
||||
Response response = page.navigate(server.EMPTY_PAGE);
|
||||
event.get();
|
||||
Request request = response.request();
|
||||
Response[] response = {null};
|
||||
Request finishedRequest = page.waitForRequestFinished(() -> {
|
||||
response[0] = page.navigate(server.EMPTY_PAGE);
|
||||
});
|
||||
assertNotNull(response[0]);
|
||||
Request request = response[0].request();
|
||||
assertEquals(request, finishedRequest);
|
||||
assertEquals(server.EMPTY_PAGE, request.url());
|
||||
assertNotNull(request.response());
|
||||
assertEquals(page.mainFrame(), request.frame());
|
||||
|
||||
@@ -184,12 +184,12 @@ public class TestPageExposeFunction extends TestBase {
|
||||
}, new Page.ExposeBindingOptions().withHandle(true));
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
|
||||
Deferred<Response> navigation = page.futureNavigation(new Page.FutureNavigationOptions().withWaitUntil(LOAD));
|
||||
page.evaluate("async url => {\n" +
|
||||
" window['logme']({ foo: 42 });\n" +
|
||||
" window.location.href = url;\n" +
|
||||
"}", server.PREFIX + "/one-style.html");
|
||||
navigation.get();
|
||||
page.waitForNavigation(() -> {
|
||||
page.evaluate("async url => {\n" +
|
||||
" window['logme']({ foo: 42 });\n" +
|
||||
" window.location.href = url;\n" +
|
||||
"}", server.PREFIX + "/one-style.html");
|
||||
}, new Page.WaitForNavigationOptions().withWaitUntil(LOAD));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -101,9 +101,7 @@ public class TestPageRoute extends TestBase {
|
||||
page.setContent("<form action='/rredirect' method='post'>\n" +
|
||||
" <input type='hidden' id='foo' name='foo' value='FOOBAR'>\n" +
|
||||
"</form>");
|
||||
Deferred<Response> navigationResponse = page.futureNavigation();
|
||||
page.evalOnSelector("form", "form => form.submit()");
|
||||
navigationResponse.get();
|
||||
page.waitForNavigation(() -> page.evalOnSelector("form", "form => form.submit()"));
|
||||
}
|
||||
|
||||
// @see https://github.com/GoogleChrome/puppeteer/issues/3973
|
||||
@@ -435,9 +433,8 @@ public class TestPageRoute extends TestBase {
|
||||
Route[] route = {null};
|
||||
page.route("**/*", r -> route[0] = r);
|
||||
// Wait for request interception.
|
||||
Deferred<Event<Page.EventType>> event = page.futureEvent(REQUEST);
|
||||
page.evalOnSelector("iframe", "(frame, url) => frame.src = url", server.EMPTY_PAGE);
|
||||
event.get();
|
||||
page.waitForRequest(() ->
|
||||
page.evalOnSelector("iframe", "(frame, url) => frame.src = url", server.EMPTY_PAGE));
|
||||
// Delete frame to cause request to be canceled.
|
||||
page.evalOnSelector("iframe", "frame => frame.remove()");
|
||||
try {
|
||||
|
||||
@@ -94,9 +94,7 @@ public class TestPageSelectOption extends TestBase {
|
||||
void shouldNotThrowWhenSelectCausesNavigation() {
|
||||
page.navigate(server.PREFIX + "/input/select.html");
|
||||
page.evalOnSelector("select", "select => select.addEventListener('input', () => window.location.href = '/empty.html')");
|
||||
Deferred<Response> response = page.futureNavigation();
|
||||
page.selectOption("select", "blue");
|
||||
response.get();
|
||||
page.waitForNavigation(() -> page.selectOption("select", "blue"));
|
||||
assertTrue(page.url().contains("empty.html"));
|
||||
}
|
||||
|
||||
|
||||
@@ -67,9 +67,7 @@ public class TestPageSetInputFiles extends TestBase {
|
||||
@Test
|
||||
void shouldEmitEventOnce() {
|
||||
page.setContent("<input type=file>");
|
||||
Deferred<Event<Page.EventType>> event = page.futureEvent(Page.EventType.FILECHOOSER);
|
||||
page.click("input");
|
||||
FileChooser chooser = (FileChooser) event.get().data();
|
||||
FileChooser chooser = page.waitForFileChooser(() -> page.click("input"));
|
||||
assertNotNull(chooser);
|
||||
}
|
||||
|
||||
@@ -99,20 +97,20 @@ public class TestPageSetInputFiles extends TestBase {
|
||||
@Test
|
||||
void shouldWorkWhenFileInputIsAttachedToDOM() {
|
||||
page.setContent("<input type=file>");
|
||||
Deferred<Event<Page.EventType>> chooser = page.futureEvent(Page.EventType.FILECHOOSER);
|
||||
page.click("input");
|
||||
assertNotNull(chooser.get());
|
||||
FileChooser chooser = page.waitForFileChooser(() -> page.click("input"));
|
||||
assertNotNull(chooser);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWorkWhenFileInputIsNotAttachedToDOM() {
|
||||
Deferred<Event<Page.EventType>> chooser = page.futureEvent(Page.EventType.FILECHOOSER);
|
||||
page.evaluate("() => {\n" +
|
||||
" const el = document.createElement('input');\n" +
|
||||
" el.type = 'file';\n" +
|
||||
" el.click();\n" +
|
||||
"}");
|
||||
assertNotNull(chooser.get());
|
||||
FileChooser chooser = page.waitForFileChooser(() -> {
|
||||
page.evaluate("() => {\n" +
|
||||
" const el = document.createElement('input');\n" +
|
||||
" el.type = 'file';\n" +
|
||||
" el.click();\n" +
|
||||
"}");
|
||||
});
|
||||
assertNotNull(chooser);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -128,8 +126,7 @@ public class TestPageSetInputFiles extends TestBase {
|
||||
@Test
|
||||
void shouldRespectTimeout() {
|
||||
try {
|
||||
Deferred<Event<Page.EventType>> event = page.futureEvent(Page.EventType.FILECHOOSER, new Page.FutureEventOptions().withTimeout(1));
|
||||
event.get();
|
||||
page.waitForFileChooser(() -> {}, new Page.WaitForFileChooserOptions().withTimeout(1));
|
||||
fail("did not throw");
|
||||
} catch (PlaywrightException e) {
|
||||
assertTrue(e.getMessage().contains("Timeout 1ms exceeded"));
|
||||
@@ -140,8 +137,7 @@ public class TestPageSetInputFiles extends TestBase {
|
||||
void shouldRespectDefaultTimeoutWhenThereIsNoCustomTimeout() {
|
||||
page.setDefaultTimeout(1);
|
||||
try {
|
||||
Deferred<Event<Page.EventType>> event = page.futureEvent(Page.EventType.FILECHOOSER);
|
||||
event.get();
|
||||
page.waitForFileChooser(() -> {});
|
||||
fail("did not throw");
|
||||
} catch (PlaywrightException e) {
|
||||
assertTrue(e.getMessage().contains("Timeout 1ms exceeded"));
|
||||
@@ -151,10 +147,8 @@ public class TestPageSetInputFiles extends TestBase {
|
||||
@Test
|
||||
void shouldPrioritizeExactTimeoutOverDefaultTimeout() {
|
||||
page.setDefaultTimeout(0);
|
||||
Deferred<Event<Page.EventType>> event = page.futureEvent(Page.EventType.FILECHOOSER,
|
||||
new Page.FutureEventOptions().withTimeout(1));
|
||||
try {
|
||||
event.get();
|
||||
page.waitForFileChooser(() -> {}, new Page.WaitForFileChooserOptions().withTimeout(1));
|
||||
fail("did not throw");
|
||||
} catch (PlaywrightException e) {
|
||||
assertTrue(e.getMessage().contains("Timeout 1ms exceeded"));
|
||||
@@ -163,31 +157,32 @@ public class TestPageSetInputFiles extends TestBase {
|
||||
|
||||
@Test
|
||||
void shouldWorkWithNoTimeout() {
|
||||
Deferred<Event<Page.EventType>> event = page.futureEvent(Page.EventType.FILECHOOSER,
|
||||
new Page.FutureEventOptions().withTimeout(0));
|
||||
page.evaluate("() => setTimeout(() => {\n" +
|
||||
" const el = document.createElement('input');\n" +
|
||||
" el.type = 'file';\n" +
|
||||
" el.click();\n" +
|
||||
"}, 50)");
|
||||
assertNotNull(event.get().data());
|
||||
FileChooser fileChooser = page.waitForFileChooser(() -> {
|
||||
page.evaluate("() => setTimeout(() => {\n" +
|
||||
" const el = document.createElement('input');\n" +
|
||||
" el.type = 'file';\n" +
|
||||
" el.click();\n" +
|
||||
"}, 50)");
|
||||
}, new Page.WaitForFileChooserOptions().withTimeout(0));
|
||||
assertNotNull(fileChooser);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnTheSameFileChooserWhenThereAreManyWatchdogsSimultaneously() {
|
||||
page.setContent("<input type=file>");
|
||||
Deferred<Event<Page.EventType>> fileChooser1 = page.futureEvent(Page.EventType.FILECHOOSER);
|
||||
Deferred<Event<Page.EventType>> fileChooser2 = page.futureEvent(Page.EventType.FILECHOOSER);
|
||||
page.evalOnSelector("input", "input => input.click()");
|
||||
assertEquals(fileChooser1.get().data(), fileChooser2.get().data());
|
||||
FileChooser[] fileChooser = {null};
|
||||
FileChooser fileChooser1 = page.waitForFileChooser(() -> {
|
||||
fileChooser[0] = page.waitForFileChooser(() -> {
|
||||
page.evalOnSelector("input", "input => input.click()");
|
||||
});
|
||||
});
|
||||
assertEquals(fileChooser[0], fileChooser1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAcceptSingleFile() {
|
||||
page.setContent("<input type=file oninput='javascript:console.timeStamp()'>");
|
||||
Deferred<Event<Page.EventType>> event = page.futureEvent(Page.EventType.FILECHOOSER);
|
||||
page.click("input");
|
||||
FileChooser fileChooser = (FileChooser) event.get().data();
|
||||
FileChooser fileChooser = page.waitForFileChooser(() -> page.click("input"));
|
||||
assertEquals(page, fileChooser.page());
|
||||
assertNotNull(fileChooser.element());
|
||||
fileChooser.setFiles(FILE_TO_UPLOAD);
|
||||
@@ -255,9 +250,7 @@ public class TestPageSetInputFiles extends TestBase {
|
||||
@Test
|
||||
void shouldNotAcceptMultipleFilesForSingleFileInput() {
|
||||
page.setContent("<input type=file>");
|
||||
Deferred<Event<Page.EventType>> event = page.futureEvent(Page.EventType.FILECHOOSER);
|
||||
page.click("input");
|
||||
FileChooser fileChooser = (FileChooser) event.get().data();
|
||||
FileChooser fileChooser = page.waitForFileChooser(() -> page.click("input"));
|
||||
try {
|
||||
fileChooser.setFiles(new Path[]{FILE_TO_UPLOAD, Paths.get("src/test/resources/pptr.png")});
|
||||
fail("did not throw");
|
||||
@@ -281,27 +274,21 @@ public class TestPageSetInputFiles extends TestBase {
|
||||
@Test
|
||||
void shouldWorkForSingleFilePick() {
|
||||
page.setContent("<input type=file>");
|
||||
Deferred<Event<Page.EventType>> event = page.futureEvent(Page.EventType.FILECHOOSER);
|
||||
page.click("input");
|
||||
FileChooser fileChooser = (FileChooser) event.get().data();
|
||||
FileChooser fileChooser = page.waitForFileChooser(() -> page.click("input"));
|
||||
assertFalse(fileChooser.isMultiple());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWorkForMultiple() {
|
||||
page.setContent("<input multiple type=file>");
|
||||
Deferred<Event<Page.EventType>> event = page.futureEvent(Page.EventType.FILECHOOSER);
|
||||
page.click("input");
|
||||
FileChooser fileChooser = (FileChooser) event.get().data();
|
||||
FileChooser fileChooser = page.waitForFileChooser(() -> page.click("input"));
|
||||
assertTrue(fileChooser.isMultiple());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWorkForWebkitdirectory() {
|
||||
page.setContent("<input multiple webkitdirectory type=file>");
|
||||
Deferred<Event<Page.EventType>> event = page.futureEvent(Page.EventType.FILECHOOSER);
|
||||
page.click("input");
|
||||
FileChooser fileChooser = (FileChooser) event.get().data();
|
||||
FileChooser fileChooser = page.waitForFileChooser(() -> page.click("input"));
|
||||
assertTrue(fileChooser.isMultiple());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,21 +33,20 @@ public class TestPageWaitForNavigation extends TestBase {
|
||||
@Test
|
||||
void shouldWork() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Response> response = page.futureNavigation();
|
||||
page.evaluate("url => window.location.href = url", server.PREFIX + "/grid.html");
|
||||
assertTrue(response.get().ok());
|
||||
assertTrue(response.get().url().contains("grid.html"));
|
||||
Response response = page.waitForNavigation(() -> page.evaluate(
|
||||
"url => window.location.href = url", server.PREFIX + "/grid.html"));
|
||||
assertTrue(response.ok());
|
||||
assertTrue(response.url().contains("grid.html"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRespectTimeout() {
|
||||
Deferred<Response> promise = page.futureNavigation(new Page.FutureNavigationOptions().withUrl("**/frame.html").withTimeout(5000));
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
try {
|
||||
promise.get();
|
||||
page.waitForNavigation(
|
||||
() -> page.navigate(server.EMPTY_PAGE),
|
||||
new Page.WaitForNavigationOptions().withUrl("**/frame.html").withTimeout(5000));
|
||||
fail("did not throw");
|
||||
} catch (PlaywrightException e) {
|
||||
// assertTrue(e.getMessage().contains("page.futureNavigation: Timeout 5000ms exceeded."));
|
||||
assertTrue(e.getMessage().contains("Timeout 5000ms exceeded"));
|
||||
// assertTrue(e.getMessage().contains("waiting for navigation to '**/frame.html' until 'load'"));
|
||||
// assertTrue(e.getMessage().contains("navigated to '${server.EMPTY_PAGE}'"));
|
||||
@@ -62,9 +61,8 @@ public class TestPageWaitForNavigation extends TestBase {
|
||||
void shouldWorkWithClickingOnAnchorLinks() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
page.setContent("<a href='#foobar'>foobar</a>");
|
||||
Deferred<Response> response = page.futureNavigation();
|
||||
page.click("a");
|
||||
assertNull(response.get());
|
||||
Response response = page.waitForNavigation(() -> page.click("a"));
|
||||
assertNull(response);
|
||||
assertEquals(server.EMPTY_PAGE + "#foobar", page.url());
|
||||
}
|
||||
|
||||
@@ -75,11 +73,9 @@ public class TestPageWaitForNavigation extends TestBase {
|
||||
@Test
|
||||
void shouldWorkWithClickingOnLinksWhichDoNotCommitNavigation() throws InterruptedException {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Response> event = page.futureNavigation();
|
||||
page.setContent("<a href='" + httpsServer.EMPTY_PAGE + "'>foobar</a>");
|
||||
try {
|
||||
page.click("a");
|
||||
event.get();
|
||||
page.waitForNavigation(() -> page.click("a"));
|
||||
fail("did not throw");
|
||||
} catch (PlaywrightException e) {
|
||||
// TODO: figure out why it is inconsistent on Linux WebKit.
|
||||
@@ -95,9 +91,8 @@ public class TestPageWaitForNavigation extends TestBase {
|
||||
"<script>\n" +
|
||||
" function pushState() { history.pushState({}, '', 'wow.html') }\n" +
|
||||
"</script>");
|
||||
Deferred<Response> response = page.futureNavigation();
|
||||
page.click("a");
|
||||
assertNull(response.get());
|
||||
Response response = page.waitForNavigation(() -> page.click("a"));
|
||||
assertNull(response);
|
||||
assertEquals(server.PREFIX + "/wow.html", page.url());
|
||||
}
|
||||
|
||||
@@ -108,9 +103,8 @@ public class TestPageWaitForNavigation extends TestBase {
|
||||
"<script>\n" +
|
||||
" function replaceState() { history.replaceState({}, '', '/replaced.html') }\n" +
|
||||
"</script>");
|
||||
Deferred<Response> response = page.futureNavigation();
|
||||
page.click("a");
|
||||
assertNull(response.get());
|
||||
Response response = page.waitForNavigation(() -> page.click("a"));
|
||||
assertNull(response);
|
||||
assertEquals(server.PREFIX + "/replaced.html", page.url());
|
||||
}
|
||||
|
||||
@@ -127,14 +121,13 @@ public class TestPageWaitForNavigation extends TestBase {
|
||||
"</script>");
|
||||
assertEquals(server.PREFIX + "/second.html", page.url());
|
||||
|
||||
Deferred<Response> backResponse = page.futureNavigation();
|
||||
page.click("a#back");
|
||||
assertNull(backResponse.get());
|
||||
Response backResponse = page.waitForNavigation(() -> page.click("a#back"));
|
||||
assertNull(backResponse);
|
||||
assertEquals(server.PREFIX + "/first.html", page.url());
|
||||
|
||||
Deferred<Response> forwardResponse = page.futureNavigation();
|
||||
Response forwardResponse = page.waitForNavigation(() -> page.click("a#forward"));
|
||||
page.click("a#forward");
|
||||
assertNull(forwardResponse.get());
|
||||
assertNull(forwardResponse);
|
||||
assertEquals(server.PREFIX + "/second.html", page.url());
|
||||
}
|
||||
|
||||
@@ -159,51 +152,55 @@ public class TestPageWaitForNavigation extends TestBase {
|
||||
void shouldWorkWithUrlMatch() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
|
||||
Deferred<Response> response1 = page.futureNavigation(new Page.FutureNavigationOptions().withUrl("**/one-style.html"));
|
||||
page.navigate(server.PREFIX + "/one-style.html");
|
||||
assertNotNull(response1.get());
|
||||
assertEquals(server.PREFIX + "/one-style.html", response1.get().url());
|
||||
Response response1 = page.waitForNavigation(
|
||||
() -> page.navigate(server.PREFIX + "/one-style.html"),
|
||||
new Page.WaitForNavigationOptions().withUrl("**/one-style.html"));
|
||||
assertNotNull(response1);
|
||||
assertEquals(server.PREFIX + "/one-style.html", response1.url());
|
||||
|
||||
Deferred<Response> response2 = page.futureNavigation(new Page.FutureNavigationOptions().withUrl(Pattern.compile("frame.html$")));
|
||||
page.navigate(server.PREFIX + "/frame.html");
|
||||
assertNotNull(response2.get());
|
||||
assertEquals(server.PREFIX + "/frame.html", response2.get().url());
|
||||
Response response2 = page.waitForNavigation(
|
||||
() -> page.navigate(server.PREFIX + "/frame.html"),
|
||||
new Page.WaitForNavigationOptions().withUrl(Pattern.compile("frame.html$")));
|
||||
assertNotNull(response2);
|
||||
assertEquals(server.PREFIX + "/frame.html", response2.url());
|
||||
|
||||
Deferred<Response> response3 = page.futureNavigation(new Page.FutureNavigationOptions().withUrl(url -> {
|
||||
try {
|
||||
return new URL(url).getQuery().contains("foo=bar");
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}));
|
||||
page.navigate(server.PREFIX + "/frame.html?foo=bar");
|
||||
assertNotNull(response3.get());
|
||||
assertEquals(server.PREFIX + "/frame.html?foo=bar", response3.get().url());
|
||||
Response response3 = page.waitForNavigation(
|
||||
() -> page.navigate(server.PREFIX + "/frame.html?foo=bar"),
|
||||
new Page.WaitForNavigationOptions().withUrl(url -> {
|
||||
try {
|
||||
return new URL(url).getQuery().contains("foo=bar");
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}));
|
||||
assertNotNull(response3);
|
||||
assertEquals(server.PREFIX + "/frame.html?foo=bar", response3.url());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWorkWithUrlMatchForSameDocumentNavigations() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Response> waitPromise = page.futureNavigation(new Page.FutureNavigationOptions().withUrl("**/third.html"));
|
||||
page.evaluate("() => {\n" +
|
||||
" history.pushState({}, '', '/first.html');\n" +
|
||||
"}");
|
||||
page.evaluate("() => {\n" +
|
||||
" history.pushState({}, '', '/second.html');\n" +
|
||||
"}");
|
||||
page.evaluate("() => {\n" +
|
||||
" history.pushState({}, '', '/third.html');\n" +
|
||||
"}");
|
||||
assertNull(waitPromise.get());
|
||||
Response response = page.waitForNavigation(() -> {
|
||||
page.evaluate("() => {\n" +
|
||||
" history.pushState({}, '', '/first.html');\n" +
|
||||
"}");
|
||||
page.evaluate("() => {\n" +
|
||||
" history.pushState({}, '', '/second.html');\n" +
|
||||
"}");
|
||||
page.evaluate("() => {\n" +
|
||||
" history.pushState({}, '', '/third.html');\n" +
|
||||
"}");
|
||||
}, new Page.WaitForNavigationOptions().withUrl("**/third.html"));
|
||||
assertNull(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWorkForCrossProcessNavigations() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Response> waitPromise = page.futureNavigation(new Page.FutureNavigationOptions().withWaitUntil(Frame.LoadState.DOMCONTENTLOADED));
|
||||
String url = server.CROSS_PROCESS_PREFIX + "/empty.html";
|
||||
page.navigate(url);
|
||||
Response response = waitPromise.get();
|
||||
Response response = page.waitForNavigation(
|
||||
() -> page.navigate(url),
|
||||
new Page.WaitForNavigationOptions().withWaitUntil(Frame.LoadState.DOMCONTENTLOADED));
|
||||
assertEquals(url, response.url());
|
||||
assertEquals(url, page.url());
|
||||
assertEquals(url, page.evaluate("document.location.href"));
|
||||
@@ -213,11 +210,11 @@ public class TestPageWaitForNavigation extends TestBase {
|
||||
void shouldWorkOnFrame() {
|
||||
page.navigate(server.PREFIX + "/frames/one-frame.html");
|
||||
Frame frame = page.frames().get(1);
|
||||
Deferred<Response> response = frame.futureNavigation();
|
||||
frame.evaluate("url => window.location.href = url", server.PREFIX + "/grid.html");
|
||||
assertTrue(response.get().ok());
|
||||
assertTrue(response.get().url().contains("grid.html"));
|
||||
assertEquals(frame, response.get().frame());
|
||||
Response response = frame.waitForNavigation(() ->
|
||||
frame.evaluate("url => window.location.href = url", server.PREFIX + "/grid.html"));
|
||||
assertTrue(response.ok());
|
||||
assertTrue(response.url().contains("grid.html"));
|
||||
assertEquals(frame, response.frame());
|
||||
assertTrue(page.url().contains("/frames/one-frame.html"));
|
||||
}
|
||||
|
||||
@@ -227,12 +224,12 @@ public class TestPageWaitForNavigation extends TestBase {
|
||||
Frame frame = page.frames().get(1);
|
||||
server.setRoute("/empty.html", exchange -> {});
|
||||
try {
|
||||
Deferred<Response> response = frame.futureNavigation();
|
||||
page.evaluate("() => {\n" +
|
||||
" frames[0].location.href = '/empty.html';\n" +
|
||||
" setTimeout(() => document.querySelector('iframe').remove());\n" +
|
||||
"}\n");
|
||||
response.get();
|
||||
frame.waitForNavigation(() -> {
|
||||
page.evaluate("() => {\n" +
|
||||
" frames[0].location.href = '/empty.html';\n" +
|
||||
" setTimeout(() => document.querySelector('iframe').remove());\n" +
|
||||
"}\n");
|
||||
});
|
||||
fail("did not throw");
|
||||
} catch (PlaywrightException e) {
|
||||
// assertTrue(e.getMessage().contains("waiting for navigation until \"load\""));
|
||||
|
||||
@@ -28,32 +28,33 @@ public class TestPageWaitForRequest extends TestBase {
|
||||
@Test
|
||||
void shouldWork() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Request> request = page.futureRequest(server.PREFIX + "/digits/2.png");
|
||||
page.evaluate("() => {\n" +
|
||||
" fetch('/digits/1.png');\n" +
|
||||
" fetch('/digits/2.png');\n" +
|
||||
" fetch('/digits/3.png');\n" +
|
||||
"}");
|
||||
assertEquals(server.PREFIX + "/digits/2.png", request.get().url());
|
||||
Request request = page.waitForRequest(() -> {
|
||||
page.evaluate("() => {\n" +
|
||||
" fetch('/digits/1.png');\n" +
|
||||
" fetch('/digits/2.png');\n" +
|
||||
" fetch('/digits/3.png');\n" +
|
||||
"}");
|
||||
}, server.PREFIX + "/digits/2.png");
|
||||
assertEquals(server.PREFIX + "/digits/2.png", request.url());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWorkWithPredicate() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Request> request = page.futureRequest(url -> url.equals(server.PREFIX + "/digits/2.png"));
|
||||
page.evaluate("() => {\n" +
|
||||
" fetch('/digits/1.png');\n" +
|
||||
" fetch('/digits/2.png');\n" +
|
||||
" fetch('/digits/3.png');\n" +
|
||||
"}");
|
||||
assertEquals(server.PREFIX + "/digits/2.png", request.get().url());
|
||||
Request request = page.waitForRequest(() -> {
|
||||
page.evaluate("() => {\n" +
|
||||
" fetch('/digits/1.png');\n" +
|
||||
" fetch('/digits/2.png');\n" +
|
||||
" fetch('/digits/3.png');\n" +
|
||||
"}");
|
||||
}, url -> url.equals(server.PREFIX + "/digits/2.png"));
|
||||
assertEquals(server.PREFIX + "/digits/2.png", request.url());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRespectTimeout() {
|
||||
try {
|
||||
page.futureEvent(REQUEST, new Page.FutureEventOptions()
|
||||
.withPredicate(url -> false).withTimeout(1)).get();
|
||||
page.waitForRequest(() -> {}, url -> false, new Page.WaitForRequestOptions().withTimeout(1));
|
||||
fail("did not throw");
|
||||
} catch (PlaywrightException e) {
|
||||
assertTrue(e.getMessage().contains("Timeout"), e.getMessage());
|
||||
@@ -64,7 +65,7 @@ public class TestPageWaitForRequest extends TestBase {
|
||||
void shouldRespectDefaultTimeout() {
|
||||
page.setDefaultTimeout(1);
|
||||
try {
|
||||
page.futureEvent(REQUEST, url -> false).get();
|
||||
page.waitForRequest(() -> {}, url -> false);
|
||||
fail("did not throw");
|
||||
} catch (PlaywrightException e) {
|
||||
assertTrue(e.getMessage().contains("Timeout"), e.getMessage());
|
||||
@@ -74,24 +75,27 @@ public class TestPageWaitForRequest extends TestBase {
|
||||
@Test
|
||||
void shouldWorkWithNoTimeout() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Request> request = page.futureRequest(server.PREFIX + "/digits/2.png",
|
||||
new Page.FutureRequestOptions().withTimeout(0));
|
||||
page.evaluate("() => setTimeout(() => {\n" +
|
||||
" fetch('/digits/1.png');\n" +
|
||||
" fetch('/digits/2.png');\n" +
|
||||
" fetch('/digits/3.png');\n" +
|
||||
"}, 50)");
|
||||
assertEquals(server.PREFIX + "/digits/2.png", request.get().url());
|
||||
Request request = page.waitForRequest(() -> {
|
||||
page.evaluate("() => setTimeout(() => {\n" +
|
||||
" fetch('/digits/1.png');\n" +
|
||||
" fetch('/digits/2.png');\n" +
|
||||
" fetch('/digits/3.png');\n" +
|
||||
"}, 50)");
|
||||
},
|
||||
server.PREFIX + "/digits/2.png",
|
||||
new Page.WaitForRequestOptions().withTimeout(0));
|
||||
assertEquals(server.PREFIX + "/digits/2.png", request.url());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWorkWithUrlMatch() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Request> request = page.futureRequest(Pattern.compile(".*digits/\\d\\.png"));
|
||||
page.evaluate("() => {\n" +
|
||||
" fetch('/digits/1.png');\n" +
|
||||
"}");
|
||||
assertEquals(server.PREFIX + "/digits/1.png", request.get().url());
|
||||
Request request = page.waitForRequest(() -> {
|
||||
page.evaluate("() => {\n" +
|
||||
" fetch('/digits/1.png');\n" +
|
||||
"}");
|
||||
}, Pattern.compile(".*digits/\\d\\.png"));
|
||||
assertEquals(server.PREFIX + "/digits/1.png", request.url());
|
||||
}
|
||||
|
||||
void shouldWorkWithUrlMatchRegularExpressionFromADifferentContext() {
|
||||
|
||||
@@ -26,44 +26,47 @@ public class TestPageWaitForResponse extends TestBase {
|
||||
@Test
|
||||
void shouldWork() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Response> response = page.futureResponse(server.PREFIX + "/digits/2.png");
|
||||
page.evaluate("() => {\n" +
|
||||
" fetch('/digits/1.png');\n" +
|
||||
" fetch('/digits/2.png');\n" +
|
||||
" fetch('/digits/3.png');\n" +
|
||||
"}");
|
||||
assertEquals(server.PREFIX + "/digits/2.png", response.get().url());
|
||||
Response response = page.waitForResponse(() -> {
|
||||
page.evaluate("() => {\n" +
|
||||
" fetch('/digits/1.png');\n" +
|
||||
" fetch('/digits/2.png');\n" +
|
||||
" fetch('/digits/3.png');\n" +
|
||||
"}");
|
||||
}, server.PREFIX + "/digits/2.png");
|
||||
assertEquals(server.PREFIX + "/digits/2.png", response.url());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRespectTimeout() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Response> response = page.futureResponse(url -> url.equals(server.PREFIX + "/digits/2.png"));
|
||||
page.evaluate("() => {\n" +
|
||||
" fetch('/digits/1.png');\n" +
|
||||
" fetch('/digits/2.png');\n" +
|
||||
" fetch('/digits/3.png');\n" +
|
||||
"}");
|
||||
assertEquals(server.PREFIX + "/digits/2.png", response.get().url());
|
||||
Response response = page.waitForResponse(() -> {
|
||||
page.evaluate("() => {\n" +
|
||||
" fetch('/digits/1.png');\n" +
|
||||
" fetch('/digits/2.png');\n" +
|
||||
" fetch('/digits/3.png');\n" +
|
||||
"}");
|
||||
}, url -> url.equals(server.PREFIX + "/digits/2.png"));
|
||||
assertEquals(server.PREFIX + "/digits/2.png", response.url());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWorkWithPredicate() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Response> response = page.futureResponse(url -> url.equals(server.PREFIX + "/digits/2.png"));
|
||||
page.evaluate("() => {\n" +
|
||||
" fetch('/digits/1.png');\n" +
|
||||
" fetch('/digits/2.png');\n" +
|
||||
" fetch('/digits/3.png');\n" +
|
||||
"}");
|
||||
assertEquals(server.PREFIX + "/digits/2.png", response.get().url());
|
||||
Response response = page.waitForResponse(() -> {
|
||||
page.evaluate("() => {\n" +
|
||||
" fetch('/digits/1.png');\n" +
|
||||
" fetch('/digits/2.png');\n" +
|
||||
" fetch('/digits/3.png');\n" +
|
||||
"}");
|
||||
}, url -> url.equals(server.PREFIX + "/digits/2.png"));
|
||||
assertEquals(server.PREFIX + "/digits/2.png", response.url());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRespectDefaultTimeout() {
|
||||
page.setDefaultTimeout(1);
|
||||
try {
|
||||
page.futureEvent(RESPONSE, url -> false).get();
|
||||
page.waitForResponse(() -> {}, url -> false);
|
||||
fail("did not throw");
|
||||
} catch (PlaywrightException e) {
|
||||
assertTrue(e.getMessage().contains("Timeout"), e.getMessage());
|
||||
@@ -73,13 +76,16 @@ public class TestPageWaitForResponse extends TestBase {
|
||||
@Test
|
||||
void shouldWorkWithNoTimeout() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Response> response = page.futureResponse(server.PREFIX + "/digits/2.png",
|
||||
new Page.FutureResponseOptions().withTimeout(0));
|
||||
page.evaluate("() => setTimeout(() => {\n" +
|
||||
" fetch('/digits/1.png');\n" +
|
||||
" fetch('/digits/2.png');\n" +
|
||||
" fetch('/digits/3.png');\n" +
|
||||
"}, 50)");
|
||||
assertEquals(server.PREFIX + "/digits/2.png", response.get().url());
|
||||
Response response = page.waitForResponse(() -> {
|
||||
page.evaluate("() => setTimeout(() => {\n" +
|
||||
" fetch('/digits/1.png');\n" +
|
||||
" fetch('/digits/2.png');\n" +
|
||||
" fetch('/digits/3.png');\n" +
|
||||
"}, 50)");
|
||||
|
||||
},
|
||||
server.PREFIX + "/digits/2.png",
|
||||
new Page.WaitForResponseOptions().withTimeout(0));
|
||||
assertEquals(server.PREFIX + "/digits/2.png", response.url());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,9 +38,7 @@ public class TestPopup extends TestBase {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
page.setContent("<a target=_blank rel=noopener href='/popup/popup.html'>link</a>");
|
||||
Future<Server.Request> requestPromise = server.futureRequest("/popup/popup.html");
|
||||
Deferred<Event<BrowserContext.EventType>> popupEvent = context.futureEvent(BrowserContext.EventType.PAGE);
|
||||
page.click("a");
|
||||
Page popup = (Page) popupEvent.get().data();
|
||||
Page popup = context.waitForPage(() -> page.click("a"));
|
||||
popup.waitForLoadState(DOMCONTENTLOADED);
|
||||
String userAgent = (String) popup.evaluate("() => window['initialUserAgent']");
|
||||
Server.Request request = requestPromise.get();
|
||||
@@ -60,9 +58,7 @@ public class TestPopup extends TestBase {
|
||||
route.continue_();
|
||||
intercepted[0] = true;
|
||||
});
|
||||
Deferred<Event<BrowserContext.EventType>> popup = context.futureEvent(BrowserContext.EventType.PAGE);
|
||||
page.click("a");
|
||||
popup.get();
|
||||
context.waitForPage(() -> page.click("a"));
|
||||
|
||||
context.close();
|
||||
assertTrue(intercepted[0]);
|
||||
@@ -103,9 +99,8 @@ public class TestPopup extends TestBase {
|
||||
.withHttpCredentials("user", "pass"));
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Event<Page.EventType>> popupEvent = page.futureEvent(POPUP);
|
||||
page.evaluate("url => window['_popup'] = window.open(url)", server.PREFIX + "/title.html");
|
||||
Page popup = (Page) popupEvent.get().data();
|
||||
Page popup = page.waitForPopup(() -> page.evaluate(
|
||||
"url => window['_popup'] = window.open(url)", server.PREFIX + "/title.html"));
|
||||
popup.waitForLoadState(DOMCONTENTLOADED);
|
||||
assertEquals("Woof-Woof", popup.title());
|
||||
context.close();
|
||||
@@ -146,17 +141,18 @@ public class TestPopup extends TestBase {
|
||||
.withViewport(700, 700));
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Event<Page.EventType>> popupEvent = page.futureEvent(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 = (Page) popupEvent.get().data();
|
||||
Object[] size = {null};
|
||||
Page popup = page.waitForPopup(() -> {
|
||||
size[0] = 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" +
|
||||
"}");
|
||||
});
|
||||
popup.setViewportSize(500, 400);
|
||||
popup.waitForLoadState();
|
||||
Object resized = popup.evaluate("() => ({ width: window.innerWidth, height: window.innerHeight })");
|
||||
context.close();
|
||||
assertEquals(mapOf("width", 600, "height", 300), size);
|
||||
assertEquals(mapOf("width", 600, "height", 300), size[0]);
|
||||
assertEquals(mapOf("width", 500, "height", 400), resized);
|
||||
}
|
||||
|
||||
@@ -170,9 +166,9 @@ public class TestPopup extends TestBase {
|
||||
route.continue_();
|
||||
intercepted[0] = true;
|
||||
});
|
||||
Deferred<Event<Page.EventType>> popupEvent = page.futureEvent(POPUP);
|
||||
page.evaluate("url => window['__popup'] = window.open(url)", server.EMPTY_PAGE);
|
||||
popupEvent.get();
|
||||
page.waitForPopup(() -> {
|
||||
page.evaluate("url => window['__popup'] = window.open(url)", server.EMPTY_PAGE);
|
||||
});
|
||||
assertTrue(intercepted[0]);
|
||||
context.close();
|
||||
}
|
||||
@@ -197,9 +193,9 @@ public class TestPopup extends TestBase {
|
||||
context.addInitScript("() => window['injected'] = 123");
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Event<Page.EventType>> popupEvent = page.futureEvent(POPUP);
|
||||
page.evaluate("url => window.open(url)", server.CROSS_PROCESS_PREFIX + "/title.html");
|
||||
Page popup = (Page) popupEvent.get().data();
|
||||
Page popup = page.waitForPopup(() -> {
|
||||
page.evaluate("url => window.open(url)", server.CROSS_PROCESS_PREFIX + "/title.html");
|
||||
});
|
||||
assertEquals(123, popup.evaluate("injected"));
|
||||
|
||||
popup.reload();
|
||||
|
||||
@@ -66,9 +66,7 @@ public class TestRequestContinue extends TestBase {
|
||||
page.route("**/foo", route -> {
|
||||
route.continue_(new Route.ContinueOverrides().withUrl(server.PREFIX + "/global-var.html"));
|
||||
});
|
||||
Deferred<Event<Page.EventType>> responseEvent = page.futureEvent(RESPONSE);
|
||||
page.navigate(server.PREFIX + "/foo");
|
||||
Response response = (Response) responseEvent.get().data();
|
||||
Response response = page.navigate(server.PREFIX + "/foo");
|
||||
assertEquals(server.PREFIX + "/foo", response.url());
|
||||
assertEquals(123, page.evaluate("window['globalVar']"));
|
||||
assertEquals("GET", serverRequest.get().method);
|
||||
|
||||
@@ -201,33 +201,28 @@ public class TestWebSocket extends TestBase {
|
||||
|
||||
@Test
|
||||
void shouldNotHaveStrayErrorEvents() {
|
||||
Deferred<Event<Page.EventType>> wsEvent = page.futureEvent(WEBSOCKET);
|
||||
page.evaluate("port => {\n" +
|
||||
" window.ws = new WebSocket('ws://localhost:' + port + '/ws');\n" +
|
||||
"}", webSocketServer.getPort());
|
||||
|
||||
com.microsoft.playwright.WebSocket ws = (com.microsoft.playwright.WebSocket) wsEvent.get().data();
|
||||
com.microsoft.playwright.WebSocket ws = page.waitForWebSocket(() -> {
|
||||
page.evaluate("port => {\n" +
|
||||
" window.ws = new WebSocket('ws://localhost:' + port + '/ws');\n" +
|
||||
"}", webSocketServer.getPort());
|
||||
});
|
||||
boolean[] error = {false};
|
||||
ws.addListener(SOCKETERROR, e -> error[0] = true);
|
||||
Deferred<Event<com.microsoft.playwright.WebSocket.EventType>> frameReceivedEvent = ws.futureEvent(FRAMERECEIVED);
|
||||
frameReceivedEvent.get();
|
||||
ws.waitForFrameReceived(() -> {});
|
||||
page.evaluate("window.ws.close()");
|
||||
assertFalse(error[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectFutureEventOnSocketClose() {
|
||||
Deferred<Event<Page.EventType>> wsEvent = page.futureEvent(WEBSOCKET);
|
||||
page.evaluate("port => {\n" +
|
||||
" window.ws = new WebSocket('ws://localhost:' + port + '/ws');\n" +
|
||||
"}", webSocketServer.getPort());
|
||||
|
||||
com.microsoft.playwright.WebSocket ws = (com.microsoft.playwright.WebSocket) wsEvent.get().data();
|
||||
ws.futureEvent(FRAMERECEIVED).get();
|
||||
Deferred<Event<com.microsoft.playwright.WebSocket.EventType>> frameSentEvent = ws.futureEvent(FRAMESENT);
|
||||
page.evaluate("window.ws.close()");
|
||||
com.microsoft.playwright.WebSocket ws = page.waitForWebSocket(() -> {
|
||||
page.evaluate("port => {\n" +
|
||||
" window.ws = new WebSocket('ws://localhost:' + port + '/ws');\n" +
|
||||
"}", webSocketServer.getPort());
|
||||
});
|
||||
ws.waitForFrameReceived(() -> {});
|
||||
try {
|
||||
frameSentEvent.get();
|
||||
ws.waitForFrameSent(() -> page.evaluate("window.ws.close()"));
|
||||
fail("did not throw");
|
||||
} catch (PlaywrightException exception) {
|
||||
assertTrue(exception.getMessage().contains("Socket closed"));
|
||||
@@ -236,17 +231,14 @@ public class TestWebSocket extends TestBase {
|
||||
|
||||
@Test
|
||||
void shouldRejectFutureEventOnPageClose() {
|
||||
Deferred<Event<Page.EventType>> wsEvent = page.futureEvent(WEBSOCKET);
|
||||
page.evaluate("port => {\n" +
|
||||
" window.ws = new WebSocket('ws://localhost:' + port + '/ws');\n" +
|
||||
"}", webSocketServer.getPort());
|
||||
|
||||
com.microsoft.playwright.WebSocket ws = (com.microsoft.playwright.WebSocket) wsEvent.get().data();
|
||||
ws.futureEvent(FRAMERECEIVED).get();
|
||||
Deferred<Event<com.microsoft.playwright.WebSocket.EventType>> frameSentEvent = ws.futureEvent(FRAMESENT);
|
||||
page.close();
|
||||
com.microsoft.playwright.WebSocket ws = page.waitForWebSocket(() -> {
|
||||
page.evaluate("port => {\n" +
|
||||
" window.ws = new WebSocket('ws://localhost:' + port + '/ws');\n" +
|
||||
"}", webSocketServer.getPort());
|
||||
});
|
||||
ws.waitForFrameReceived(() -> {});
|
||||
try {
|
||||
frameSentEvent.get();
|
||||
ws.waitForFrameSent(() -> page.close());
|
||||
fail("did not throw");
|
||||
} catch (PlaywrightException exception) {
|
||||
assertTrue(exception.getMessage().contains("Page closed"));
|
||||
|
||||
@@ -22,17 +22,14 @@ import org.junit.jupiter.api.condition.EnabledIf;
|
||||
|
||||
import static com.microsoft.playwright.Page.EventType.*;
|
||||
import static com.microsoft.playwright.Utils.attachFrame;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestWorkers extends TestBase {
|
||||
|
||||
@Test
|
||||
void pageWorkers() {
|
||||
Deferred<Event<Page.EventType>> workerEvent = page.futureEvent(WORKER);
|
||||
page.navigate(server.PREFIX + "/worker/worker.html");
|
||||
workerEvent.get();
|
||||
Worker worker = page.workers().get(0);
|
||||
Worker worker = page.waitForWorker(() ->
|
||||
page.navigate(server.PREFIX + "/worker/worker.html"));
|
||||
assertTrue(worker.url().contains("worker.js"));
|
||||
assertEquals("worker function result", worker.evaluate("() => self['workerFunction']()"));
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
@@ -41,13 +38,15 @@ public class TestWorkers extends TestBase {
|
||||
|
||||
@Test
|
||||
void shouldEmitCreatedAndDestroyedEvents() {
|
||||
Deferred<Event<Page.EventType>> workerCreatedPromise = page.futureEvent(WORKER);
|
||||
JSHandle workerObj = page.evaluateHandle("() => new Worker(URL.createObjectURL(new Blob(['1'], {type: 'application/javascript'})))");
|
||||
Worker worker = (Worker) workerCreatedPromise.get().data();
|
||||
JSHandle[] workerObj = {null};
|
||||
Worker worker = page.waitForWorker(() -> {
|
||||
workerObj[0] = page.evaluateHandle(
|
||||
"() => new Worker(URL.createObjectURL(new Blob(['1'], {type: 'application/javascript'})))");
|
||||
});
|
||||
JSHandle workerThisObj = worker.evaluateHandle("() => this");
|
||||
Deferred<Event<Worker.EventType>> workerDestroyedPromise = worker.futureEvent(Worker.EventType.CLOSE);
|
||||
page.evaluate("workerObj => workerObj.terminate()", workerObj);
|
||||
assertEquals(worker, workerDestroyedPromise.get().data());
|
||||
Worker closedWorker = worker.waitForClose(() ->
|
||||
page.evaluate("workerObj => workerObj.terminate()", workerObj[0]));
|
||||
assertEquals(worker, closedWorker);
|
||||
try {
|
||||
workerThisObj.getProperty("self");
|
||||
} catch (PlaywrightException e) {
|
||||
@@ -57,16 +56,15 @@ public class TestWorkers extends TestBase {
|
||||
|
||||
@Test
|
||||
void shouldReportConsoleLogs() {
|
||||
Deferred<Event<Page.EventType>> consoleEvent = page.futureEvent(CONSOLE);
|
||||
page.evaluate("() => new Worker(URL.createObjectURL(new Blob(['console.log(1)'], {type: 'application/javascript'})))");
|
||||
assertEquals("1", ((ConsoleMessage) consoleEvent.get().data()).text());
|
||||
ConsoleMessage message = page.waitForConsole(() -> page.evaluate(
|
||||
"() => new Worker(URL.createObjectURL(new Blob(['console.log(1)'], {type: 'application/javascript'})))"));
|
||||
assertEquals("1", message.text());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHaveJSHandlesForConsoleLogs() {
|
||||
Deferred<Event<Page.EventType>> consoleEvent = page.futureEvent(CONSOLE);
|
||||
page.evaluate("() => new Worker(URL.createObjectURL(new Blob(['console.log(1,2,3,this)'], {type: 'application/javascript'})))");
|
||||
ConsoleMessage log = (ConsoleMessage) consoleEvent.get().data();
|
||||
ConsoleMessage log = page.waitForConsole(() -> page.evaluate(
|
||||
"() => new Worker(URL.createObjectURL(new Blob(['console.log(1,2,3,this)'], {type: 'application/javascript'})))"));
|
||||
assertEquals("1 2 3 JSHandle@object", log.text());
|
||||
assertEquals(4, log.args().size());
|
||||
assertEquals("null", (log.args().get(3).getProperty("origin")).jsonValue());
|
||||
@@ -74,23 +72,22 @@ public class TestWorkers extends TestBase {
|
||||
|
||||
@Test
|
||||
void shouldEvaluate() {
|
||||
Deferred<Event<Page.EventType>> workerCreatedPromise = page.futureEvent(WORKER);
|
||||
page.evaluate("() => new Worker(URL.createObjectURL(new Blob(['console.log(1)'], {type: 'application/javascript'})))");
|
||||
Worker worker = (Worker) workerCreatedPromise.get().data();
|
||||
Worker worker = page.waitForWorker(() -> page.evaluate(
|
||||
"() => new Worker(URL.createObjectURL(new Blob(['console.log(1)'], {type: 'application/javascript'})))"));
|
||||
assertEquals(2, worker.evaluate("1+1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReportErrors() {
|
||||
Deferred<Event<Page.EventType>> errorPromise = page.futureEvent(PAGEERROR);
|
||||
page.evaluate("() => new Worker(URL.createObjectURL(new Blob([`\n" +
|
||||
" setTimeout(() => {\n" +
|
||||
" // Do a console.log just to check that we do not confuse it with an error.\n" +
|
||||
" console.log('hey');\n" +
|
||||
" throw new Error('this is my error');\n" +
|
||||
" })\n" +
|
||||
"`], {type: 'application/javascript'})))");
|
||||
Page.Error errorLog = (Page.Error) errorPromise.get().data();
|
||||
Page.Error errorLog = page.waitForPageError(() -> {
|
||||
page.evaluate("() => new Worker(URL.createObjectURL(new Blob([`\n" +
|
||||
" setTimeout(() => {\n" +
|
||||
" // Do a console.log just to check that we do not confuse it with an error.\n" +
|
||||
" console.log('hey');\n" +
|
||||
" throw new Error('this is my error');\n" +
|
||||
" })\n" +
|
||||
"`], {type: 'application/javascript'})))");
|
||||
});
|
||||
assertTrue(errorLog.message().contains("this is my error"));
|
||||
}
|
||||
|
||||
@@ -98,23 +95,19 @@ public class TestWorkers extends TestBase {
|
||||
@DisabledIf(value="com.microsoft.playwright.TestBase#isFirefox", disabledReason="flaky upstream")
|
||||
void shouldClearUponNavigation() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Event<Page.EventType>> workerCreatedPromise = page.futureEvent(WORKER);
|
||||
page.evaluate("() => new Worker(URL.createObjectURL(new Blob(['console.log(1)'], {type: 'application/javascript'})))");
|
||||
Worker worker = (Worker) workerCreatedPromise.get().data();
|
||||
Worker worker = page.waitForWorker(() -> page.evaluate(
|
||||
"() => new Worker(URL.createObjectURL(new Blob(['console.log(1)'], {type: 'application/javascript'})))"));
|
||||
assertEquals(1, page.workers().size());
|
||||
boolean[] destroyed = {false};
|
||||
worker.addListener(Worker.EventType.CLOSE, event -> destroyed[0] = true);
|
||||
page.navigate(server.PREFIX + "/one-style.html");
|
||||
assertTrue(destroyed[0]);
|
||||
Worker destroyed = worker.waitForClose(() -> page.navigate(server.PREFIX + "/one-style.html"));
|
||||
assertEquals(worker, destroyed);
|
||||
assertEquals(0, page.workers().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldClearUponCrossProcessNavigation() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Event<Page.EventType>> workerCreatedPromise = page.futureEvent(WORKER);
|
||||
page.evaluate("() => new Worker(URL.createObjectURL(new Blob(['console.log(1)'], {type: 'application/javascript'})))");
|
||||
Worker worker = (Worker) workerCreatedPromise.get().data();
|
||||
Worker worker = page.waitForWorker(() -> page.evaluate(
|
||||
"() => new Worker(URL.createObjectURL(new Blob(['console.log(1)'], {type: 'application/javascript'})))"));
|
||||
assertEquals(1, page.workers().size());
|
||||
boolean[] destroyed = {false};
|
||||
worker.addListener(Worker.EventType.CLOSE, event -> destroyed[0] = true);
|
||||
@@ -127,31 +120,31 @@ public class TestWorkers extends TestBase {
|
||||
@EnabledIf(value="com.microsoft.playwright.TestBase#isWebKit", disabledReason="fixme")
|
||||
void shouldAttributeNetworkActivityForWorkerInsideIframeToTheIframe() {
|
||||
page.navigate(server.PREFIX + "/empty.html");
|
||||
Deferred<Event<Page.EventType>> workerEvent = page.futureEvent(WORKER);
|
||||
Frame frame = attachFrame(page, "frame1", server.PREFIX + "/worker/worker.html");
|
||||
Frame[] frame = {null};
|
||||
Worker worker = page.waitForWorker(() -> {
|
||||
frame[0] = attachFrame(page, "frame1", server.PREFIX + "/worker/worker.html");
|
||||
});
|
||||
assertNotNull(frame[0]);
|
||||
String url = server.PREFIX + "/one-style.css";
|
||||
Deferred<Request> request = page.futureRequest(url);
|
||||
Worker worker = (Worker) workerEvent.get().data();
|
||||
|
||||
worker.evaluate("url => fetch(url).then(response => response.text()).then(console.log)", url);
|
||||
|
||||
assertEquals(url, request.get().url());
|
||||
assertEquals(frame, request.get().frame());
|
||||
Request request = page.waitForRequest(() -> {
|
||||
worker.evaluate("url => fetch(url).then(response => response.text()).then(console.log)", url);
|
||||
}, url);
|
||||
assertEquals(url, request.url());
|
||||
assertEquals(frame[0], request.frame());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReportNetworkActivity() {
|
||||
Deferred<Event<Page.EventType>> workerEvent = page.futureEvent(WORKER);
|
||||
page.navigate(server.PREFIX + "/worker/worker.html");
|
||||
Worker worker = (Worker) workerEvent.get().data();
|
||||
Worker worker = page.waitForWorker(() -> page.navigate(server.PREFIX + "/worker/worker.html"));
|
||||
String url = server.PREFIX + "/one-style.css";
|
||||
Deferred<Request> requestPromise = page.futureRequest(url);
|
||||
Deferred<Response> responsePromise = page.futureResponse(url);
|
||||
worker.evaluate("url => fetch(url).then(response => response.text()).then(console.log)", url);
|
||||
Request request = requestPromise.get();
|
||||
Response response = responsePromise.get();
|
||||
assertEquals(url, request.url());
|
||||
assertEquals(request, response.request());
|
||||
Request[] request = {null};
|
||||
Response response = page.waitForResponse(() -> {
|
||||
request[0] = page.waitForRequest(() -> {
|
||||
worker.evaluate("url => fetch(url).then(response => response.text()).then(console.log)", url);
|
||||
}, url);
|
||||
assertEquals(url, request[0].url());
|
||||
}, url);
|
||||
assertEquals(request[0], response.request());
|
||||
assertTrue(response.ok());
|
||||
}
|
||||
|
||||
@@ -160,15 +153,16 @@ public class TestWorkers extends TestBase {
|
||||
// Chromium needs waitForDebugger enabled for this one.
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
String url = server.PREFIX + "/one-style.css";
|
||||
Deferred<Request> requestPromise = page.futureRequest(url);
|
||||
Deferred<Response> responsePromise = page.futureResponse(url);
|
||||
page.evaluate("url => new Worker(URL.createObjectURL(new Blob([`\n" +
|
||||
" fetch('${url}').then(response => response.text()).then(console.log);\n" +
|
||||
"`], {type: 'application/javascript'})))", url);
|
||||
Request request = requestPromise.get();
|
||||
Response response = responsePromise.get();
|
||||
assertEquals(url, request.url());
|
||||
assertEquals(request, response.request());
|
||||
Request[] request = {null};
|
||||
Response response = page.waitForResponse(() -> {
|
||||
request[0] = page.waitForRequest(() -> {
|
||||
page.evaluate("url => new Worker(URL.createObjectURL(new Blob([`\n" +
|
||||
" fetch('${url}').then(response => response.text()).then(console.log);\n" +
|
||||
"`], {type: 'application/javascript'})))", url);
|
||||
}, url);
|
||||
assertEquals(url, request[0].url());
|
||||
}, url);
|
||||
assertEquals(request[0], response.request());
|
||||
assertTrue(response.ok());
|
||||
}
|
||||
|
||||
@@ -177,9 +171,8 @@ public class TestWorkers extends TestBase {
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions().withLocale("ru-RU"));
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Event<Page.EventType>> workerEvent = page.futureEvent(WORKER);
|
||||
page.evaluate("() => new Worker(URL.createObjectURL(new Blob(['console.log(1)'], {type: 'application/javascript'})))");
|
||||
Worker worker = (Worker) workerEvent.get().data();
|
||||
Worker worker = page.waitForWorker(() -> page.evaluate(
|
||||
"() => new Worker(URL.createObjectURL(new Blob(['console.log(1)'], {type: 'application/javascript'})))"));
|
||||
assertEquals("10\u00A0000,2", worker.evaluate("() => (10000.20).toLocaleString()"));
|
||||
context.close();
|
||||
}
|
||||
|
||||
+143
-50
@@ -341,12 +341,108 @@ abstract class TypeDefinition extends Element {
|
||||
}
|
||||
|
||||
class Event extends Element {
|
||||
private static Map<String, String> eventNames = new HashMap<>();
|
||||
static {
|
||||
eventNames.put("Browser.disconnected", "Disconnected");
|
||||
|
||||
eventNames.put("BrowserContext.close", "Close");
|
||||
eventNames.put("BrowserContext.page", "Page");
|
||||
|
||||
eventNames.put("Page.close", "Close");
|
||||
eventNames.put("Page.console", "Console");
|
||||
eventNames.put("Page.crash", "Crash");
|
||||
eventNames.put("Page.dialog", "Dialog");
|
||||
eventNames.put("Page.domcontentloaded", "DomContentLoaded");
|
||||
eventNames.put("Page.download", "Download");
|
||||
eventNames.put("Page.filechooser", "FileChooser");
|
||||
eventNames.put("Page.frameattached", "FrameAttached");
|
||||
eventNames.put("Page.framedetached", "FrameDetached");
|
||||
eventNames.put("Page.framenavigated", "FrameNavigated");
|
||||
eventNames.put("Page.load", "Load");
|
||||
eventNames.put("Page.pageerror", "PageError");
|
||||
eventNames.put("Page.popup", "Popup");
|
||||
eventNames.put("Page.request", "Request");
|
||||
eventNames.put("Page.requestfailed", "RequestFailed");
|
||||
eventNames.put("Page.requestfinished", "RequestFinished");
|
||||
eventNames.put("Page.response", "Response");
|
||||
eventNames.put("Page.websocket", "WebSocket");
|
||||
eventNames.put("Page.worker", "Worker");
|
||||
|
||||
eventNames.put("WebSocket.close", "Close");
|
||||
eventNames.put("WebSocket.framereceived", "FrameReceived");
|
||||
eventNames.put("WebSocket.framesent", "FrameSent");
|
||||
eventNames.put("WebSocket.socketerror", "SocketError");
|
||||
|
||||
eventNames.put("Worker.close", "Close");
|
||||
}
|
||||
|
||||
private static Set<String> waitForEvents = new HashSet<>();
|
||||
static {
|
||||
waitForEvents.add("BrowserContext.page");
|
||||
|
||||
waitForEvents.add("Page.close");
|
||||
waitForEvents.add("Page.console");
|
||||
waitForEvents.add("Page.download");
|
||||
waitForEvents.add("Page.filechooser");
|
||||
waitForEvents.add("Page.frameattached");
|
||||
waitForEvents.add("Page.framedetached");
|
||||
waitForEvents.add("Page.framenavigated");
|
||||
waitForEvents.add("Page.pageerror");
|
||||
waitForEvents.add("Page.popup");
|
||||
waitForEvents.add("Page.request");
|
||||
waitForEvents.add("Page.requestfailed");
|
||||
waitForEvents.add("Page.requestfinished");
|
||||
waitForEvents.add("Page.response");
|
||||
waitForEvents.add("Page.websocket");
|
||||
waitForEvents.add("Page.worker");
|
||||
|
||||
waitForEvents.add("WebSocket.framereceived");
|
||||
waitForEvents.add("WebSocket.framesent");
|
||||
waitForEvents.add("WebSocket.socketerror");
|
||||
|
||||
waitForEvents.add("Worker.close");
|
||||
}
|
||||
|
||||
private final TypeRef type;
|
||||
|
||||
Event(Element parent, JsonObject jsonElement) {
|
||||
super(parent, jsonElement);
|
||||
type = new TypeRef(this, jsonElement.get("type"));
|
||||
}
|
||||
|
||||
void writeListenerMethods(List<String> output, String offset) {
|
||||
if (!eventNames.containsKey(jsonPath)) {
|
||||
throw new RuntimeException("Unknown event: " + jsonPath);
|
||||
}
|
||||
String name = eventNames.get(jsonPath);
|
||||
String listenerType = "void".equals(type.toJava()) ? "Runnable" : "Consumer<" + type.toJava() + ">";
|
||||
output.add(offset + "void on" + name + "(" + listenerType + " handler);");
|
||||
output.add(offset + "void off" + name + "(" + listenerType + " handler);");
|
||||
}
|
||||
|
||||
void writeWaitForEventIfNeeded(List<String> output, String offset) {
|
||||
if (!waitForEvents.contains(jsonPath)) {
|
||||
return;
|
||||
}
|
||||
String name = eventNames.get(jsonPath);
|
||||
String methodName = "waitFor" + name;
|
||||
// Skip events for which there is waitFor* method in the upstream API, that method will generate the code.
|
||||
if (Method.waitForMethods.contains(parent.jsonPath + "." + methodName)) {
|
||||
return;
|
||||
}
|
||||
output.add("");
|
||||
String optionsClass = toTitle(methodName) + "Options";
|
||||
output.add(offset + "class " + optionsClass + " {");
|
||||
output.add(offset + " public Double timeout;");
|
||||
output.add(offset + " public " + optionsClass + " withTimeout(double timeout) {");
|
||||
output.add(offset + " this.timeout = timeout;");
|
||||
output.add(offset + " return this;");
|
||||
output.add(offset + " }");
|
||||
output.add(offset + "}");
|
||||
String paramType = jsonPath.equals("Page.close") ? "Page" : type.toJava();
|
||||
output.add(offset + paramType + " " + methodName + "(Runnable code, " + optionsClass + " options);");
|
||||
output.add(offset + "default " + paramType + " " + methodName + "(Runnable code) { return " + methodName + "(code, null); }");
|
||||
}
|
||||
}
|
||||
|
||||
class Method extends Element {
|
||||
@@ -362,7 +458,14 @@ class Method extends Element {
|
||||
tsToJavaMethodName.put("$", "querySelector");
|
||||
tsToJavaMethodName.put("$$", "querySelectorAll");
|
||||
tsToJavaMethodName.put("goto", "navigate");
|
||||
tsToJavaMethodName.put("waitForNavigation", "futureNavigation");
|
||||
}
|
||||
|
||||
static Set<String> waitForMethods = new HashSet<>();
|
||||
static {
|
||||
waitForMethods.add("Page.waitForNavigation");
|
||||
waitForMethods.add("Page.waitForRequest");
|
||||
waitForMethods.add("Page.waitForResponse");
|
||||
waitForMethods.add("Frame.waitForNavigation");
|
||||
}
|
||||
|
||||
private static Map<String, String[]> customSignature = new HashMap<>();
|
||||
@@ -451,38 +554,37 @@ class Method extends Element {
|
||||
customSignature.put("Page.setInputFiles", setInputFilesWithSelector);
|
||||
customSignature.put("Frame.setInputFiles", setInputFilesWithSelector);
|
||||
|
||||
String[] waitForEvent = {
|
||||
"default Deferred<Event<EventType>> futureEvent(EventType event) {",
|
||||
" return futureEvent(event, (FutureEventOptions) null);",
|
||||
"}",
|
||||
"default Deferred<Event<EventType>> futureEvent(EventType event, Predicate<Event<EventType>> predicate) {",
|
||||
" FutureEventOptions options = new FutureEventOptions();",
|
||||
" options.predicate = predicate;",
|
||||
" return futureEvent(event, options);",
|
||||
"}",
|
||||
"Deferred<Event<EventType>> futureEvent(EventType event, FutureEventOptions options);",
|
||||
};
|
||||
customSignature.put("Page.waitForEvent", waitForEvent);
|
||||
customSignature.put("BrowserContext.waitForEvent", waitForEvent);
|
||||
customSignature.put("WebSocket.waitForEvent", waitForEvent);
|
||||
// We only have typed onPage/onDownload/... event listeners in Java.
|
||||
customSignature.put("Page.waitForEvent", new String[] {});
|
||||
customSignature.put("BrowserContext.waitForEvent", new String[] {});
|
||||
customSignature.put("WebSocket.waitForEvent", new String[] {});
|
||||
|
||||
customSignature.put("Page.waitForRequest", new String[] {
|
||||
"default Deferred<Request> futureRequest(String urlGlob) { return futureRequest(urlGlob, null); }",
|
||||
"default Deferred<Request> futureRequest(Pattern urlPattern) { return futureRequest(urlPattern, null); }",
|
||||
"default Deferred<Request> futureRequest(Predicate<String> urlPredicate) { return futureRequest(urlPredicate, null); }",
|
||||
"Deferred<Request> futureRequest(String urlGlob, FutureRequestOptions options);",
|
||||
"Deferred<Request> futureRequest(Pattern urlPattern, FutureRequestOptions options);",
|
||||
"Deferred<Request> futureRequest(Predicate<String> urlPredicate, FutureRequestOptions options);"
|
||||
"Request waitForRequest(Runnable code);",
|
||||
"default Request waitForRequest(Runnable code, String urlGlob) { return waitForRequest(code, urlGlob, null); }",
|
||||
"default Request waitForRequest(Runnable code, Pattern urlPattern) { return waitForRequest(code, urlPattern, null); }",
|
||||
"default Request waitForRequest(Runnable code, Predicate<String> urlPredicate) { return waitForRequest(code, urlPredicate, null); }",
|
||||
"Request waitForRequest(Runnable code, String urlGlob, WaitForRequestOptions options);",
|
||||
"Request waitForRequest(Runnable code, Pattern urlPattern, WaitForRequestOptions options);",
|
||||
"Request waitForRequest(Runnable code, Predicate<String> urlPredicate, WaitForRequestOptions options);"
|
||||
});
|
||||
customSignature.put("Page.waitForResponse", new String[] {
|
||||
"default Deferred<Response> futureResponse(String urlGlob) { return futureResponse(urlGlob, null); }",
|
||||
"default Deferred<Response> futureResponse(Pattern urlPattern) { return futureResponse(urlPattern, null); }",
|
||||
"default Deferred<Response> futureResponse(Predicate<String> urlPredicate) { return futureResponse(urlPredicate, null); }",
|
||||
"Deferred<Response> futureResponse(String urlGlob, FutureResponseOptions options);",
|
||||
"Deferred<Response> futureResponse(Pattern urlPattern, FutureResponseOptions options);",
|
||||
"Deferred<Response> futureResponse(Predicate<String> urlPredicate, FutureResponseOptions options);"
|
||||
"Response waitForResponse(Runnable code);",
|
||||
"default Response waitForResponse(Runnable code, String urlGlob) { return waitForResponse(code, urlGlob, null); }",
|
||||
"default Response waitForResponse(Runnable code, Pattern urlPattern) { return waitForResponse(code, urlPattern, null); }",
|
||||
"default Response waitForResponse(Runnable code, Predicate<String> urlPredicate) { return waitForResponse(code, urlPredicate, null); }",
|
||||
"Response waitForResponse(Runnable code, String urlGlob, WaitForResponseOptions options);",
|
||||
"Response waitForResponse(Runnable code, Pattern urlPattern, WaitForResponseOptions options);",
|
||||
"Response waitForResponse(Runnable code, Predicate<String> urlPredicate, WaitForResponseOptions options);"
|
||||
});
|
||||
|
||||
String[] waitForNavigation = {
|
||||
"default Response waitForNavigation(Runnable code) { return waitForNavigation(code, null); }",
|
||||
"Response waitForNavigation(Runnable code, WaitForNavigationOptions options);"
|
||||
};
|
||||
customSignature.put("Frame.waitForNavigation", waitForNavigation);
|
||||
customSignature.put("Page.waitForNavigation", waitForNavigation);
|
||||
|
||||
String[] selectOption = {
|
||||
"default List<String> selectOption(String selector, String value) {",
|
||||
" return selectOption(selector, value, null);",
|
||||
@@ -742,15 +844,15 @@ class Field extends Element {
|
||||
void writeBuilderMethod(List<String> output, String offset, String parentClass) {
|
||||
if (asList("Frame.waitForNavigation.options.url",
|
||||
"Page.waitForNavigation.options.url").contains(jsonPath)) {
|
||||
output.add(offset + "public FutureNavigationOptions withUrl(String glob) {");
|
||||
output.add(offset + "public WaitForNavigationOptions withUrl(String glob) {");
|
||||
output.add(offset + " this.glob = glob;");
|
||||
output.add(offset + " return this;");
|
||||
output.add(offset + "}");
|
||||
output.add(offset + "public FutureNavigationOptions withUrl(Pattern pattern) {");
|
||||
output.add(offset + "public WaitForNavigationOptions withUrl(Pattern pattern) {");
|
||||
output.add(offset + " this.pattern = pattern;");
|
||||
output.add(offset + " return this;");
|
||||
output.add(offset + "}");
|
||||
output.add(offset + "public FutureNavigationOptions withUrl(Predicate<String> predicate) {");
|
||||
output.add(offset + "public WaitForNavigationOptions withUrl(Predicate<String> predicate) {");
|
||||
output.add(offset + " this.predicate = predicate;");
|
||||
output.add(offset + " return this;");
|
||||
output.add(offset + "}");
|
||||
@@ -929,7 +1031,7 @@ class Interface extends TypeDefinition {
|
||||
output.add("import java.nio.file.Path;");
|
||||
}
|
||||
output.add("import java.util.*;");
|
||||
if (asList("Page", "BrowserContext").contains(jsonName)) {
|
||||
if (asList("Page", "BrowserContext", "WebSocket", "Worker").contains(jsonName)) {
|
||||
output.add("import java.util.function.Consumer;");
|
||||
}
|
||||
if (asList("Page", "Frame", "BrowserContext", "WebSocket").contains(jsonName)) {
|
||||
@@ -957,9 +1059,6 @@ class Interface extends TypeDefinition {
|
||||
for (Method m : methods) {
|
||||
m.writeTo(output, offset);
|
||||
}
|
||||
if ("Worker".equals(jsonName)) {
|
||||
output.add(offset + "Deferred<Event<EventType>> futureEvent(EventType event);");
|
||||
}
|
||||
if ("Playwright".equals(jsonName)) {
|
||||
output.add("");
|
||||
output.add(offset + "static Playwright create() {");
|
||||
@@ -985,6 +1084,16 @@ class Interface extends TypeDefinition {
|
||||
output.add("");
|
||||
output.add(offset + "void addListener(EventType type, Listener<EventType> listener);");
|
||||
output.add(offset + "void removeListener(EventType type, Listener<EventType> listener);");
|
||||
|
||||
for (Event e : events) {
|
||||
output.add("");
|
||||
e.writeListenerMethods(output, offset);
|
||||
}
|
||||
output.add("");
|
||||
for (Event e : events) {
|
||||
e.writeWaitForEventIfNeeded(output, offset);
|
||||
}
|
||||
output.add("");
|
||||
}
|
||||
|
||||
private void writeSharedTypes(List<String> output, String offset) {
|
||||
@@ -1184,22 +1293,6 @@ class Interface extends TypeDefinition {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (asList("Page", "BrowserContext", "WebSocket").contains(jsonName)){
|
||||
output.add(offset + "class FutureEventOptions {");
|
||||
output.add(offset + " public Double timeout;");
|
||||
output.add(offset + " public Predicate<Event<EventType>> predicate;");
|
||||
|
||||
output.add(offset + " public FutureEventOptions withTimeout(double millis) {");
|
||||
output.add(offset + " timeout = millis;");
|
||||
output.add(offset + " return this;");
|
||||
output.add(offset + " }");
|
||||
output.add(offset + " public FutureEventOptions withPredicate(Predicate<Event<EventType>> predicate) {");
|
||||
output.add(offset + " this.predicate = predicate;");
|
||||
output.add(offset + " return this;");
|
||||
output.add(offset + " }");
|
||||
output.add(offset + "}");
|
||||
output.add("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -261,9 +261,9 @@ class Types {
|
||||
add("BrowserContext.waitForEvent.optionsOrPredicate", "Function|Object", "String");
|
||||
add("BrowserContext.waitForEvent", "Promise<any>", "Deferred<Event<EventType>>", new Empty());
|
||||
add("Page.waitForNavigation.options.url", "RegExp|function(URL):boolean|string", "Custom");
|
||||
add("Page.waitForNavigation.options", "Object", "FutureNavigationOptions");
|
||||
add("Page.waitForRequest.options", "Object", "FutureRequestOptions");
|
||||
add("Page.waitForResponse.options", "Object", "FutureResponseOptions");
|
||||
add("Page.waitForNavigation.options", "Object", "WaitForNavigationOptions");
|
||||
add("Page.waitForRequest.options", "Object", "WaitForRequestOptions");
|
||||
add("Page.waitForResponse.options", "Object", "WaitForResponseOptions");
|
||||
add("Page.frame.options", "string|Object", "FrameOptions", new Empty());
|
||||
add("Page.route.url", "RegExp|function(URL):boolean|string", "String");
|
||||
add("Page.selectOption.values", "Array<ElementHandle>|Array<Object>|Array<string>|ElementHandle|Object|null|string", "String");
|
||||
@@ -275,7 +275,7 @@ class Types {
|
||||
add("Page.waitForRequest.urlOrPredicate", "RegExp|function(Request):boolean|string", "String");
|
||||
add("Page.waitForResponse.urlOrPredicate", "RegExp|function(Response):boolean|string", "String");
|
||||
add("Frame.waitForNavigation.options.url", "RegExp|function(URL):boolean|string", "Custom");
|
||||
add("Frame.waitForNavigation.options", "Object", "FutureNavigationOptions");
|
||||
add("Frame.waitForNavigation.options", "Object", "WaitForNavigationOptions");
|
||||
add("Frame.selectOption.values", "Array<ElementHandle>|Array<Object>|Array<string>|ElementHandle|Object|null|string", "String");
|
||||
add("Frame.setInputFiles.files", "Array<Object>|Array<path>|Object|path", "String");
|
||||
add("ElementHandle.selectOption.values", "Array<ElementHandle>|Array<Object>|Array<string>|ElementHandle|Object|null|string", "String");
|
||||
|
||||
Reference in New Issue
Block a user