diff --git a/.claude/skills/playwright-roll/SKILL.md b/.claude/skills/playwright-roll/SKILL.md new file mode 100644 index 000000000..c33ecdcbb --- /dev/null +++ b/.claude/skills/playwright-roll/SKILL.md @@ -0,0 +1,22 @@ +--- +name: playwright-roll +description: Roll Playwright Java to a new version +--- + +Help the user roll to a new version of Playwright. +ROLLING.md contains general instructions and scripts. + +Start with updating the version and generating the API to see the state of things. +Afterwards, work through the list of changes that need to be backported. +You can find a list of pull requests that might need to be taking into account in the issue titled "Backport changes". +Work through them one-by-one and check off the items that you have handled. +Not all of them will be relevant, some might have partially been reverted, etc. - so feel free to check with the upstream release branch. + +Rolling includes: +- updating client implementation to match changes in the upstream JS implementation (see ../playwright/packages/playwright-core/src/client) +- adding a couple of new tests to verify new/changed functionality + +## Tips & Tricks +- Project checkouts are in the parent directory (`../`). +- When updating checkboxes, store the issue content into /tmp and edit it there, then update the issue based on the file +- use the "gh" cli to interact with GitHub diff --git a/README.md b/README.md index 7278f8930..e5b87f976 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 143.0.7499.4 | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Chromium 145.0.7632.6 | :white_check_mark: | :white_check_mark: | :white_check_mark: | | WebKit 26.0 | ✅ | ✅ | ✅ | -| Firefox 144.0.2 | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Firefox 146.0.1 | :white_check_mark: | :white_check_mark: | :white_check_mark: | ## Documentation diff --git a/examples/pom.xml b/examples/pom.xml index 0fb4c580b..8029f389f 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ Playwright Client Examples UTF-8 - 1.57.0 + 1.58.0 diff --git a/playwright/src/main/java/com/microsoft/playwright/BrowserType.java b/playwright/src/main/java/com/microsoft/playwright/BrowserType.java index 54864b3b0..a0a7383b6 100644 --- a/playwright/src/main/java/com/microsoft/playwright/BrowserType.java +++ b/playwright/src/main/java/com/microsoft/playwright/BrowserType.java @@ -128,6 +128,11 @@ class ConnectOverCDPOptions { * Additional HTTP headers to be sent with connect request. Optional. */ public Map headers; + /** + * Tells Playwright that it runs on the same host as the CDP server. It will enable certain optimizations that rely upon + * the file system being the same between Playwright and the Browser. + */ + public Boolean isLocal; /** * Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going on. * Defaults to 0. @@ -146,6 +151,14 @@ public ConnectOverCDPOptions setHeaders(Map headers) { this.headers = headers; return this; } + /** + * Tells Playwright that it runs on the same host as the CDP server. It will enable certain optimizations that rely upon + * the file system being the same between Playwright and the Browser. + */ + public ConnectOverCDPOptions setIsLocal(boolean isLocal) { + this.isLocal = isLocal; + return this; + } /** * Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going on. * Defaults to 0. @@ -186,10 +199,6 @@ class LaunchOptions { * Enable Chromium sandboxing. Defaults to {@code false}. */ public Boolean chromiumSandbox; - /** - * @deprecated Use debugging tools instead. - */ - public Boolean devtools; /** * If specified, accepted downloads are downloaded into this directory. Otherwise, temporary directory is created and is * deleted when browser is closed. In either case, the downloads are deleted when the browser context they were created in @@ -229,8 +238,7 @@ 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}. */ public Boolean headless; /** @@ -307,13 +315,6 @@ public LaunchOptions setChromiumSandbox(boolean chromiumSandbox) { this.chromiumSandbox = chromiumSandbox; return this; } - /** - * @deprecated Use debugging tools instead. - */ - public LaunchOptions setDevtools(boolean devtools) { - this.devtools = devtools; - return this; - } /** * If specified, accepted downloads are downloaded into this directory. Otherwise, temporary directory is created and is * deleted when browser is closed. In either case, the downloads are deleted when the browser context they were created in @@ -374,8 +375,7 @@ 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}. */ public LaunchOptions setHeadless(boolean headless) { this.headless = headless; @@ -518,10 +518,6 @@ class LaunchPersistentContextOptions { * href="https://playwright.dev/java/docs/emulation#devices">emulating devices with device scale factor. */ public Double deviceScaleFactor; - /** - * @deprecated Use debugging tools instead. - */ - public Boolean devtools; /** * If specified, accepted downloads are downloaded into this directory. Otherwise, temporary directory is created and is * deleted when browser is closed. In either case, the downloads are deleted when the browser context they were created in @@ -577,8 +573,7 @@ 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}. */ public Boolean headless; /** @@ -856,13 +851,6 @@ public LaunchPersistentContextOptions setDeviceScaleFactor(double deviceScaleFac this.deviceScaleFactor = deviceScaleFactor; return this; } - /** - * @deprecated Use debugging tools instead. - */ - public LaunchPersistentContextOptions setDevtools(boolean devtools) { - this.devtools = devtools; - return this; - } /** * If specified, accepted downloads are downloaded into this directory. Otherwise, temporary directory is created and is * deleted when browser is closed. In either case, the downloads are deleted when the browser context they were created in @@ -954,8 +942,7 @@ 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}. */ public LaunchPersistentContextOptions setHeadless(boolean headless) { this.headless = headless; diff --git a/playwright/src/main/java/com/microsoft/playwright/Locator.java b/playwright/src/main/java/com/microsoft/playwright/Locator.java index cba38f1e1..8e4317f4f 100644 --- a/playwright/src/main/java/com/microsoft/playwright/Locator.java +++ b/playwright/src/main/java/com/microsoft/playwright/Locator.java @@ -2661,8 +2661,7 @@ default void dblclick() { Locator describe(String description); /** * Returns locator description previously set with {@link com.microsoft.playwright.Locator#describe Locator.describe()}. - * Returns {@code null} if no custom description has been set. Prefer {@code Locator.toString()} for a human-readable - * representation, as it uses the description when available. + * Returns {@code null} if no custom description has been set. * *

