diff --git a/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java b/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java
index 8820f8ba..d36d9c35 100644
--- a/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java
+++ b/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java
@@ -488,6 +488,17 @@ public interface BrowserContext extends AutoCloseable {
* browser.close();
* }
*
+ *
It is possible to examine the request to decide the route action. For example, mocking all requests that contain some
+ * post data, and leaving all other requests as is:
+ *
{@code
+ * context.route("/api/**", route -> {
+ * if (route.request().postData().contains("my-string"))
+ * route.fulfill(new Route.FulfillOptions().setBody("mocked-data"));
+ * else
+ * route.resume();
+ * });
+ * }
+ *
* Page routes (set up with {@link Page#route Page.route()}) take precedence over browser context routes when request
* matches both handlers.
*
@@ -521,6 +532,17 @@ public interface BrowserContext extends AutoCloseable {
* browser.close();
* }
*
+ *
It is possible to examine the request to decide the route action. For example, mocking all requests that contain some
+ * post data, and leaving all other requests as is:
+ *
{@code
+ * context.route("/api/**", route -> {
+ * if (route.request().postData().contains("my-string"))
+ * route.fulfill(new Route.FulfillOptions().setBody("mocked-data"));
+ * else
+ * route.resume();
+ * });
+ * }
+ *
* Page routes (set up with {@link Page#route Page.route()}) take precedence over browser context routes when request
* matches both handlers.
*
@@ -554,6 +576,17 @@ public interface BrowserContext extends AutoCloseable {
* browser.close();
* }
*
+ *
It is possible to examine the request to decide the route action. For example, mocking all requests that contain some
+ * post data, and leaving all other requests as is:
+ *
{@code
+ * context.route("/api/**", route -> {
+ * if (route.request().postData().contains("my-string"))
+ * route.fulfill(new Route.FulfillOptions().setBody("mocked-data"));
+ * else
+ * route.resume();
+ * });
+ * }
+ *
* Page routes (set up with {@link Page#route Page.route()}) take precedence over browser context routes when request
* matches both handlers.
*
diff --git a/playwright/src/main/java/com/microsoft/playwright/BrowserType.java b/playwright/src/main/java/com/microsoft/playwright/BrowserType.java
index 69927ee0..235b7ea3 100644
--- a/playwright/src/main/java/com/microsoft/playwright/BrowserType.java
+++ b/playwright/src/main/java/com/microsoft/playwright/BrowserType.java
@@ -42,6 +42,10 @@ import java.util.*;
*/
public interface BrowserType {
class ConnectOptions {
+ /**
+ * Additional HTTP headers to be sent with web socket connect request. Optional.
+ */
+ public Map headers;
/**
* Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going on.
* Defaults to 0.
@@ -53,6 +57,10 @@ public interface BrowserType {
*/
public Double timeout;
+ public ConnectOptions setHeaders(Map headers) {
+ this.headers = headers;
+ return this;
+ }
public ConnectOptions setSlowMo(double slowMo) {
this.slowMo = slowMo;
return this;
@@ -63,6 +71,10 @@ public interface BrowserType {
}
}
class ConnectOverCDPOptions {
+ /**
+ * Additional HTTP headers to be sent with connect request. Optional.
+ */
+ public Map headers;
/**
* Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going on.
* Defaults to 0.
@@ -74,6 +86,10 @@ public interface BrowserType {
*/
public Double timeout;
+ public ConnectOverCDPOptions setHeaders(Map headers) {
+ this.headers = headers;
+ return this;
+ }
public ConnectOverCDPOptions setSlowMo(double slowMo) {
this.slowMo = slowMo;
return this;
@@ -253,7 +269,8 @@ public interface BrowserType {
*/
public Boolean bypassCSP;
/**
- * Browser distribution channel.
+ * Browser distribution channel. Read more about using Google Chrome and Microsoft Edge.
*/
public BrowserChannel channel;
/**
diff --git a/playwright/src/main/java/com/microsoft/playwright/ElementHandle.java b/playwright/src/main/java/com/microsoft/playwright/ElementHandle.java
index f14a1689..160d922b 100644
--- a/playwright/src/main/java/com/microsoft/playwright/ElementHandle.java
+++ b/playwright/src/main/java/com/microsoft/playwright/ElementHandle.java
@@ -71,6 +71,12 @@ public interface ElementHandle extends JSHandle {
* Page.setDefaultTimeout()} methods.
*/
public Double timeout;
+ /**
+ * When set, this method only performs the actionability
+ * checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
+ * performing it.
+ */
+ public Boolean trial;
public CheckOptions setForce(boolean force) {
this.force = force;
@@ -91,6 +97,10 @@ public interface ElementHandle extends JSHandle {
this.timeout = timeout;
return this;
}
+ public CheckOptions setTrial(boolean trial) {
+ this.trial = trial;
+ return this;
+ }
}
class ClickOptions {
/**
@@ -132,6 +142,12 @@ public interface ElementHandle extends JSHandle {
* Page.setDefaultTimeout()} methods.
*/
public Double timeout;
+ /**
+ * When set, this method only performs the actionability
+ * checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
+ * performing it.
+ */
+ public Boolean trial;
public ClickOptions setButton(MouseButton button) {
this.button = button;
@@ -168,6 +184,10 @@ public interface ElementHandle extends JSHandle {
this.timeout = timeout;
return this;
}
+ public ClickOptions setTrial(boolean trial) {
+ this.trial = trial;
+ return this;
+ }
}
class DblclickOptions {
/**
@@ -205,6 +225,12 @@ public interface ElementHandle extends JSHandle {
* Page.setDefaultTimeout()} methods.
*/
public Double timeout;
+ /**
+ * When set, this method only performs the actionability
+ * checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
+ * performing it.
+ */
+ public Boolean trial;
public DblclickOptions setButton(MouseButton button) {
this.button = button;
@@ -237,6 +263,10 @@ public interface ElementHandle extends JSHandle {
this.timeout = timeout;
return this;
}
+ public DblclickOptions setTrial(boolean trial) {
+ this.trial = trial;
+ return this;
+ }
}
class FillOptions {
/**
@@ -283,6 +313,12 @@ public interface ElementHandle extends JSHandle {
* Page.setDefaultTimeout()} methods.
*/
public Double timeout;
+ /**
+ * When set, this method only performs the actionability
+ * checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
+ * performing it.
+ */
+ public Boolean trial;
public HoverOptions setForce(boolean force) {
this.force = force;
@@ -303,6 +339,10 @@ public interface ElementHandle extends JSHandle {
this.timeout = timeout;
return this;
}
+ public HoverOptions setTrial(boolean trial) {
+ this.trial = trial;
+ return this;
+ }
}
class PressOptions {
/**
@@ -483,6 +523,12 @@ public interface ElementHandle extends JSHandle {
* Page.setDefaultTimeout()} methods.
*/
public Double timeout;
+ /**
+ * When set, this method only performs the actionability
+ * checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
+ * performing it.
+ */
+ public Boolean trial;
public TapOptions setForce(boolean force) {
this.force = force;
@@ -507,6 +553,10 @@ public interface ElementHandle extends JSHandle {
this.timeout = timeout;
return this;
}
+ public TapOptions setTrial(boolean trial) {
+ this.trial = trial;
+ return this;
+ }
}
class TypeOptions {
/**
@@ -562,6 +612,12 @@ public interface ElementHandle extends JSHandle {
* Page.setDefaultTimeout()} methods.
*/
public Double timeout;
+ /**
+ * When set, this method only performs the actionability
+ * checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
+ * performing it.
+ */
+ public Boolean trial;
public UncheckOptions setForce(boolean force) {
this.force = force;
@@ -582,6 +638,10 @@ public interface ElementHandle extends JSHandle {
this.timeout = timeout;
return this;
}
+ public UncheckOptions setTrial(boolean trial) {
+ this.trial = trial;
+ return this;
+ }
}
class WaitForElementStateOptions {
/**
diff --git a/playwright/src/main/java/com/microsoft/playwright/Frame.java b/playwright/src/main/java/com/microsoft/playwright/Frame.java
index 1f6446cf..f292047e 100644
--- a/playwright/src/main/java/com/microsoft/playwright/Frame.java
+++ b/playwright/src/main/java/com/microsoft/playwright/Frame.java
@@ -148,6 +148,12 @@ public interface Frame {
* Page.setDefaultTimeout()} methods.
*/
public Double timeout;
+ /**
+ * When set, this method only performs the actionability
+ * checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
+ * performing it.
+ */
+ public Boolean trial;
public CheckOptions setForce(boolean force) {
this.force = force;
@@ -168,6 +174,10 @@ public interface Frame {
this.timeout = timeout;
return this;
}
+ public CheckOptions setTrial(boolean trial) {
+ this.trial = trial;
+ return this;
+ }
}
class ClickOptions {
/**
@@ -209,6 +219,12 @@ public interface Frame {
* Page.setDefaultTimeout()} methods.
*/
public Double timeout;
+ /**
+ * When set, this method only performs the actionability
+ * checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
+ * performing it.
+ */
+ public Boolean trial;
public ClickOptions setButton(MouseButton button) {
this.button = button;
@@ -245,6 +261,10 @@ public interface Frame {
this.timeout = timeout;
return this;
}
+ public ClickOptions setTrial(boolean trial) {
+ this.trial = trial;
+ return this;
+ }
}
class DblclickOptions {
/**
@@ -282,6 +302,12 @@ public interface Frame {
* Page.setDefaultTimeout()} methods.
*/
public Double timeout;
+ /**
+ * When set, this method only performs the actionability
+ * checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
+ * performing it.
+ */
+ public Boolean trial;
public DblclickOptions setButton(MouseButton button) {
this.button = button;
@@ -314,6 +340,10 @@ public interface Frame {
this.timeout = timeout;
return this;
}
+ public DblclickOptions setTrial(boolean trial) {
+ this.trial = trial;
+ return this;
+ }
}
class DispatchEventOptions {
/**
@@ -435,6 +465,12 @@ public interface Frame {
* Page.setDefaultTimeout()} methods.
*/
public Double timeout;
+ /**
+ * When set, this method only performs the actionability
+ * checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
+ * performing it.
+ */
+ public Boolean trial;
public HoverOptions setForce(boolean force) {
this.force = force;
@@ -455,6 +491,10 @@ public interface Frame {
this.timeout = timeout;
return this;
}
+ public HoverOptions setTrial(boolean trial) {
+ this.trial = trial;
+ return this;
+ }
}
class InnerHTMLOptions {
/**
@@ -692,6 +732,12 @@ public interface Frame {
* Page.setDefaultTimeout()} methods.
*/
public Double timeout;
+ /**
+ * When set, this method only performs the actionability
+ * checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
+ * performing it.
+ */
+ public Boolean trial;
public TapOptions setForce(boolean force) {
this.force = force;
@@ -716,6 +762,10 @@ public interface Frame {
this.timeout = timeout;
return this;
}
+ public TapOptions setTrial(boolean trial) {
+ this.trial = trial;
+ return this;
+ }
}
class TextContentOptions {
/**
@@ -784,6 +834,12 @@ public interface Frame {
* Page.setDefaultTimeout()} methods.
*/
public Double timeout;
+ /**
+ * When set, this method only performs the actionability
+ * checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
+ * performing it.
+ */
+ public Boolean trial;
public UncheckOptions setForce(boolean force) {
this.force = force;
@@ -804,6 +860,10 @@ public interface Frame {
this.timeout = timeout;
return this;
}
+ public UncheckOptions setTrial(boolean trial) {
+ this.trial = trial;
+ return this;
+ }
}
class WaitForFunctionOptions {
/**
diff --git a/playwright/src/main/java/com/microsoft/playwright/Page.java b/playwright/src/main/java/com/microsoft/playwright/Page.java
index 0bbddfaf..3c6ee7cc 100644
--- a/playwright/src/main/java/com/microsoft/playwright/Page.java
+++ b/playwright/src/main/java/com/microsoft/playwright/Page.java
@@ -393,6 +393,12 @@ public interface Page extends AutoCloseable {
* Page.setDefaultTimeout()} methods.
*/
public Double timeout;
+ /**
+ * When set, this method only performs the actionability
+ * checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
+ * performing it.
+ */
+ public Boolean trial;
public CheckOptions setForce(boolean force) {
this.force = force;
@@ -413,6 +419,10 @@ public interface Page extends AutoCloseable {
this.timeout = timeout;
return this;
}
+ public CheckOptions setTrial(boolean trial) {
+ this.trial = trial;
+ return this;
+ }
}
class ClickOptions {
/**
@@ -454,6 +464,12 @@ public interface Page extends AutoCloseable {
* Page.setDefaultTimeout()} methods.
*/
public Double timeout;
+ /**
+ * When set, this method only performs the actionability
+ * checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
+ * performing it.
+ */
+ public Boolean trial;
public ClickOptions setButton(MouseButton button) {
this.button = button;
@@ -490,6 +506,10 @@ public interface Page extends AutoCloseable {
this.timeout = timeout;
return this;
}
+ public ClickOptions setTrial(boolean trial) {
+ this.trial = trial;
+ return this;
+ }
}
class CloseOptions {
/**
@@ -539,6 +559,12 @@ public interface Page extends AutoCloseable {
* Page.setDefaultTimeout()} methods.
*/
public Double timeout;
+ /**
+ * When set, this method only performs the actionability
+ * checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
+ * performing it.
+ */
+ public Boolean trial;
public DblclickOptions setButton(MouseButton button) {
this.button = button;
@@ -571,6 +597,10 @@ public interface Page extends AutoCloseable {
this.timeout = timeout;
return this;
}
+ public DblclickOptions setTrial(boolean trial) {
+ this.trial = trial;
+ return this;
+ }
}
class DispatchEventOptions {
/**
@@ -779,6 +809,12 @@ public interface Page extends AutoCloseable {
* Page.setDefaultTimeout()} methods.
*/
public Double timeout;
+ /**
+ * When set, this method only performs the actionability
+ * checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
+ * performing it.
+ */
+ public Boolean trial;
public HoverOptions setForce(boolean force) {
this.force = force;
@@ -799,6 +835,10 @@ public interface Page extends AutoCloseable {
this.timeout = timeout;
return this;
}
+ public HoverOptions setTrial(boolean trial) {
+ this.trial = trial;
+ return this;
+ }
}
class InnerHTMLOptions {
/**
@@ -1248,6 +1288,12 @@ public interface Page extends AutoCloseable {
* Page.setDefaultTimeout()} methods.
*/
public Double timeout;
+ /**
+ * When set, this method only performs the actionability
+ * checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
+ * performing it.
+ */
+ public Boolean trial;
public TapOptions setForce(boolean force) {
this.force = force;
@@ -1272,6 +1318,10 @@ public interface Page extends AutoCloseable {
this.timeout = timeout;
return this;
}
+ public TapOptions setTrial(boolean trial) {
+ this.trial = trial;
+ return this;
+ }
}
class TextContentOptions {
/**
@@ -1340,6 +1390,12 @@ public interface Page extends AutoCloseable {
* Page.setDefaultTimeout()} methods.
*/
public Double timeout;
+ /**
+ * When set, this method only performs the actionability
+ * checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
+ * performing it.
+ */
+ public Boolean trial;
public UncheckOptions setForce(boolean force) {
this.force = force;
@@ -1360,6 +1416,10 @@ public interface Page extends AutoCloseable {
this.timeout = timeout;
return this;
}
+ public UncheckOptions setTrial(boolean trial) {
+ this.trial = trial;
+ return this;
+ }
}
class WaitForCloseOptions {
/**
@@ -3127,6 +3187,17 @@ public interface Page extends AutoCloseable {
* browser.close();
* }
*
+ * It is possible to examine the request to decide the route action. For example, mocking all requests that contain some
+ * post data, and leaving all other requests as is:
+ *
{@code
+ * page.route("/api/**", route -> {
+ * if (route.request().postData().contains("my-string"))
+ * route.fulfill(new Route.FulfillOptions().setBody("mocked-data"));
+ * else
+ * route.resume();
+ * });
+ * }
+ *
* Page routes take precedence over browser context routes (set up with {@link BrowserContext#route
* BrowserContext.route()}) when request matches both handlers.
*
@@ -3161,6 +3232,17 @@ public interface Page extends AutoCloseable {
* browser.close();
* }
*
+ *
It is possible to examine the request to decide the route action. For example, mocking all requests that contain some
+ * post data, and leaving all other requests as is:
+ *
{@code
+ * page.route("/api/**", route -> {
+ * if (route.request().postData().contains("my-string"))
+ * route.fulfill(new Route.FulfillOptions().setBody("mocked-data"));
+ * else
+ * route.resume();
+ * });
+ * }
+ *
* Page routes take precedence over browser context routes (set up with {@link BrowserContext#route
* BrowserContext.route()}) when request matches both handlers.
*
@@ -3195,6 +3277,17 @@ public interface Page extends AutoCloseable {
* browser.close();
* }
*
+ *
It is possible to examine the request to decide the route action. For example, mocking all requests that contain some
+ * post data, and leaving all other requests as is:
+ *
{@code
+ * page.route("/api/**", route -> {
+ * if (route.request().postData().contains("my-string"))
+ * route.fulfill(new Route.FulfillOptions().setBody("mocked-data"));
+ * else
+ * route.resume();
+ * });
+ * }
+ *
* Page routes take precedence over browser context routes (set up with {@link BrowserContext#route
* BrowserContext.route()}) when request matches both handlers.
*
@@ -4224,12 +4317,20 @@ public interface Page extends AutoCloseable {
*/
Page waitForPopup(WaitForPopupOptions options, Runnable callback);
/**
- * Waits for the matching request and returns it.
+ * Waits for the matching request and returns it. See waiting for event for more details about events.
*
{@code
- * Request firstRequest = page.waitForRequest("http://example.com/resource");
- * Object finalRequest = page.waitForRequest(
- * request -> "http://example.com".equals(request.url()) && "GET".equals(request.method()), () -> {});
- * return firstRequest.url();
+ * // Waits for the next response with the specified url
+ * Request request = page.waitForRequest("https://example.com/resource", () -> {
+ * // Triggers the request
+ * page.click("button.triggers-request");
+ * });
+ *
+ * // Waits for the next request matching some conditions
+ * Request request = page.waitForRequest(request -> "https://example.com".equals(request.url()) && "GET".equals(request.method()), () -> {
+ * // Triggers the request
+ * page.click("button.triggers-request");
+ * });
* }
*
* @param urlOrPredicate Request URL string, regex or predicate receiving {@code Request} object.
@@ -4239,12 +4340,20 @@ public interface Page extends AutoCloseable {
return waitForRequest(urlOrPredicate, null, callback);
}
/**
- * Waits for the matching request and returns it.
+ * Waits for the matching request and returns it. See waiting for event for more details about events.
* {@code
- * Request firstRequest = page.waitForRequest("http://example.com/resource");
- * Object finalRequest = page.waitForRequest(
- * request -> "http://example.com".equals(request.url()) && "GET".equals(request.method()), () -> {});
- * return firstRequest.url();
+ * // Waits for the next response with the specified url
+ * Request request = page.waitForRequest("https://example.com/resource", () -> {
+ * // Triggers the request
+ * page.click("button.triggers-request");
+ * });
+ *
+ * // Waits for the next request matching some conditions
+ * Request request = page.waitForRequest(request -> "https://example.com".equals(request.url()) && "GET".equals(request.method()), () -> {
+ * // Triggers the request
+ * page.click("button.triggers-request");
+ * });
* }
*
* @param urlOrPredicate Request URL string, regex or predicate receiving {@code Request} object.
@@ -4252,12 +4361,20 @@ public interface Page extends AutoCloseable {
*/
Request waitForRequest(String urlOrPredicate, WaitForRequestOptions options, Runnable callback);
/**
- * Waits for the matching request and returns it.
+ * Waits for the matching request and returns it. See waiting for event for more details about events.
* {@code
- * Request firstRequest = page.waitForRequest("http://example.com/resource");
- * Object finalRequest = page.waitForRequest(
- * request -> "http://example.com".equals(request.url()) && "GET".equals(request.method()), () -> {});
- * return firstRequest.url();
+ * // Waits for the next response with the specified url
+ * Request request = page.waitForRequest("https://example.com/resource", () -> {
+ * // Triggers the request
+ * page.click("button.triggers-request");
+ * });
+ *
+ * // Waits for the next request matching some conditions
+ * Request request = page.waitForRequest(request -> "https://example.com".equals(request.url()) && "GET".equals(request.method()), () -> {
+ * // Triggers the request
+ * page.click("button.triggers-request");
+ * });
* }
*
* @param urlOrPredicate Request URL string, regex or predicate receiving {@code Request} object.
@@ -4267,12 +4384,20 @@ public interface Page extends AutoCloseable {
return waitForRequest(urlOrPredicate, null, callback);
}
/**
- * Waits for the matching request and returns it.
+ * Waits for the matching request and returns it. See waiting for event for more details about events.
* {@code
- * Request firstRequest = page.waitForRequest("http://example.com/resource");
- * Object finalRequest = page.waitForRequest(
- * request -> "http://example.com".equals(request.url()) && "GET".equals(request.method()), () -> {});
- * return firstRequest.url();
+ * // Waits for the next response with the specified url
+ * Request request = page.waitForRequest("https://example.com/resource", () -> {
+ * // Triggers the request
+ * page.click("button.triggers-request");
+ * });
+ *
+ * // Waits for the next request matching some conditions
+ * Request request = page.waitForRequest(request -> "https://example.com".equals(request.url()) && "GET".equals(request.method()), () -> {
+ * // Triggers the request
+ * page.click("button.triggers-request");
+ * });
* }
*
* @param urlOrPredicate Request URL string, regex or predicate receiving {@code Request} object.
@@ -4280,12 +4405,20 @@ public interface Page extends AutoCloseable {
*/
Request waitForRequest(Pattern urlOrPredicate, WaitForRequestOptions options, Runnable callback);
/**
- * Waits for the matching request and returns it.
+ * Waits for the matching request and returns it. See waiting for event for more details about events.
* {@code
- * Request firstRequest = page.waitForRequest("http://example.com/resource");
- * Object finalRequest = page.waitForRequest(
- * request -> "http://example.com".equals(request.url()) && "GET".equals(request.method()), () -> {});
- * return firstRequest.url();
+ * // Waits for the next response with the specified url
+ * Request request = page.waitForRequest("https://example.com/resource", () -> {
+ * // Triggers the request
+ * page.click("button.triggers-request");
+ * });
+ *
+ * // Waits for the next request matching some conditions
+ * Request request = page.waitForRequest(request -> "https://example.com".equals(request.url()) && "GET".equals(request.method()), () -> {
+ * // Triggers the request
+ * page.click("button.triggers-request");
+ * });
* }
*
* @param urlOrPredicate Request URL string, regex or predicate receiving {@code Request} object.
@@ -4295,12 +4428,20 @@ public interface Page extends AutoCloseable {
return waitForRequest(urlOrPredicate, null, callback);
}
/**
- * Waits for the matching request and returns it.
+ * Waits for the matching request and returns it. See waiting for event for more details about events.
* {@code
- * Request firstRequest = page.waitForRequest("http://example.com/resource");
- * Object finalRequest = page.waitForRequest(
- * request -> "http://example.com".equals(request.url()) && "GET".equals(request.method()), () -> {});
- * return firstRequest.url();
+ * // Waits for the next response with the specified url
+ * Request request = page.waitForRequest("https://example.com/resource", () -> {
+ * // Triggers the request
+ * page.click("button.triggers-request");
+ * });
+ *
+ * // Waits for the next request matching some conditions
+ * Request request = page.waitForRequest(request -> "https://example.com".equals(request.url()) && "GET".equals(request.method()), () -> {
+ * // Triggers the request
+ * page.click("button.triggers-request");
+ * });
* }
*
* @param urlOrPredicate Request URL string, regex or predicate receiving {@code Request} object.
@@ -4308,11 +4449,20 @@ public interface Page extends AutoCloseable {
*/
Request waitForRequest(Predicate urlOrPredicate, WaitForRequestOptions options, Runnable callback);
/**
- * Returns the matched response.
+ * Returns the matched response. See waiting for
+ * event for more details about events.
* {@code
- * Response firstResponse = page.waitForResponse("https://example.com/resource", () -> {});
- * Response finalResponse = page.waitForResponse(response -> "https://example.com".equals(response.url()) && response.status() == 200, () -> {});
- * return finalResponse.ok();
+ * // Waits for the next response with the specified url
+ * Response response = page.waitForResponse("https://example.com/resource", () -> {
+ * // Triggers the response
+ * page.click("button.triggers-response");
+ * });
+ *
+ * // Waits for the next response matching some conditions
+ * Response response = page.waitForResponse(response -> "https://example.com".equals(response.url()) && response.status() == 200, () -> {
+ * // Triggers the response
+ * page.click("button.triggers-response");
+ * });
* }
*
* @param urlOrPredicate Request URL string, regex or predicate receiving {@code Response} object.
@@ -4322,11 +4472,20 @@ public interface Page extends AutoCloseable {
return waitForResponse(urlOrPredicate, null, callback);
}
/**
- * Returns the matched response.
+ * Returns the matched response. See waiting for
+ * event for more details about events.
* {@code
- * Response firstResponse = page.waitForResponse("https://example.com/resource", () -> {});
- * Response finalResponse = page.waitForResponse(response -> "https://example.com".equals(response.url()) && response.status() == 200, () -> {});
- * return finalResponse.ok();
+ * // Waits for the next response with the specified url
+ * Response response = page.waitForResponse("https://example.com/resource", () -> {
+ * // Triggers the response
+ * page.click("button.triggers-response");
+ * });
+ *
+ * // Waits for the next response matching some conditions
+ * Response response = page.waitForResponse(response -> "https://example.com".equals(response.url()) && response.status() == 200, () -> {
+ * // Triggers the response
+ * page.click("button.triggers-response");
+ * });
* }
*
* @param urlOrPredicate Request URL string, regex or predicate receiving {@code Response} object.
@@ -4334,11 +4493,20 @@ public interface Page extends AutoCloseable {
*/
Response waitForResponse(String urlOrPredicate, WaitForResponseOptions options, Runnable callback);
/**
- * Returns the matched response.
+ * Returns the matched response. See waiting for
+ * event for more details about events.
* {@code
- * Response firstResponse = page.waitForResponse("https://example.com/resource", () -> {});
- * Response finalResponse = page.waitForResponse(response -> "https://example.com".equals(response.url()) && response.status() == 200, () -> {});
- * return finalResponse.ok();
+ * // Waits for the next response with the specified url
+ * Response response = page.waitForResponse("https://example.com/resource", () -> {
+ * // Triggers the response
+ * page.click("button.triggers-response");
+ * });
+ *
+ * // Waits for the next response matching some conditions
+ * Response response = page.waitForResponse(response -> "https://example.com".equals(response.url()) && response.status() == 200, () -> {
+ * // Triggers the response
+ * page.click("button.triggers-response");
+ * });
* }
*
* @param urlOrPredicate Request URL string, regex or predicate receiving {@code Response} object.
@@ -4348,11 +4516,20 @@ public interface Page extends AutoCloseable {
return waitForResponse(urlOrPredicate, null, callback);
}
/**
- * Returns the matched response.
+ * Returns the matched response. See waiting for
+ * event for more details about events.
* {@code
- * Response firstResponse = page.waitForResponse("https://example.com/resource", () -> {});
- * Response finalResponse = page.waitForResponse(response -> "https://example.com".equals(response.url()) && response.status() == 200, () -> {});
- * return finalResponse.ok();
+ * // Waits for the next response with the specified url
+ * Response response = page.waitForResponse("https://example.com/resource", () -> {
+ * // Triggers the response
+ * page.click("button.triggers-response");
+ * });
+ *
+ * // Waits for the next response matching some conditions
+ * Response response = page.waitForResponse(response -> "https://example.com".equals(response.url()) && response.status() == 200, () -> {
+ * // Triggers the response
+ * page.click("button.triggers-response");
+ * });
* }
*
* @param urlOrPredicate Request URL string, regex or predicate receiving {@code Response} object.
@@ -4360,11 +4537,20 @@ public interface Page extends AutoCloseable {
*/
Response waitForResponse(Pattern urlOrPredicate, WaitForResponseOptions options, Runnable callback);
/**
- * Returns the matched response.
+ * Returns the matched response. See waiting for
+ * event for more details about events.
* {@code
- * Response firstResponse = page.waitForResponse("https://example.com/resource", () -> {});
- * Response finalResponse = page.waitForResponse(response -> "https://example.com".equals(response.url()) && response.status() == 200, () -> {});
- * return finalResponse.ok();
+ * // Waits for the next response with the specified url
+ * Response response = page.waitForResponse("https://example.com/resource", () -> {
+ * // Triggers the response
+ * page.click("button.triggers-response");
+ * });
+ *
+ * // Waits for the next response matching some conditions
+ * Response response = page.waitForResponse(response -> "https://example.com".equals(response.url()) && response.status() == 200, () -> {
+ * // Triggers the response
+ * page.click("button.triggers-response");
+ * });
* }
*
* @param urlOrPredicate Request URL string, regex or predicate receiving {@code Response} object.
@@ -4374,11 +4560,20 @@ public interface Page extends AutoCloseable {
return waitForResponse(urlOrPredicate, null, callback);
}
/**
- * Returns the matched response.
+ * Returns the matched response. See waiting for
+ * event for more details about events.
* {@code
- * Response firstResponse = page.waitForResponse("https://example.com/resource", () -> {});
- * Response finalResponse = page.waitForResponse(response -> "https://example.com".equals(response.url()) && response.status() == 200, () -> {});
- * return finalResponse.ok();
+ * // Waits for the next response with the specified url
+ * Response response = page.waitForResponse("https://example.com/resource", () -> {
+ * // Triggers the response
+ * page.click("button.triggers-response");
+ * });
+ *
+ * // Waits for the next response matching some conditions
+ * Response response = page.waitForResponse(response -> "https://example.com".equals(response.url()) && response.status() == 200, () -> {
+ * // Triggers the response
+ * page.click("button.triggers-response");
+ * });
* }
*
* @param urlOrPredicate Request URL string, regex or predicate receiving {@code Response} object.
diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/BrowserTypeImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/BrowserTypeImpl.java
index 5da9be86..e84d3f37 100644
--- a/playwright/src/main/java/com/microsoft/playwright/impl/BrowserTypeImpl.java
+++ b/playwright/src/main/java/com/microsoft/playwright/impl/BrowserTypeImpl.java
@@ -27,6 +27,8 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.time.Duration;
+import java.util.Collections;
+import java.util.Map;
import java.util.function.Consumer;
import static com.microsoft.playwright.impl.Serialization.gson;
@@ -58,10 +60,16 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
private Browser connectImpl(String wsEndpoint, ConnectOptions options) {
try {
Duration timeout = Duration.ofDays(1);
- if (options != null && options.timeout != null) {
- timeout = Duration.ofMillis(Math.round(options.timeout));
+ Map headers = Collections.emptyMap();
+ if (options != null) {
+ if (options.timeout != null) {
+ timeout = Duration.ofMillis(Math.round(options.timeout));
+ }
+ if (options.headers != null) {
+ headers = options.headers;
+ }
}
- WebSocketTransport transport = new WebSocketTransport(new URI(wsEndpoint), timeout);
+ WebSocketTransport transport = new WebSocketTransport(new URI(wsEndpoint), headers, timeout);
Connection connection = new Connection(transport);
PlaywrightImpl playwright = (PlaywrightImpl) connection.waitForObjectWithKnownName("Playwright");
if (!playwright.initializer.has("preLaunchedBrowser")) {
diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/WebSocketTransport.java b/playwright/src/main/java/com/microsoft/playwright/impl/WebSocketTransport.java
index 89fc36d1..267543d9 100644
--- a/playwright/src/main/java/com/microsoft/playwright/impl/WebSocketTransport.java
+++ b/playwright/src/main/java/com/microsoft/playwright/impl/WebSocketTransport.java
@@ -23,6 +23,7 @@ import org.java_websocket.handshake.ServerHandshake;
import java.io.IOException;
import java.net.URI;
import java.time.Duration;
+import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -62,8 +63,11 @@ class WebSocketTransport implements Transport {
}
}
- WebSocketTransport(URI uri, Duration timeout) {
+ WebSocketTransport(URI uri, Map headers, Duration timeout) {
clientConnection = new ClientConnection(uri);
+ for (Map.Entry entry : headers.entrySet()) {
+ clientConnection.addHeader(entry.getKey(), entry.getValue());
+ }
try {
if (!clientConnection.connectBlocking(timeout.toMillis(), TimeUnit.MILLISECONDS)) {
throw new PlaywrightException("Failed to connect", lastError);
diff --git a/playwright/src/test/java/com/microsoft/playwright/TestBrowserTypeConnect.java b/playwright/src/test/java/com/microsoft/playwright/TestBrowserTypeConnect.java
index 290f439a..a6db747c 100644
--- a/playwright/src/test/java/com/microsoft/playwright/TestBrowserTypeConnect.java
+++ b/playwright/src/test/java/com/microsoft/playwright/TestBrowserTypeConnect.java
@@ -18,14 +18,17 @@ package com.microsoft.playwright;
import com.microsoft.playwright.impl.Driver;
import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
+import java.net.InetSocketAddress;
import java.nio.file.Path;
+import static com.microsoft.playwright.Utils.mapOf;
import static org.junit.jupiter.api.Assertions.*;
public class TestBrowserTypeConnect extends TestBase {
@@ -133,6 +136,20 @@ public class TestBrowserTypeConnect extends TestBase {
browser2.close();
}
+ @Test
+ void shouldSendExtraHeadersWithConnectRequest() throws Exception {
+ try (WebSocketServerImpl webSocketServer = WebSocketServerImpl.create()) {
+ try {
+ browserType.connect("ws://localhost:" + webSocketServer.getPort() + "/ws",
+ new BrowserType.ConnectOptions().setHeaders(mapOf("User-Agent", "Playwright", "foo", "bar")));
+ } catch (Exception e) {
+ }
+ assertNotNull(webSocketServer.lastClientHandshake);
+ assertEquals("Playwright", webSocketServer.lastClientHandshake.getFieldValue("User-Agent"));
+ assertEquals("bar", webSocketServer.lastClientHandshake.getFieldValue("foo"));
+ }
+ }
+
@Test
void disconnectedEventShouldBeEmittedWhenBrowserIsClosedOrServerIsClosed() throws InterruptedException {
// Launch another server to not affect other tests.
diff --git a/playwright/src/test/java/com/microsoft/playwright/TestChromium.java b/playwright/src/test/java/com/microsoft/playwright/TestChromium.java
index 5136ba60..9afdb343 100644
--- a/playwright/src/test/java/com/microsoft/playwright/TestChromium.java
+++ b/playwright/src/test/java/com/microsoft/playwright/TestChromium.java
@@ -29,8 +29,10 @@ import java.net.URL;
import java.net.URLConnection;
import java.util.List;
+import static com.microsoft.playwright.Utils.mapOf;
import static java.util.Arrays.asList;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
@EnabledIf(value="com.microsoft.playwright.TestBase#isChromium", disabledReason="Chromium-specific API")
public class TestChromium extends TestBase {
@@ -104,4 +106,18 @@ public class TestChromium extends TestBase {
cdpBrowser2.close();
}
}
+
+ @Test
+ void shouldSendExtraHeadersWithConnectRequest() throws Exception {
+ try (WebSocketServerImpl webSocketServer = WebSocketServerImpl.create()) {
+ try {
+ browserType.connectOverCDP("ws://localhost:" + webSocketServer.getPort() + "/ws",
+ new BrowserType.ConnectOverCDPOptions().setHeaders(mapOf("User-Agent", "Playwright", "foo", "bar")));
+ } catch (Exception e) {
+ }
+ assertNotNull(webSocketServer.lastClientHandshake);
+ assertEquals("Playwright", webSocketServer.lastClientHandshake.getFieldValue("User-Agent"));
+ assertEquals("bar", webSocketServer.lastClientHandshake.getFieldValue("foo"));
+ }
+ }
}
diff --git a/playwright/src/test/java/com/microsoft/playwright/TestDownload.java b/playwright/src/test/java/com/microsoft/playwright/TestDownload.java
index 0d79232f..510e21d4 100644
--- a/playwright/src/test/java/com/microsoft/playwright/TestDownload.java
+++ b/playwright/src/test/java/com/microsoft/playwright/TestDownload.java
@@ -213,7 +213,7 @@ public class TestDownload extends TestBase {
download.saveAs(userPath);
fail("did not throw");
} catch (PlaywrightException e) {
- assertTrue(e.getMessage().contains("File already deleted. Save before deleting."), e.getMessage());
+ assertTrue(e.getMessage().contains("Target page, context or browser has been closed"), e.getMessage());
}
page.close();
}
diff --git a/playwright/src/test/java/com/microsoft/playwright/TestWebSocket.java b/playwright/src/test/java/com/microsoft/playwright/TestWebSocket.java
index 3618358d..99d0590c 100644
--- a/playwright/src/test/java/com/microsoft/playwright/TestWebSocket.java
+++ b/playwright/src/test/java/com/microsoft/playwright/TestWebSocket.java
@@ -16,9 +16,6 @@
package com.microsoft.playwright;
-import org.java_websocket.WebSocket;
-import org.java_websocket.handshake.ClientHandshake;
-import org.java_websocket.server.WebSocketServer;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@@ -35,35 +32,10 @@ import static org.junit.jupiter.api.Assertions.*;
public class TestWebSocket extends TestBase {
private static WebSocketServerImpl webSocketServer;
- private static int WS_SERVER_PORT = 8910;
-
- private static class WebSocketServerImpl extends WebSocketServer {
- WebSocketServerImpl(InetSocketAddress address) {
- super(address, 1);
- }
-
- @Override
- public void onOpen(org.java_websocket.WebSocket webSocket, ClientHandshake clientHandshake) {
- webSocket.send("incoming");
- }
-
- @Override
- public void onClose(org.java_websocket.WebSocket webSocket, int i, String s, boolean b) { }
-
- @Override
- public void onMessage(org.java_websocket.WebSocket webSocket, String s) { }
-
- @Override
- public void onError(WebSocket webSocket, Exception e) { }
-
- @Override
- public void onStart() { }
- }
@BeforeAll
- static void startWebSockerServer() {
- webSocketServer = new WebSocketServerImpl(new InetSocketAddress("localhost", WS_SERVER_PORT));
- new Thread(webSocketServer).start();
+ static void startWebSockerServer() throws InterruptedException {
+ webSocketServer = WebSocketServerImpl.create();
}
@AfterAll
diff --git a/playwright/src/test/java/com/microsoft/playwright/WebSocketServerImpl.java b/playwright/src/test/java/com/microsoft/playwright/WebSocketServerImpl.java
new file mode 100644
index 00000000..cd864ab9
--- /dev/null
+++ b/playwright/src/test/java/com/microsoft/playwright/WebSocketServerImpl.java
@@ -0,0 +1,70 @@
+/*
+ * 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.java_websocket.WebSocket;
+import org.java_websocket.handshake.ClientHandshake;
+import org.java_websocket.server.WebSocketServer;
+
+import java.net.InetSocketAddress;
+import java.util.concurrent.Semaphore;
+
+class WebSocketServerImpl extends WebSocketServer implements AutoCloseable {
+ volatile ClientHandshake lastClientHandshake;
+ private final Semaphore startSemaphore = new Semaphore(0);
+
+ static final int WS_SERVER_PORT = 8910;
+
+ static WebSocketServerImpl create() throws InterruptedException {
+ WebSocketServerImpl result = new WebSocketServerImpl(new InetSocketAddress("localhost", WebSocketServerImpl.WS_SERVER_PORT));
+ result.start();
+ result.startSemaphore.acquire();
+ return result;
+ }
+
+ private WebSocketServerImpl(InetSocketAddress address) {
+ super(address, 1);
+ }
+
+ @Override
+ public void close() throws Exception {
+ this.stop();
+ }
+
+ @Override
+ public void onOpen(org.java_websocket.WebSocket webSocket, ClientHandshake clientHandshake) {
+ lastClientHandshake = clientHandshake;
+ webSocket.send("incoming");
+ }
+
+ @Override
+ public void onClose(org.java_websocket.WebSocket webSocket, int i, String s, boolean b) {
+ }
+
+ @Override
+ public void onMessage(org.java_websocket.WebSocket webSocket, String s) {
+ }
+
+ @Override
+ public void onError(WebSocket webSocket, Exception e) {
+ }
+
+ @Override
+ public void onStart() {
+ startSemaphore.release();
+ }
+}
diff --git a/scripts/CLI_VERSION b/scripts/CLI_VERSION
index ce392920..25738e33 100644
--- a/scripts/CLI_VERSION
+++ b/scripts/CLI_VERSION
@@ -1 +1 @@
-1.11.0-next-1618951606000
+1.11.0-next-1619459952000