diff --git a/README.md b/README.md index 5ff12a170..676b4b9f4 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,9 @@ Playwright is a Java library to automate [Chromium](https://www.chromium.org/Hom | | Linux | macOS | Windows | | :--- | :---: | :---: | :---: | -| Chromium 134.0.6998.35 | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Chromium 136.0.7103.25 | :white_check_mark: | :white_check_mark: | :white_check_mark: | | WebKit 18.4 | ✅ | ✅ | ✅ | -| Firefox 135.0 | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Firefox 137.0 | :white_check_mark: | :white_check_mark: | :white_check_mark: | ## Documentation diff --git a/playwright/src/main/java/com/microsoft/playwright/APIRequest.java b/playwright/src/main/java/com/microsoft/playwright/APIRequest.java index 85833f084..ba3090b79 100644 --- a/playwright/src/main/java/com/microsoft/playwright/APIRequest.java +++ b/playwright/src/main/java/com/microsoft/playwright/APIRequest.java @@ -72,6 +72,12 @@ class NewContextOptions { * Whether to ignore HTTPS errors when sending network requests. Defaults to {@code false}. */ public Boolean ignoreHTTPSErrors; + /** + * Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is + * exceeded. Defaults to {@code 20}. Pass {@code 0} to not follow redirects. This can be overwritten for each request + * individually. + */ + public Integer maxRedirects; /** * Network proxy settings. */ @@ -171,6 +177,15 @@ public NewContextOptions setIgnoreHTTPSErrors(boolean ignoreHTTPSErrors) { this.ignoreHTTPSErrors = ignoreHTTPSErrors; return this; } + /** + * Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is + * exceeded. Defaults to {@code 20}. Pass {@code 0} to not follow redirects. This can be overwritten for each request + * individually. + */ + public NewContextOptions setMaxRedirects(int maxRedirects) { + this.maxRedirects = maxRedirects; + return this; + } /** * Network proxy settings. */ diff --git a/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java b/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java index be6b18654..97b46508b 100644 --- a/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java +++ b/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java @@ -411,8 +411,6 @@ class StorageStateOptions { * Set to {@code true} to include IndexedDB in * the storage state snapshot. If your application uses IndexedDB to store authentication tokens, like Firebase * Authentication, enable this. - * - *
NOTE: IndexedDBs with typed arrays are currently not supported. */ public Boolean indexedDB; /** @@ -425,8 +423,6 @@ class StorageStateOptions { * Set to {@code true} to include IndexedDB in * the storage state snapshot. If your application uses IndexedDB to store authentication tokens, like Firebase * Authentication, enable this. - * - *
NOTE: IndexedDBs with typed arrays are currently not supported.
*/
public StorageStateOptions setIndexedDB(boolean indexedDB) {
this.indexedDB = indexedDB;
@@ -996,8 +992,8 @@ default void grantPermissions(List NOTE: Enabling routing disables http cache.
*
- * @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
- * context options was provided and the passed URL is a path, it gets merged via the {@code new URL()} constructor.
* @param handler handler function to route the request.
* @since v1.8
@@ -1052,8 +1048,8 @@ default void route(String url, Consumer NOTE: Enabling routing disables http cache.
*
- * @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
- * context options was provided and the passed URL is a path, it gets merged via the {@code new URL()} constructor.
* @param handler handler function to route the request.
* @since v1.8
@@ -1106,8 +1102,8 @@ default void route(String url, Consumer NOTE: Enabling routing disables http cache.
*
- * @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
- * context options was provided and the passed URL is a path, it gets merged via the {@code new URL()} constructor.
* @param handler handler function to route the request.
* @since v1.8
@@ -1162,8 +1158,8 @@ default void route(Pattern url, Consumer NOTE: Enabling routing disables http cache.
*
- * @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
- * context options was provided and the passed URL is a path, it gets merged via the {@code new URL()} constructor.
* @param handler handler function to route the request.
* @since v1.8
@@ -1216,8 +1212,8 @@ default void route(Pattern url, Consumer NOTE: Enabling routing disables http cache.
*
- * @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
- * context options was provided and the passed URL is a path, it gets merged via the {@code new URL()} constructor.
* @param handler handler function to route the request.
* @since v1.8
@@ -1272,8 +1268,8 @@ default void route(Predicate NOTE: Enabling routing disables http cache.
*
- * @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
- * context options was provided and the passed URL is a path, it gets merged via the {@code new URL()} constructor.
* @param handler handler function to route the request.
* @since v1.8
diff --git a/playwright/src/main/java/com/microsoft/playwright/BrowserType.java b/playwright/src/main/java/com/microsoft/playwright/BrowserType.java
index b100387de..6f6681fc1 100644
--- a/playwright/src/main/java/com/microsoft/playwright/BrowserType.java
+++ b/playwright/src/main/java/com/microsoft/playwright/BrowserType.java
@@ -226,8 +226,8 @@ class LaunchOptions {
/**
* Whether to run browser in headless mode. More details for Chromium and Firefox. Defaults to {@code true}
- * unless the {@code devtools} option is {@code true}.
+ * href="https://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/">Firefox. Defaults to {@code true} unless
+ * the {@code devtools} option is {@code true}.
*/
public Boolean headless;
/**
@@ -368,8 +368,8 @@ public LaunchOptions setHandleSIGTERM(boolean handleSIGTERM) {
/**
* Whether to run browser in headless mode. More details for Chromium and Firefox. Defaults to {@code true}
- * unless the {@code devtools} option is {@code true}.
+ * href="https://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/">Firefox. Defaults to {@code true} unless
+ * the {@code devtools} option is {@code true}.
*/
public LaunchOptions setHeadless(boolean headless) {
this.headless = headless;
@@ -564,8 +564,8 @@ class LaunchPersistentContextOptions {
/**
* Whether to run browser in headless mode. More details for Chromium and Firefox. Defaults to {@code true}
- * unless the {@code devtools} option is {@code true}.
+ * href="https://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/">Firefox. Defaults to {@code true} unless
+ * the {@code devtools} option is {@code true}.
*/
public Boolean headless;
/**
@@ -934,8 +934,8 @@ public LaunchPersistentContextOptions setHasTouch(boolean hasTouch) {
/**
* Whether to run browser in headless mode. More details for Chromium and Firefox. Defaults to {@code true}
- * unless the {@code devtools} option is {@code true}.
+ * href="https://hacks.mozilla.org/2017/12/using-headless-mode-in-firefox/">Firefox. Defaults to {@code true} unless
+ * the {@code devtools} option is {@code true}.
*/
public LaunchPersistentContextOptions setHeadless(boolean headless) {
this.headless = headless;
@@ -1365,11 +1365,15 @@ default Browser launch() {
* Launches browser that uses persistent storage located at {@code userDataDir} and returns the only context. Closing this
* context will automatically close the browser.
*
- * @param userDataDir Path to a User Data Directory, which stores browser session data like cookies and local storage. More details for More details for Chromium and Firefox. Note that
- * Chromium's user data directory is the **parent** directory of the "Profile Path" seen at {@code chrome://version}. Pass
- * an empty string to use a temporary directory instead.
+ * href="https://wiki.mozilla.org/Firefox/CommandLineOptions#User_profile">Firefox. Chromium's user data directory is
+ * the **parent** directory of the "Profile Path" seen at {@code chrome://version}.
+ *
+ * Note that browsers do not allow launching multiple instances with the same User Data Directory.
* @since v1.8
*/
default BrowserContext launchPersistentContext(Path userDataDir) {
@@ -1381,11 +1385,15 @@ default BrowserContext launchPersistentContext(Path userDataDir) {
* Launches browser that uses persistent storage located at {@code userDataDir} and returns the only context. Closing this
* context will automatically close the browser.
*
- * @param userDataDir Path to a User Data Directory, which stores browser session data like cookies and local storage. More details for More details for Chromium and Firefox. Note that
- * Chromium's user data directory is the **parent** directory of the "Profile Path" seen at {@code chrome://version}. Pass
- * an empty string to use a temporary directory instead.
+ * href="https://wiki.mozilla.org/Firefox/CommandLineOptions#User_profile">Firefox. Chromium's user data directory is
+ * the **parent** directory of the "Profile Path" seen at {@code chrome://version}.
+ *
+ * Note that browsers do not allow launching multiple instances with the same User Data Directory.
* @since v1.8
*/
BrowserContext launchPersistentContext(Path userDataDir, LaunchPersistentContextOptions options);
diff --git a/playwright/src/main/java/com/microsoft/playwright/Locator.java b/playwright/src/main/java/com/microsoft/playwright/Locator.java
index 1fdaea343..0027ea4fc 100644
--- a/playwright/src/main/java/com/microsoft/playwright/Locator.java
+++ b/playwright/src/main/java/com/microsoft/playwright/Locator.java
@@ -30,6 +30,11 @@
*/
public interface Locator {
class AriaSnapshotOptions {
+ /**
+ * Generate symbolic reference for each element. One can use {@code aria-ref=} locator immediately after capturing the
+ * snapshot to perform actions on the element.
+ */
+ public Boolean ref;
/**
* Maximum time in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
* value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
@@ -38,6 +43,14 @@ class AriaSnapshotOptions {
*/
public Double timeout;
+ /**
+ * Generate symbolic reference for each element. One can use {@code aria-ref=} locator immediately after capturing the
+ * snapshot to perform actions on the element.
+ */
+ public AriaSnapshotOptions setRef(boolean ref) {
+ this.ref = ref;
+ return this;
+ }
/**
* Maximum time in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
* value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
@@ -600,18 +613,14 @@ public ElementHandleOptions setTimeout(double timeout) {
}
class EvaluateOptions {
/**
- * Maximum time in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
- * value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
- * BrowserContext.setDefaultTimeout()} or {@link com.microsoft.playwright.Page#setDefaultTimeout Page.setDefaultTimeout()}
- * methods.
+ * Maximum time in milliseconds to wait for the locator before evaluating. Note that after locator is resolved, evaluation
+ * itself is not limited by the timeout. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout.
*/
public Double timeout;
/**
- * Maximum time in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
- * value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
- * BrowserContext.setDefaultTimeout()} or {@link com.microsoft.playwright.Page#setDefaultTimeout Page.setDefaultTimeout()}
- * methods.
+ * Maximum time in milliseconds to wait for the locator before evaluating. Note that after locator is resolved, evaluation
+ * itself is not limited by the timeout. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout.
*/
public EvaluateOptions setTimeout(double timeout) {
this.timeout = timeout;
@@ -620,18 +629,14 @@ public EvaluateOptions setTimeout(double timeout) {
}
class EvaluateHandleOptions {
/**
- * Maximum time in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
- * value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
- * BrowserContext.setDefaultTimeout()} or {@link com.microsoft.playwright.Page#setDefaultTimeout Page.setDefaultTimeout()}
- * methods.
+ * Maximum time in milliseconds to wait for the locator before evaluating. Note that after locator is resolved, evaluation
+ * itself is not limited by the timeout. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout.
*/
public Double timeout;
/**
- * Maximum time in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
- * value can be changed by using the {@link com.microsoft.playwright.BrowserContext#setDefaultTimeout
- * BrowserContext.setDefaultTimeout()} or {@link com.microsoft.playwright.Page#setDefaultTimeout Page.setDefaultTimeout()}
- * methods.
+ * Maximum time in milliseconds to wait for the locator before evaluating. Note that after locator is resolved, evaluation
+ * itself is not limited by the timeout. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout.
*/
public EvaluateHandleOptions setTimeout(double timeout) {
this.timeout = timeout;
diff --git a/playwright/src/main/java/com/microsoft/playwright/Page.java b/playwright/src/main/java/com/microsoft/playwright/Page.java
index 4a3cd7314..3f7158283 100644
--- a/playwright/src/main/java/com/microsoft/playwright/Page.java
+++ b/playwright/src/main/java/com/microsoft/playwright/Page.java
@@ -6317,8 +6317,8 @@ default Response reload() {
*
* NOTE: Enabling routing disables http cache.
*
- * @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
- * context options was provided and the passed URL is a path, it gets merged via the {@code new URL()} constructor.
* @param handler handler function to route the request.
* @since v1.8
@@ -6376,8 +6376,8 @@ default void route(String url, Consumer NOTE: Enabling routing disables http cache.
*
- * @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
- * context options was provided and the passed URL is a path, it gets merged via the {@code new URL()} constructor.
* @param handler handler function to route the request.
* @since v1.8
@@ -6433,8 +6433,8 @@ default void route(String url, Consumer NOTE: Enabling routing disables http cache.
*
- * @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
- * context options was provided and the passed URL is a path, it gets merged via the {@code new URL()} constructor.
* @param handler handler function to route the request.
* @since v1.8
@@ -6492,8 +6492,8 @@ default void route(Pattern url, Consumer NOTE: Enabling routing disables http cache.
*
- * @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
- * context options was provided and the passed URL is a path, it gets merged via the {@code new URL()} constructor.
* @param handler handler function to route the request.
* @since v1.8
@@ -6549,8 +6549,8 @@ default void route(Pattern url, Consumer NOTE: Enabling routing disables http cache.
*
- * @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
- * context options was provided and the passed URL is a path, it gets merged via the {@code new URL()} constructor.
* @param handler handler function to route the request.
* @since v1.8
@@ -6608,8 +6608,8 @@ default void route(Predicate NOTE: Enabling routing disables http cache.
*
- * @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
- * context options was provided and the passed URL is a path, it gets merged via the {@code new URL()} constructor.
* @param handler handler function to route the request.
* @since v1.8
diff --git a/playwright/src/main/java/com/microsoft/playwright/Route.java b/playwright/src/main/java/com/microsoft/playwright/Route.java
index ae05c816c..e9bc75a7f 100644
--- a/playwright/src/main/java/com/microsoft/playwright/Route.java
+++ b/playwright/src/main/java/com/microsoft/playwright/Route.java
@@ -370,6 +370,10 @@ default void abort() {
* matching handlers won't be invoked. Use {@link com.microsoft.playwright.Route#fallback Route.fallback()} If you want
* next matching handler in the chain to be invoked.
*
+ * NOTE: The {@code Cookie} header cannot be overridden using this method. If a value is provided, it will be ignored, and the
+ * cookie will be loaded from the browser's cookie store. To set custom cookies, use {@link
+ * com.microsoft.playwright.BrowserContext#addCookies BrowserContext.addCookies()}.
+ *
* @since v1.8
*/
default void resume() {
@@ -398,6 +402,10 @@ default void resume() {
* matching handlers won't be invoked. Use {@link com.microsoft.playwright.Route#fallback Route.fallback()} If you want
* next matching handler in the chain to be invoked.
*
+ * NOTE: The {@code Cookie} header cannot be overridden using this method. If a value is provided, it will be ignored, and the
+ * cookie will be loaded from the browser's cookie store. To set custom cookies, use {@link
+ * com.microsoft.playwright.BrowserContext#addCookies BrowserContext.addCookies()}.
+ *
* @since v1.8
*/
void resume(ResumeOptions options);
diff --git a/playwright/src/main/java/com/microsoft/playwright/assertions/LocatorAssertions.java b/playwright/src/main/java/com/microsoft/playwright/assertions/LocatorAssertions.java
index fc021796e..a8607fdfd 100644
--- a/playwright/src/main/java/com/microsoft/playwright/assertions/LocatorAssertions.java
+++ b/playwright/src/main/java/com/microsoft/playwright/assertions/LocatorAssertions.java
@@ -16,6 +16,7 @@
package com.microsoft.playwright.assertions;
+import java.util.*;
import java.util.regex.Pattern;
import com.microsoft.playwright.options.AriaRole;
@@ -237,6 +238,20 @@ public IsVisibleOptions setVisible(boolean visible) {
return this;
}
}
+ class ContainsClassOptions {
+ /**
+ * Time to retry the assertion for in milliseconds. Defaults to {@code 5000}.
+ */
+ public Double timeout;
+
+ /**
+ * Time to retry the assertion for in milliseconds. Defaults to {@code 5000}.
+ */
+ public ContainsClassOptions setTimeout(double timeout) {
+ this.timeout = timeout;
+ return this;
+ }
+ }
class ContainsTextOptions {
/**
* Whether to perform case-insensitive match. {@code ignoreCase} option takes precedence over the corresponding regular
@@ -855,6 +870,98 @@ default void isVisible() {
* @since v1.20
*/
void isVisible(IsVisibleOptions options);
+ /**
+ * Ensures the {@code Locator} points to an element with given CSS classes. All classes from the asserted value, separated
+ * by spaces, must be present in the Element.classList in any order.
+ *
+ * Usage
+ * When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
+ * class lists. Each element's class attribute is matched against the corresponding class in the array:
+ * Usage
+ * When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
+ * class lists. Each element's class attribute is matched against the corresponding class in the array:
+ * Usage
+ * When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
+ * class lists. Each element's class attribute is matched against the corresponding class in the array:
+ * Usage
+ * When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
+ * class lists. Each element's class attribute is matched against the corresponding class in the array:
+ * Usage
* When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
@@ -1468,12 +1576,13 @@ default void hasClass(String expected) {
}
/**
* Ensures the {@code Locator} points to an element with given CSS classes. When a string is provided, it must fully match
- * the element's {@code class} attribute. To match individual classes or perform partial matches, use a regular expression:
+ * the element's {@code class} attribute. To match individual classes use {@link
+ * com.microsoft.playwright.assertions.LocatorAssertions#containsClass LocatorAssertions.containsClass()}.
*
* Usage
* When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
@@ -1489,12 +1598,13 @@ default void hasClass(String expected) {
void hasClass(String expected, HasClassOptions options);
/**
* Ensures the {@code Locator} points to an element with given CSS classes. When a string is provided, it must fully match
- * the element's {@code class} attribute. To match individual classes or perform partial matches, use a regular expression:
+ * the element's {@code class} attribute. To match individual classes use {@link
+ * com.microsoft.playwright.assertions.LocatorAssertions#containsClass LocatorAssertions.containsClass()}.
*
* Usage
* When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
@@ -1512,12 +1622,13 @@ default void hasClass(Pattern expected) {
}
/**
* Ensures the {@code Locator} points to an element with given CSS classes. When a string is provided, it must fully match
- * the element's {@code class} attribute. To match individual classes or perform partial matches, use a regular expression:
+ * the element's {@code class} attribute. To match individual classes use {@link
+ * com.microsoft.playwright.assertions.LocatorAssertions#containsClass LocatorAssertions.containsClass()}.
*
* Usage
* When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
@@ -1533,12 +1644,13 @@ default void hasClass(Pattern expected) {
void hasClass(Pattern expected, HasClassOptions options);
/**
* Ensures the {@code Locator} points to an element with given CSS classes. When a string is provided, it must fully match
- * the element's {@code class} attribute. To match individual classes or perform partial matches, use a regular expression:
+ * the element's {@code class} attribute. To match individual classes use {@link
+ * com.microsoft.playwright.assertions.LocatorAssertions#containsClass LocatorAssertions.containsClass()}.
*
* Usage
* When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
@@ -1556,12 +1668,13 @@ default void hasClass(String[] expected) {
}
/**
* Ensures the {@code Locator} points to an element with given CSS classes. When a string is provided, it must fully match
- * the element's {@code class} attribute. To match individual classes or perform partial matches, use a regular expression:
+ * the element's {@code class} attribute. To match individual classes use {@link
+ * com.microsoft.playwright.assertions.LocatorAssertions#containsClass LocatorAssertions.containsClass()}.
*
* Usage
* When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
@@ -1577,12 +1690,13 @@ default void hasClass(String[] expected) {
void hasClass(String[] expected, HasClassOptions options);
/**
* Ensures the {@code Locator} points to an element with given CSS classes. When a string is provided, it must fully match
- * the element's {@code class} attribute. To match individual classes or perform partial matches, use a regular expression:
+ * the element's {@code class} attribute. To match individual classes use {@link
+ * com.microsoft.playwright.assertions.LocatorAssertions#containsClass LocatorAssertions.containsClass()}.
*
* Usage
* When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
@@ -1600,12 +1714,13 @@ default void hasClass(Pattern[] expected) {
}
/**
* Ensures the {@code Locator} points to an element with given CSS classes. When a string is provided, it must fully match
- * the element's {@code class} attribute. To match individual classes or perform partial matches, use a regular expression:
+ * the element's {@code class} attribute. To match individual classes use {@link
+ * com.microsoft.playwright.assertions.LocatorAssertions#containsClass LocatorAssertions.containsClass()}.
*
* Usage
* When an array is passed, the method asserts that the list of elements located matches the corresponding list of expected
diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java
index c1bb3dd72..4d0f84025 100644
--- a/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java
+++ b/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java
@@ -480,7 +480,7 @@ public APIRequestContextImpl request() {
@Override
public void route(String url, Consumer{@code
+ * assertThat(page.locator("#component")).containsClass("middle selected row");
+ * assertThat(page.locator("#component")).containsClass("selected");
+ * assertThat(page.locator("#component")).containsClass("row middle");
+ * }
+ *
+ * {@code
+ * assertThat(page.locator("list > .component")).containsClass(new String[] {"inactive", "active", "inactive"});
+ * }
+ *
+ * @param expected A string containing expected class names, separated by spaces, or a list of such strings to assert multiple elements.
+ * @since v1.52
+ */
+ default void containsClass(String expected) {
+ containsClass(expected, null);
+ }
+ /**
+ * Ensures the {@code Locator} points to an element with given CSS classes. All classes from the asserted value, separated
+ * by spaces, must be present in the Element.classList in any order.
+ *
+ * {@code
+ * assertThat(page.locator("#component")).containsClass("middle selected row");
+ * assertThat(page.locator("#component")).containsClass("selected");
+ * assertThat(page.locator("#component")).containsClass("row middle");
+ * }
+ *
+ * {@code
+ * assertThat(page.locator("list > .component")).containsClass(new String[] {"inactive", "active", "inactive"});
+ * }
+ *
+ * @param expected A string containing expected class names, separated by spaces, or a list of such strings to assert multiple elements.
+ * @since v1.52
+ */
+ void containsClass(String expected, ContainsClassOptions options);
+ /**
+ * Ensures the {@code Locator} points to an element with given CSS classes. All classes from the asserted value, separated
+ * by spaces, must be present in the Element.classList in any order.
+ *
+ * {@code
+ * assertThat(page.locator("#component")).containsClass("middle selected row");
+ * assertThat(page.locator("#component")).containsClass("selected");
+ * assertThat(page.locator("#component")).containsClass("row middle");
+ * }
+ *
+ * {@code
+ * assertThat(page.locator("list > .component")).containsClass(new String[] {"inactive", "active", "inactive"});
+ * }
+ *
+ * @param expected A string containing expected class names, separated by spaces, or a list of such strings to assert multiple elements.
+ * @since v1.52
+ */
+ default void containsClass(List{@code
+ * assertThat(page.locator("#component")).containsClass("middle selected row");
+ * assertThat(page.locator("#component")).containsClass("selected");
+ * assertThat(page.locator("#component")).containsClass("row middle");
+ * }
+ *
+ * {@code
+ * assertThat(page.locator("list > .component")).containsClass(new String[] {"inactive", "active", "inactive"});
+ * }
+ *
+ * @param expected A string containing expected class names, separated by spaces, or a list of such strings to assert multiple elements.
+ * @since v1.52
+ */
+ void containsClass(List{@code
- * assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
* assertThat(page.locator("#component")).hasClass("middle selected row");
+ * assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
* }
*
* {@code
- * assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
* assertThat(page.locator("#component")).hasClass("middle selected row");
+ * assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
* }
*
* {@code
- * assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
* assertThat(page.locator("#component")).hasClass("middle selected row");
+ * assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
* }
*
* {@code
- * assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
* assertThat(page.locator("#component")).hasClass("middle selected row");
+ * assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
* }
*
* {@code
- * assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
* assertThat(page.locator("#component")).hasClass("middle selected row");
+ * assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
* }
*
* {@code
- * assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
* assertThat(page.locator("#component")).hasClass("middle selected row");
+ * assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
* }
*
* {@code
- * assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
* assertThat(page.locator("#component")).hasClass("middle selected row");
+ * assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
* }
*
* {@code
- * assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
* assertThat(page.locator("#component")).hasClass("middle selected row");
+ * assertThat(page.locator("#component")).hasClass(Pattern.compile("(^|\\s)selected(\\s|$)"));
* }
*
*
");
+ assertEquals(unshift("- list [ref=s1e3]:\n - listitem [ref=s1e4]: foo"), page.locator("body").ariaSnapshot(new AriaSnapshotOptions().setRef(true)));
}
@Test
@@ -83,4 +92,23 @@ void shouldSnapshotDetailsVisibility(Page page) {
page.setContent("Summary
");
+ assertThat(page.locator("body")).matchesAriaSnapshot("- list:\n - /children: equal\n - listitem\n - listitem: Two\n - listitem: Three");
+ assertThat(page.locator("body")).not().matchesAriaSnapshot("- list:\n - /children: equal\n - listitem\n - listitem: Two");
+
+ assertThat(page.locator("body")).matchesAriaSnapshot("- list:\n - /children: deep-equal\n - listitem:\n - img\n - text: One\n - listitem: Two\n - listitem: Three");
+ assertThat(page.locator("body")).not().matchesAriaSnapshot("- list:\n - /children: deep-equal\n - listitem:\n - text: One\n - listitem: Two\n - listitem: Three");
+ assertThat(page.locator("body")).matchesAriaSnapshot("- list:\n - /children: deep-equal\n - listitem:\n - /children: contain\n - text: One\n - listitem: Two\n - listitem: Three");
+ }
+
+ @Test
+ void shouldMatchUrl(Page page) {
+ page.setContent("Link");
+ assertThat(page.locator("body")).matchesAriaSnapshot("" +
+ "- link:\n" +
+ " - /url: /.*example.com/");
+ }
}
diff --git a/playwright/src/test/java/com/microsoft/playwright/TestPageClock.java b/playwright/src/test/java/com/microsoft/playwright/TestPageClock.java
index bbdbb2d29..d00d365d6 100644
--- a/playwright/src/test/java/com/microsoft/playwright/TestPageClock.java
+++ b/playwright/src/test/java/com/microsoft/playwright/TestPageClock.java
@@ -391,8 +391,8 @@ void whileRunningShouldPause(Page page) {
page.clock().install(new Clock.InstallOptions().setTime(0));
page.navigate("data:text/html,");
page.clock().pauseAt(1000);
- page.waitForTimeout(1000);
- page.clock().resume();
+ // Internally wait to make sure the clock is paused and not running.
+ page.waitForTimeout(1111);
int now = (int) page.evaluate("() => Date.now()");
assertTrue(now >= 0 && now <= 1000);
}
diff --git a/playwright/src/test/java/com/microsoft/playwright/TestPageInterception.java b/playwright/src/test/java/com/microsoft/playwright/TestPageInterception.java
index a398ede58..a6462ff22 100644
--- a/playwright/src/test/java/com/microsoft/playwright/TestPageInterception.java
+++ b/playwright/src/test/java/com/microsoft/playwright/TestPageInterception.java
@@ -18,11 +18,12 @@
import org.junit.jupiter.api.Test;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
+import com.microsoft.playwright.impl.PlaywrightImpl;
+
import java.util.HashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
+import java.util.regex.Pattern;
import static org.junit.jupiter.api.Assertions.*;
@@ -141,13 +142,82 @@ void shouldNotFollowRedirectsWhenMaxRedirectsIsSetTo0InRouteFetch() {
}
@Test
- void shouldProperlyHandleCharacterSetsInGlobs() {
- page.route("**/[a-z]*.html", route -> {
- APIResponse response = route.fetch(new Route.FetchOptions().setUrl(server.PREFIX + "/one-style.html"));
- route.fulfill(new Route.FulfillOptions().setResponse(response));
- });
- Response response = page.navigate(server.PREFIX + "/empty.html");
- assertEquals(200, response.status());
- assertTrue(response.text().contains("one-style.css"), response.text());
+ void shouldWorkWithGlob() {
+ assertTrue(globToRegex("**/*.js").matcher("https://localhost:8080/foo.js").find());
+ assertFalse(globToRegex("**/*.css").matcher("https://localhost:8080/foo.js").find());
+ assertFalse(globToRegex("*.js").matcher("https://localhost:8080/foo.js").find());
+ assertTrue(globToRegex("https://**/*.js").matcher("https://localhost:8080/foo.js").find());
+ assertTrue(globToRegex("http://localhost:8080/simple/path.js").matcher("http://localhost:8080/simple/path.js").find());
+ assertTrue(globToRegex("**/{a,b}.js").matcher("https://localhost:8080/a.js").find());
+ assertTrue(globToRegex("**/{a,b}.js").matcher("https://localhost:8080/b.js").find());
+ assertFalse(globToRegex("**/{a,b}.js").matcher("https://localhost:8080/c.js").find());
+
+ assertTrue(globToRegex("**/*.{png,jpg,jpeg}").matcher("https://localhost:8080/c.jpg").find());
+ assertTrue(globToRegex("**/*.{png,jpg,jpeg}").matcher("https://localhost:8080/c.jpeg").find());
+ assertTrue(globToRegex("**/*.{png,jpg,jpeg}").matcher("https://localhost:8080/c.png").find());
+ assertFalse(globToRegex("**/*.{png,jpg,jpeg}").matcher("https://localhost:8080/c.css").find());
+ assertTrue(globToRegex("foo*").matcher("foo.js").find());
+ assertFalse(globToRegex("foo*").matcher("foo/bar.js").find());
+ assertFalse(globToRegex("http://localhost:3000/signin-oidc*").matcher("http://localhost:3000/signin-oidc/foo").find());
+ assertTrue(globToRegex("http://localhost:3000/signin-oidc*").matcher("http://localhost:3000/signin-oidcnice").find());
+
+ // range [] is NOT supported
+ assertTrue(globToRegex("**/api/v[0-9]").matcher("http://example.com/api/v[0-9]").find());
+ assertFalse(globToRegex("**/api/v[0-9]").matcher("http://example.com/api/version").find());
+
+ // query params
+ assertTrue(globToRegex("**/api\\?param").matcher("http://example.com/api?param").find());
+ assertFalse(globToRegex("**/api\\?param").matcher("http://example.com/api-param").find());
+ assertTrue(globToRegex("**/three-columns/settings.html\\?**id=settings-**").matcher("http://mydomain:8080/blah/blah/three-columns/settings.html?id=settings-e3c58efe-02e9-44b0-97ac-dd138100cf7c&blah").find());
+
+ assertEquals("^\\?$", globToRegex("\\?").pattern());
+ assertEquals("^\\\\$", globToRegex("\\").pattern());
+ assertEquals("^\\\\$", globToRegex("\\\\").pattern());
+ assertEquals("^\\[$", globToRegex("\\[").pattern());
+ assertEquals("^\\[a-z\\]$", globToRegex("[a-z]").pattern());
+ assertEquals("^\\$\\^\\+\\.\\*\\(\\)\\|\\?\\{\\}\\[\\]$", globToRegex("$^+.\\*()|\\?\\{\\}\\[\\]").pattern());
+
+
+ assertTrue(urlMatches(null, "http://playwright.dev/", "http://playwright.dev"));
+ assertTrue(urlMatches(null, "http://playwright.dev/?a=b", "http://playwright.dev?a=b"));
+ assertTrue(urlMatches(null, "http://playwright.dev/", "h*://playwright.dev"));
+ assertTrue(urlMatches(null, "http://api.playwright.dev/?x=y", "http://*.playwright.dev?x=y"));
+ assertTrue(urlMatches(null, "http://playwright.dev/foo/bar", "**/foo/**"));
+ assertTrue(urlMatches("http://playwright.dev", "http://playwright.dev/?x=y", "?x=y"));
+ assertTrue(urlMatches("http://playwright.dev/foo/", "http://playwright.dev/foo/bar?x=y", "./bar?x=y"));
+
+ // This is not supported, we treat ? as a query separator.
+ assertFalse(urlMatches(null, "http://localhost:8080/Simple/path.js", "http://localhost:8080/?imple/path.js"));
+ assertFalse(urlMatches(null, "http://playwright.dev/", "http://playwright.?ev"));
+ assertTrue(urlMatches(null, "http://playwright./?ev", "http://playwright.?ev"));
+ assertFalse(urlMatches(null, "http://playwright.dev/foo", "http://playwright.dev/f??"));
+ assertTrue(urlMatches(null, "http://playwright.dev/f??", "http://playwright.dev/f??"));
+ assertTrue(urlMatches(null, "http://playwright.dev/?x=y", "http://playwright.dev\\\\?x=y"));
+ assertTrue(urlMatches(null, "http://playwright.dev/?x=y", "http://playwright.dev/\\\\?x=y"));
+ assertTrue(urlMatches("http://playwright.dev/foo", "http://playwright.dev/foo?bar", "?bar"));
+ assertTrue(urlMatches("http://playwright.dev/foo", "http://playwright.dev/foo?bar", "\\\\?bar"));
+ assertTrue(urlMatches("http://first.host/", "http://second.host/foo", "**/foo"));
+ assertTrue(urlMatches("http://playwright.dev/", "http://localhost/", "*//localhost/"));
+ }
+
+ Pattern globToRegex(String glob) {
+ return globToRegex(glob, null, false);
+ }
+
+ Pattern globToRegex(String glob, String baseURL, boolean webSocketUrl) {
+ return ((PlaywrightImpl) playwright).localUtils().globToRegex(glob, baseURL, webSocketUrl);
+ }
+
+ boolean urlMatches(String baseURL, String urlString, String match) {
+ if (match == null) {
+ return true;
+ }
+
+ String glob = (String) match;
+ if (glob.isEmpty()) {
+ return true;
+ }
+
+ return globToRegex(glob, baseURL, false).matcher(urlString).find();
}
}
diff --git a/playwright/src/test/java/com/microsoft/playwright/TestPageRequestContinue.java b/playwright/src/test/java/com/microsoft/playwright/TestPageRequestContinue.java
index 404371102..f715dd13a 100644
--- a/playwright/src/test/java/com/microsoft/playwright/TestPageRequestContinue.java
+++ b/playwright/src/test/java/com/microsoft/playwright/TestPageRequestContinue.java
@@ -16,9 +16,12 @@
package com.microsoft.playwright;
+import com.microsoft.playwright.options.HttpHeader;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledIf;
import java.io.OutputStreamWriter;
+import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@@ -77,4 +80,83 @@ void shouldNotThrowWhenContinuingAfterPageIsClosed() {
e.getMessage().contains("frame was detached"), e.getMessage());
assertTrue(done[0]);
}
+
+ @Test
+ @DisabledIf(value = "com.microsoft.playwright.TestBase#isFirefox", disabledReason = "We currently clear all headers during interception in firefox")
+ void continueShouldNotPropagateCookieOverrideToRedirects() throws ExecutionException, InterruptedException {
+ // https://github.com/microsoft/playwright/issues/35168
+ server.setRoute("/set-cookie", exchange -> {
+ exchange.getResponseHeaders().add("Set-Cookie", "foo=bar;");
+ exchange.sendResponseHeaders(200, 0);
+ exchange.getResponseBody().close();
+ });
+ page.navigate(server.PREFIX + "/set-cookie");
+ assertEquals("foo=bar", page.evaluate("() => document.cookie"));
+
+ server.setRedirect("/redirect", server.PREFIX + "/empty.html");
+ page.route("**/redirect", route -> {
+ MapOne
Heading
\n" +
+ "");
+ // Non-control roles do not inherit disabled state
+ assertThat(page.locator("h1")).isEnabled();
+ }
+
+ @Test
+ void shouldSupportDisabledFieldset() {
+ page.setContent(
+ "\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "");
+
+ assertThat(page.getByTestId("inside-legend-element")).isEnabled();
+ assertThat(page.getByTestId("nested-inside-legend-element")).isEnabled();
+ assertThat(page.getByTestId("first-legend-element")).isEnabled();
+ // Only the first legend is exempt from disabled fieldset
+ assertThat(page.getByTestId("second-legend-element")).isDisabled();
+ // Nested fieldsets inherit disabled state
+ assertThat(page.getByTestId("deep-button")).isDisabled();
+ }
+
@Test
void shouldSupportLevel() {
page.setContent("Hello
\n" +
@@ -357,15 +418,6 @@ void shouldSupportName() {
""
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName(Pattern.compile("^H[ae]llo$"))).evaluateAll("els => els.map(e => e.outerHTML)"));
- assertEquals(asList(
- "",
- ""
- ), page.locator("role=button[name=/h.*o/i]").evaluateAll("els => els.map(e => e.outerHTML)"));
- assertEquals(asList(
- "",
- ""
- ), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName(Pattern.compile("h.*o", Pattern.CASE_INSENSITIVE))).evaluateAll("els => els.map(e => e.outerHTML)"));
-
assertEquals(asList(
"",
""
diff --git a/playwright/src/test/resources/to-do-notifications/scripts/todo.js b/playwright/src/test/resources/to-do-notifications/scripts/todo.js
index 2e3cfae21..40e4bbbb0 100644
--- a/playwright/src/test/resources/to-do-notifications/scripts/todo.js
+++ b/playwright/src/test/resources/to-do-notifications/scripts/todo.js
@@ -140,7 +140,7 @@ window.onload = () => {
// Grab the values entered into the form fields and store them in an object ready for being inserted into the IndexedDB
const newItem = [
- { taskTitle: title.value, hours: hours.value, minutes: minutes.value, day: day.value, month: month.value, year: year.value, notified: 'no' },
+ { taskTitle: title.value, hours: hours.value, minutes: minutes.value, day: day.value, month: month.value, year: year.value, notified: 'no', signature: new TextEncoder().encode("signed by simon") },
];
// Open a read/write DB transaction, ready for adding the data
diff --git a/scripts/DRIVER_VERSION b/scripts/DRIVER_VERSION
index c73f500ec..a63cb35e6 100644
--- a/scripts/DRIVER_VERSION
+++ b/scripts/DRIVER_VERSION
@@ -1 +1 @@
-1.51.1
+1.52.0
diff --git a/tools/api-generator/src/main/java/com/microsoft/playwright/tools/ApiGenerator.java b/tools/api-generator/src/main/java/com/microsoft/playwright/tools/ApiGenerator.java
index c0b299240..fc088237d 100644
--- a/tools/api-generator/src/main/java/com/microsoft/playwright/tools/ApiGenerator.java
+++ b/tools/api-generator/src/main/java/com/microsoft/playwright/tools/ApiGenerator.java
@@ -998,7 +998,7 @@ void writeTo(List