Usage *

{@code
diff --git a/playwright/src/main/java/com/microsoft/playwright/Route.java b/playwright/src/main/java/com/microsoft/playwright/Route.java
index e9bc75a7f..472a9f9a4 100644
--- a/playwright/src/main/java/com/microsoft/playwright/Route.java
+++ b/playwright/src/main/java/com/microsoft/playwright/Route.java
@@ -370,9 +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()}. + *

NOTE: Some request headers are **forbidden** and cannot be overridden (for example, {@code Cookie}, {@code Host}, {@code + * Content-Length} and others, see this MDN page for full list). If + * an override is provided for a forbidden header, it will be ignored and the original request header will be used.To set custom cookies, use {@link com.microsoft.playwright.BrowserContext#addCookies BrowserContext.addCookies()}. * * @since v1.8 */ @@ -402,9 +403,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()}. + *

NOTE: Some request headers are **forbidden** and cannot be overridden (for example, {@code Cookie}, {@code Host}, {@code + * Content-Length} and others, see this MDN page for full list). If + * an override is provided for a forbidden header, it will be ignored and the original request header will be used.To set custom cookies, use {@link com.microsoft.playwright.BrowserContext#addCookies BrowserContext.addCookies()}. * * @since v1.8 */ 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 e541404af..df0725d89 100644 --- a/playwright/src/main/java/com/microsoft/playwright/assertions/LocatorAssertions.java +++ b/playwright/src/main/java/com/microsoft/playwright/assertions/LocatorAssertions.java @@ -989,7 +989,7 @@ default void containsClass(List expected) { *

Let's see how we can use the assertion: *

{@code
    * // ✓ Contains the right items in the right order
-   * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3", "Text 4"});
+   * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3"});
    *
    * // ✖ Wrong order
    * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 3", "Text 2"});
@@ -1034,7 +1034,7 @@ default void containsText(String expected) {
    * 

Let's see how we can use the assertion: *

{@code
    * // ✓ Contains the right items in the right order
-   * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3", "Text 4"});
+   * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3"});
    *
    * // ✖ Wrong order
    * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 3", "Text 2"});
@@ -1077,7 +1077,7 @@ default void containsText(String expected) {
    * 

Let's see how we can use the assertion: *

{@code
    * // ✓ Contains the right items in the right order
-   * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3", "Text 4"});
+   * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3"});
    *
    * // ✖ Wrong order
    * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 3", "Text 2"});
@@ -1122,7 +1122,7 @@ default void containsText(Pattern expected) {
    * 

Let's see how we can use the assertion: *

{@code
    * // ✓ Contains the right items in the right order
-   * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3", "Text 4"});
+   * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3"});
    *
    * // ✖ Wrong order
    * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 3", "Text 2"});
@@ -1165,7 +1165,7 @@ default void containsText(Pattern expected) {
    * 

Let's see how we can use the assertion: *

{@code
    * // ✓ Contains the right items in the right order
-   * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3", "Text 4"});
+   * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3"});
    *
    * // ✖ Wrong order
    * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 3", "Text 2"});
@@ -1210,7 +1210,7 @@ default void containsText(String[] expected) {
    * 

Let's see how we can use the assertion: *

{@code
    * // ✓ Contains the right items in the right order
-   * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3", "Text 4"});
+   * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3"});
    *
    * // ✖ Wrong order
    * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 3", "Text 2"});
@@ -1253,7 +1253,7 @@ default void containsText(String[] expected) {
    * 

Let's see how we can use the assertion: *

{@code
    * // ✓ Contains the right items in the right order
-   * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3", "Text 4"});
+   * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3"});
    *
    * // ✖ Wrong order
    * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 3", "Text 2"});
@@ -1298,7 +1298,7 @@ default void containsText(Pattern[] expected) {
    * 

Let's see how we can use the assertion: *

{@code
    * // ✓ Contains the right items in the right order
-   * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3", "Text 4"});
+   * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 1", "Text 3"});
    *
    * // ✖ Wrong order
    * assertThat(page.locator("ul > li")).containsText(new String[] {"Text 3", "Text 2"});
diff --git a/playwright/src/test/java/com/microsoft/playwright/TestScreencast.java b/playwright/src/test/java/com/microsoft/playwright/TestScreencast.java
index 7f816eade..94847f337 100644
--- a/playwright/src/test/java/com/microsoft/playwright/TestScreencast.java
+++ b/playwright/src/test/java/com/microsoft/playwright/TestScreencast.java
@@ -79,14 +79,8 @@ void saveAsShouldThrowWhenNoVideoFrames(@TempDir Path videosDir) {
       if (!popup.isClosed()) {
         popup.waitForClose(() -> {});
       }
-      // WebKit pauses renderer before win.close() and actually writes something.
-      if (isWebKit()) {
-        popup.video().saveAs(saveAsPath);
-        assertTrue(Files.exists(saveAsPath));
-      } else {
-        PlaywrightException e = assertThrows(PlaywrightException.class, () -> popup.video().saveAs(saveAsPath));
-        assertTrue(e.getMessage().contains("Page did not produce any video frames"), e.getMessage());
-      }
+      PlaywrightException e = assertThrows(PlaywrightException.class, () -> popup.video().saveAs(saveAsPath));
+      assertTrue(e.getMessage().contains("Page did not produce any video frames"), e.getMessage());
     }
   }
 
diff --git a/playwright/src/test/java/com/microsoft/playwright/TestWorkers.java b/playwright/src/test/java/com/microsoft/playwright/TestWorkers.java
index 379b7d116..36170d681 100644
--- a/playwright/src/test/java/com/microsoft/playwright/TestWorkers.java
+++ b/playwright/src/test/java/com/microsoft/playwright/TestWorkers.java
@@ -193,7 +193,9 @@ void shouldFormatNumberUsingContextLocale() {
     page.navigate(server.EMPTY_PAGE);
     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()"));
+    // https://github.com/microsoft/playwright/issues/38919
+    String expected = isFirefox() ? "10,000.2" : "10\u00A0000,2";
+    assertEquals(expected, worker.evaluate("() => (10000.20).toLocaleString()"));
     context.close();
   }
 
diff --git a/playwright/src/test/java/com/microsoft/playwright/Utils.java b/playwright/src/test/java/com/microsoft/playwright/Utils.java
index ad9f7d107..6ab8933a6 100644
--- a/playwright/src/test/java/com/microsoft/playwright/Utils.java
+++ b/playwright/src/test/java/com/microsoft/playwright/Utils.java
@@ -37,24 +37,12 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 public class Utils {
-  private static final AtomicInteger nextUnusedPort = new AtomicInteger(9000);
-
-  private static boolean available(int port) {
-    try (ServerSocket ignored = new ServerSocket(port)) {
-      return true;
-    } catch (IOException ignored) {
-      return false;
-    }
-  }
-
   public static int nextFreePort() {
-    for (int i = 0; i < 100; i++) {
-      int port = nextUnusedPort.getAndIncrement();
-      if (available(port)) {
-        return port;
-      }
+    try (ServerSocket socket = new ServerSocket(0)) {
+      return socket.getLocalPort();
+    } catch (IOException e) {
+      throw new RuntimeException("Cannot find free port", e);
     }
-    throw new RuntimeException("Cannot find free port: " + nextUnusedPort.get());
   }
 
   static void assertJsonEquals(Object expected, Object actual) {
diff --git a/scripts/DRIVER_VERSION b/scripts/DRIVER_VERSION
index 755b1365f..79f82f6b8 100644
--- a/scripts/DRIVER_VERSION
+++ b/scripts/DRIVER_VERSION
@@ -1 +1 @@
-1.57.0-beta-1764692940000
+1.58.0