From daf225a0b6137cf2c6c00d0540c5a46b51551846 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Thu, 14 Nov 2024 09:59:02 -0800 Subject: [PATCH 1/7] chore: roll 1.49-beta --- README.md | 6 +- .../com/microsoft/playwright/Browser.java | 60 ++++---- .../microsoft/playwright/BrowserContext.java | 7 +- .../com/microsoft/playwright/BrowserType.java | 16 ++- .../java/com/microsoft/playwright/Clock.java | 21 ++- .../microsoft/playwright/ConsoleMessage.java | 4 +- .../java/com/microsoft/playwright/Frame.java | 40 +++--- .../microsoft/playwright/FrameLocator.java | 40 +++--- .../com/microsoft/playwright/Keyboard.java | 9 +- .../com/microsoft/playwright/Locator.java | 71 +++++++--- .../java/com/microsoft/playwright/Page.java | 131 +++++++++--------- .../java/com/microsoft/playwright/Route.java | 12 +- .../com/microsoft/playwright/Tracing.java | 74 ++++++++++ .../microsoft/playwright/WebSocketRoute.java | 26 ++-- .../assertions/APIResponseAssertions.java | 8 +- .../assertions/LocatorAssertions.java | 30 +++- .../playwright/assertions/PageAssertions.java | 6 +- .../assertions/PlaywrightAssertions.java | 5 +- .../impl/LocatorAssertionsImpl.java | 9 ++ .../playwright/impl/LocatorImpl.java | 15 +- .../playwright/impl/TracingImpl.java | 19 +++ .../playwright/impl/WebSocketRouteImpl.java | 1 + .../playwright/options/FormData.java | 22 +-- .../playwright/options/Location.java | 35 +++++ .../playwright/TestPageAriaSnapshot.java | 53 +++++++ .../com/microsoft/playwright/TestTracing.java | 73 +++++++++- scripts/DRIVER_VERSION | 2 +- .../playwright/tools/ApiGenerator.java | 2 +- 28 files changed, 566 insertions(+), 231 deletions(-) create mode 100644 playwright/src/main/java/com/microsoft/playwright/options/Location.java create mode 100644 playwright/src/test/java/com/microsoft/playwright/TestPageAriaSnapshot.java diff --git a/README.md b/README.md index b5a64ce72..af58b7c91 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 130.0.6723.31 | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| WebKit 18.0 | ✅ | ✅ | ✅ | -| Firefox 131.0 | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Chromium 131.0.6778.33 | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| WebKit 18.2 | ✅ | ✅ | ✅ | +| Firefox 132.0 | :white_check_mark: | :white_check_mark: | :white_check_mark: | Headless execution is supported for all the browsers on all platforms. Check out [system requirements](https://playwright.dev/java/docs/intro#system-requirements) for details. diff --git a/playwright/src/main/java/com/microsoft/playwright/Browser.java b/playwright/src/main/java/com/microsoft/playwright/Browser.java index 34f58217b..2860249fd 100644 --- a/playwright/src/main/java/com/microsoft/playwright/Browser.java +++ b/playwright/src/main/java/com/microsoft/playwright/Browser.java @@ -29,15 +29,15 @@ * import com.microsoft.playwright.*; * * public class Example { - * public static void main(String[] args) { - * try (Playwright playwright = Playwright.create()) { - * BrowserType firefox = playwright.firefox() - * Browser browser = firefox.launch(); - * Page page = browser.newPage(); - * page.navigate('https://example.com'); - * browser.close(); - * } - * } + * public static void main(String[] args) { + * try (Playwright playwright = Playwright.create()) { + * BrowserType firefox = playwright.firefox(); + * Browser browser = firefox.launch(); + * Page page = browser.newPage(); + * page.navigate("https://example.com"); + * browser.close(); + * } + * } * } * } */ @@ -111,9 +111,11 @@ class NewContextOptions { */ public List clientCertificates; /** - * Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code - * "no-preference"}. See {@link com.microsoft.playwright.Page#emulateMedia Page.emulateMedia()} for more details. Passing - * {@code null} resets emulation to system defaults. Defaults to {@code "light"}. + * Emulates prefers-colors-scheme media + * feature, supported values are {@code "light"} and {@code "dark"}. See {@link com.microsoft.playwright.Page#emulateMedia + * Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to {@code + * "light"}. */ public Optional colorScheme; /** @@ -323,9 +325,11 @@ public NewContextOptions setClientCertificates(List clientCer return this; } /** - * Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code - * "no-preference"}. See {@link com.microsoft.playwright.Page#emulateMedia Page.emulateMedia()} for more details. Passing - * {@code null} resets emulation to system defaults. Defaults to {@code "light"}. + * Emulates prefers-colors-scheme media + * feature, supported values are {@code "light"} and {@code "dark"}. See {@link com.microsoft.playwright.Page#emulateMedia + * Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to {@code + * "light"}. */ public NewContextOptions setColorScheme(ColorScheme colorScheme) { this.colorScheme = Optional.ofNullable(colorScheme); @@ -660,9 +664,11 @@ class NewPageOptions { */ public List clientCertificates; /** - * Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code - * "no-preference"}. See {@link com.microsoft.playwright.Page#emulateMedia Page.emulateMedia()} for more details. Passing - * {@code null} resets emulation to system defaults. Defaults to {@code "light"}. + * Emulates prefers-colors-scheme media + * feature, supported values are {@code "light"} and {@code "dark"}. See {@link com.microsoft.playwright.Page#emulateMedia + * Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to {@code + * "light"}. */ public Optional colorScheme; /** @@ -872,9 +878,11 @@ public NewPageOptions setClientCertificates(List clientCertif return this; } /** - * Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code - * "no-preference"}. See {@link com.microsoft.playwright.Page#emulateMedia Page.emulateMedia()} for more details. Passing - * {@code null} resets emulation to system defaults. Defaults to {@code "light"}. + * Emulates prefers-colors-scheme media + * feature, supported values are {@code "light"} and {@code "dark"}. See {@link com.microsoft.playwright.Page#emulateMedia + * Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to {@code + * "light"}. */ public NewPageOptions setColorScheme(ColorScheme colorScheme) { this.colorScheme = Optional.ofNullable(colorScheme); @@ -1289,7 +1297,7 @@ default void close() { * BrowserContext context = browser.newContext(); * // Create a new page in a pristine context. * Page page = context.newPage(); - * page.navigate('https://example.com'); + * page.navigate("https://example.com"); * * // Graceful close up everything * context.close(); @@ -1316,7 +1324,7 @@ default BrowserContext newContext() { * BrowserContext context = browser.newContext(); * // Create a new page in a pristine context. * Page page = context.newPage(); - * page.navigate('https://example.com'); + * page.navigate("https://example.com"); * * // Graceful close up everything * context.close(); @@ -1364,7 +1372,7 @@ default Page newPage() { *
{@code
    * browser.startTracing(page, new Browser.StartTracingOptions()
    *   .setPath(Paths.get("trace.json")));
-   * page.goto('https://www.google.com');
+   * page.navigate("https://www.google.com");
    * browser.stopTracing();
    * }
* @@ -1388,7 +1396,7 @@ default void startTracing(Page page) { *
{@code
    * browser.startTracing(page, new Browser.StartTracingOptions()
    *   .setPath(Paths.get("trace.json")));
-   * page.goto('https://www.google.com');
+   * page.navigate("https://www.google.com");
    * browser.stopTracing();
    * }
* @@ -1411,7 +1419,7 @@ default void startTracing() { *
{@code
    * browser.startTracing(page, new Browser.StartTracingOptions()
    *   .setPath(Paths.get("trace.json")));
-   * page.goto('https://www.google.com');
+   * page.navigate("https://www.google.com");
    * browser.stopTracing();
    * }
* diff --git a/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java b/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java index 005345c66..b0e7c9c9b 100644 --- a/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java +++ b/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java @@ -701,7 +701,7 @@ default List cookies() { * public class Example { * public static void main(String[] args) { * try (Playwright playwright = Playwright.create()) { - * BrowserType webkit = playwright.webkit() + * BrowserType webkit = playwright.webkit(); * Browser browser = webkit.launch(new BrowserType.LaunchOptions().setHeadless(false)); * BrowserContext context = browser.newContext(); * context.exposeBinding("pageURL", (source, args) -> source.page().url()); @@ -748,7 +748,7 @@ default void exposeBinding(String name, BindingCallback callback) { * public class Example { * public static void main(String[] args) { * try (Playwright playwright = Playwright.create()) { - * BrowserType webkit = playwright.webkit() + * BrowserType webkit = playwright.webkit(); * Browser browser = webkit.launch(new BrowserType.LaunchOptions().setHeadless(false)); * BrowserContext context = browser.newContext(); * context.exposeBinding("pageURL", (source, args) -> source.page().url()); @@ -797,8 +797,9 @@ default void exposeBinding(String name, BindingCallback callback) { * public class Example { * public static void main(String[] args) { * try (Playwright playwright = Playwright.create()) { - * BrowserType webkit = playwright.webkit() + * BrowserType webkit = playwright.webkit(); * Browser browser = webkit.launch(new BrowserType.LaunchOptions().setHeadless(false)); + * BrowserContext context = browser.newContext(); * context.exposeFunction("sha256", args -> { * String text = (String) args[0]; * MessageDigest crypto; diff --git a/playwright/src/main/java/com/microsoft/playwright/BrowserType.java b/playwright/src/main/java/com/microsoft/playwright/BrowserType.java index 827d4868b..21df1b682 100644 --- a/playwright/src/main/java/com/microsoft/playwright/BrowserType.java +++ b/playwright/src/main/java/com/microsoft/playwright/BrowserType.java @@ -470,9 +470,11 @@ class LaunchPersistentContextOptions { */ public List clientCertificates; /** - * Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code - * "no-preference"}. See {@link com.microsoft.playwright.Page#emulateMedia Page.emulateMedia()} for more details. Passing - * {@code null} resets emulation to system defaults. Defaults to {@code "light"}. + * Emulates prefers-colors-scheme media + * feature, supported values are {@code "light"} and {@code "dark"}. See {@link com.microsoft.playwright.Page#emulateMedia + * Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to {@code + * "light"}. */ public Optional colorScheme; /** @@ -774,9 +776,11 @@ public LaunchPersistentContextOptions setClientCertificates(Listprefers-colors-scheme media + * feature, supported values are {@code "light"} and {@code "dark"}. See {@link com.microsoft.playwright.Page#emulateMedia + * Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to {@code + * "light"}. */ public LaunchPersistentContextOptions setColorScheme(ColorScheme colorScheme) { this.colorScheme = Optional.ofNullable(colorScheme); diff --git a/playwright/src/main/java/com/microsoft/playwright/Clock.java b/playwright/src/main/java/com/microsoft/playwright/Clock.java index 4cd6e4549..52c64d34e 100644 --- a/playwright/src/main/java/com/microsoft/playwright/Clock.java +++ b/playwright/src/main/java/com/microsoft/playwright/Clock.java @@ -227,6 +227,10 @@ default void install() { /** * Makes {@code Date.now} and {@code new Date()} return fixed fake time at all times, keeps all the timers running. * + *

Use this method for simple scenarios where you only need to test with a predefined time. For more advanced scenarios, + * use {@link com.microsoft.playwright.Clock#install Clock.install()} instead. Read docs on clock emulation to learn more. + * *

Usage *

{@code
    * page.clock().setFixedTime(new Date());
@@ -241,6 +245,10 @@ default void install() {
   /**
    * Makes {@code Date.now} and {@code new Date()} return fixed fake time at all times, keeps all the timers running.
    *
+   * 

Use this method for simple scenarios where you only need to test with a predefined time. For more advanced scenarios, + * use {@link com.microsoft.playwright.Clock#install Clock.install()} instead. Read docs on clock emulation to learn more. + * *

Usage *

{@code
    * page.clock().setFixedTime(new Date());
@@ -255,6 +263,10 @@ default void install() {
   /**
    * Makes {@code Date.now} and {@code new Date()} return fixed fake time at all times, keeps all the timers running.
    *
+   * 

Use this method for simple scenarios where you only need to test with a predefined time. For more advanced scenarios, + * use {@link com.microsoft.playwright.Clock#install Clock.install()} instead. Read docs on clock emulation to learn more. + * *

Usage *

{@code
    * page.clock().setFixedTime(new Date());
@@ -267,7 +279,8 @@ default void install() {
    */
   void setFixedTime(Date time);
   /**
-   * Sets current system time but does not trigger any timers.
+   * Sets system time, but does not trigger any timers. Use this to test how the web page reacts to a time shift, for example
+   * switching from summer to winter time, or changing time zones.
    *
    * 

Usage *

{@code
@@ -281,7 +294,8 @@ default void install() {
    */
   void setSystemTime(long time);
   /**
-   * Sets current system time but does not trigger any timers.
+   * Sets system time, but does not trigger any timers. Use this to test how the web page reacts to a time shift, for example
+   * switching from summer to winter time, or changing time zones.
    *
    * 

Usage *

{@code
@@ -295,7 +309,8 @@ default void install() {
    */
   void setSystemTime(String time);
   /**
-   * Sets current system time but does not trigger any timers.
+   * Sets system time, but does not trigger any timers. Use this to test how the web page reacts to a time shift, for example
+   * switching from summer to winter time, or changing time zones.
    *
    * 

Usage *

{@code
diff --git a/playwright/src/main/java/com/microsoft/playwright/ConsoleMessage.java b/playwright/src/main/java/com/microsoft/playwright/ConsoleMessage.java
index 4d1aea69d..663092f3c 100644
--- a/playwright/src/main/java/com/microsoft/playwright/ConsoleMessage.java
+++ b/playwright/src/main/java/com/microsoft/playwright/ConsoleMessage.java
@@ -39,8 +39,8 @@
  * });
  *
  * // Deconstruct console.log arguments
- * msg.args().get(0).jsonValue() // hello
- * msg.args().get(1).jsonValue() // 42
+ * msg.args().get(0).jsonValue(); // hello
+ * msg.args().get(1).jsonValue(); // 42
  * }
*/ public interface ConsoleMessage { diff --git a/playwright/src/main/java/com/microsoft/playwright/Frame.java b/playwright/src/main/java/com/microsoft/playwright/Frame.java index d732b8292..4e6b35c2b 100644 --- a/playwright/src/main/java/com/microsoft/playwright/Frame.java +++ b/playwright/src/main/java/com/microsoft/playwright/Frame.java @@ -3499,19 +3499,19 @@ default Locator getByRole(AriaRole role) { *

You can locate by text substring, exact string, or a regular expression: *

{@code
    * // Matches 
-   * page.getByText("world")
+   * page.getByText("world");
    *
    * // Matches first 
- * page.getByText("Hello world") + * page.getByText("Hello world"); * * // Matches second
- * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)) + * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)); * * // Matches both
s - * page.getByText(Pattern.compile("Hello")) + * page.getByText(Pattern.compile("Hello")); * * // Matches second
- * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)) + * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)); * }
* *

Details @@ -3541,19 +3541,19 @@ default Locator getByText(String text) { *

You can locate by text substring, exact string, or a regular expression: *

{@code
    * // Matches 
-   * page.getByText("world")
+   * page.getByText("world");
    *
    * // Matches first 
- * page.getByText("Hello world") + * page.getByText("Hello world"); * * // Matches second
- * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)) + * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)); * * // Matches both
s - * page.getByText(Pattern.compile("Hello")) + * page.getByText(Pattern.compile("Hello")); * * // Matches second
- * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)) + * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)); * }
* *

Details @@ -3581,19 +3581,19 @@ default Locator getByText(String text) { *

You can locate by text substring, exact string, or a regular expression: *

{@code
    * // Matches 
-   * page.getByText("world")
+   * page.getByText("world");
    *
    * // Matches first 
- * page.getByText("Hello world") + * page.getByText("Hello world"); * * // Matches second
- * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)) + * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)); * * // Matches both
s - * page.getByText(Pattern.compile("Hello")) + * page.getByText(Pattern.compile("Hello")); * * // Matches second
- * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)) + * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)); * }
* *

Details @@ -3623,19 +3623,19 @@ default Locator getByText(Pattern text) { *

You can locate by text substring, exact string, or a regular expression: *

{@code
    * // Matches 
-   * page.getByText("world")
+   * page.getByText("world");
    *
    * // Matches first 
- * page.getByText("Hello world") + * page.getByText("Hello world"); * * // Matches second
- * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)) + * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)); * * // Matches both
s - * page.getByText(Pattern.compile("Hello")) + * page.getByText(Pattern.compile("Hello")); * * // Matches second
- * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)) + * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)); * }
* *

Details diff --git a/playwright/src/main/java/com/microsoft/playwright/FrameLocator.java b/playwright/src/main/java/com/microsoft/playwright/FrameLocator.java index 0fe625a3b..007460217 100644 --- a/playwright/src/main/java/com/microsoft/playwright/FrameLocator.java +++ b/playwright/src/main/java/com/microsoft/playwright/FrameLocator.java @@ -734,19 +734,19 @@ default Locator getByRole(AriaRole role) { *

You can locate by text substring, exact string, or a regular expression: *

{@code
    * // Matches 
-   * page.getByText("world")
+   * page.getByText("world");
    *
    * // Matches first 
- * page.getByText("Hello world") + * page.getByText("Hello world"); * * // Matches second
- * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)) + * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)); * * // Matches both
s - * page.getByText(Pattern.compile("Hello")) + * page.getByText(Pattern.compile("Hello")); * * // Matches second
- * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)) + * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)); * }
* *

Details @@ -776,19 +776,19 @@ default Locator getByText(String text) { *

You can locate by text substring, exact string, or a regular expression: *

{@code
    * // Matches 
-   * page.getByText("world")
+   * page.getByText("world");
    *
    * // Matches first 
- * page.getByText("Hello world") + * page.getByText("Hello world"); * * // Matches second
- * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)) + * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)); * * // Matches both
s - * page.getByText(Pattern.compile("Hello")) + * page.getByText(Pattern.compile("Hello")); * * // Matches second
- * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)) + * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)); * }
* *

Details @@ -816,19 +816,19 @@ default Locator getByText(String text) { *

You can locate by text substring, exact string, or a regular expression: *

{@code
    * // Matches 
-   * page.getByText("world")
+   * page.getByText("world");
    *
    * // Matches first 
- * page.getByText("Hello world") + * page.getByText("Hello world"); * * // Matches second
- * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)) + * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)); * * // Matches both
s - * page.getByText(Pattern.compile("Hello")) + * page.getByText(Pattern.compile("Hello")); * * // Matches second
- * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)) + * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)); * }
* *

Details @@ -858,19 +858,19 @@ default Locator getByText(Pattern text) { *

You can locate by text substring, exact string, or a regular expression: *

{@code
    * // Matches 
-   * page.getByText("world")
+   * page.getByText("world");
    *
    * // Matches first 
- * page.getByText("Hello world") + * page.getByText("Hello world"); * * // Matches second
- * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)) + * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)); * * // Matches both
s - * page.getByText(Pattern.compile("Hello")) + * page.getByText(Pattern.compile("Hello")); * * // Matches second
- * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)) + * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)); * }
* *

Details diff --git a/playwright/src/main/java/com/microsoft/playwright/Keyboard.java b/playwright/src/main/java/com/microsoft/playwright/Keyboard.java index 56cea1755..6ef8c0b5e 100644 --- a/playwright/src/main/java/com/microsoft/playwright/Keyboard.java +++ b/playwright/src/main/java/com/microsoft/playwright/Keyboard.java @@ -48,10 +48,7 @@ * *

An example to trigger select-all with the keyboard *

{@code
- * // on Windows and Linux
- * page.keyboard().press("Control+A");
- * // on macOS
- * page.keyboard().press("Meta+A");
+ * page.keyboard().press("ControlOrMeta+A");
  * }
*/ public interface Keyboard { @@ -164,7 +161,7 @@ public TypeOptions setDelay(double delay) { * Page page = browser.newPage(); * page.navigate("https://keycode.info"); * page.keyboard().press("A"); - * page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("A.png")); + * page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("A.png"))); * page.keyboard().press("ArrowLeft"); * page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("ArrowLeft.png"))); * page.keyboard().press("Shift+O"); @@ -211,7 +208,7 @@ default void press(String key) { * Page page = browser.newPage(); * page.navigate("https://keycode.info"); * page.keyboard().press("A"); - * page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("A.png")); + * page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("A.png"))); * page.keyboard().press("ArrowLeft"); * page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("ArrowLeft.png"))); * page.keyboard().press("Shift+O"); diff --git a/playwright/src/main/java/com/microsoft/playwright/Locator.java b/playwright/src/main/java/com/microsoft/playwright/Locator.java index 99161071e..3bc2b70a3 100644 --- a/playwright/src/main/java/com/microsoft/playwright/Locator.java +++ b/playwright/src/main/java/com/microsoft/playwright/Locator.java @@ -2151,7 +2151,7 @@ public WaitForOptions setTimeout(double timeout) { * *

Usage *

{@code
-   * for (Locator li : page.getByRole('listitem').all())
+   * for (Locator li : page.getByRole("listitem").all())
    *   li.click();
    * }
* @@ -2202,6 +2202,35 @@ public WaitForOptions setTimeout(double timeout) { * @since v1.34 */ Locator and(Locator locator); + /** + * Captures the aria snapshot of the given element. Read more about aria snapshots and {@link + * com.microsoft.playwright.assertions.LocatorAssertions#matchesAriaSnapshot LocatorAssertions.matchesAriaSnapshot()} for + * the corresponding assertion. + * + *

Usage + *

{@code
+   * page.getByRole(AriaRole.LINK).ariaSnapshot();
+   * }
+ * + *

Details + * + *

This method captures the aria snapshot of the given element. The snapshot is a string that represents the state of the + * element and its children. The snapshot can be used to assert the state of the element in the test, or to compare it to + * state in the future. + * + *

The ARIA snapshot is represented using YAML markup language: + *

    + *
  • The keys of the objects are the roles and optional accessible names of the elements.
  • + *
  • The values are either text content or an array of child elements.
  • + *
  • Generic static text can be represented with the {@code text} key.
  • + *
+ * + *

Below is the HTML markup and the respective ARIA snapshot: + * + * @since v1.49 + */ + String ariaSnapshot(); /** * Calls blur on the element. * @@ -3455,19 +3484,19 @@ default Locator getByRole(AriaRole role) { *

You can locate by text substring, exact string, or a regular expression: *

{@code
    * // Matches 
-   * page.getByText("world")
+   * page.getByText("world");
    *
    * // Matches first 
- * page.getByText("Hello world") + * page.getByText("Hello world"); * * // Matches second
- * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)) + * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)); * * // Matches both
s - * page.getByText(Pattern.compile("Hello")) + * page.getByText(Pattern.compile("Hello")); * * // Matches second
- * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)) + * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)); * }
* *

Details @@ -3497,19 +3526,19 @@ default Locator getByText(String text) { *

You can locate by text substring, exact string, or a regular expression: *

{@code
    * // Matches 
-   * page.getByText("world")
+   * page.getByText("world");
    *
    * // Matches first 
- * page.getByText("Hello world") + * page.getByText("Hello world"); * * // Matches second
- * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)) + * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)); * * // Matches both
s - * page.getByText(Pattern.compile("Hello")) + * page.getByText(Pattern.compile("Hello")); * * // Matches second
- * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)) + * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)); * }
* *

Details @@ -3537,19 +3566,19 @@ default Locator getByText(String text) { *

You can locate by text substring, exact string, or a regular expression: *

{@code
    * // Matches 
-   * page.getByText("world")
+   * page.getByText("world");
    *
    * // Matches first 
- * page.getByText("Hello world") + * page.getByText("Hello world"); * * // Matches second
- * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)) + * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)); * * // Matches both
s - * page.getByText(Pattern.compile("Hello")) + * page.getByText(Pattern.compile("Hello")); * * // Matches second
- * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)) + * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)); * }
* *

Details @@ -3579,19 +3608,19 @@ default Locator getByText(Pattern text) { *

You can locate by text substring, exact string, or a regular expression: *

{@code
    * // Matches 
-   * page.getByText("world")
+   * page.getByText("world");
    *
    * // Matches first 
- * page.getByText("Hello world") + * page.getByText("Hello world"); * * // Matches second
- * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)) + * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)); * * // Matches both
s - * page.getByText(Pattern.compile("Hello")) + * page.getByText(Pattern.compile("Hello")); * * // Matches second
- * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)) + * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)); * }
* *

Details diff --git a/playwright/src/main/java/com/microsoft/playwright/Page.java b/playwright/src/main/java/com/microsoft/playwright/Page.java index 14e788a4d..8901b5928 100644 --- a/playwright/src/main/java/com/microsoft/playwright/Page.java +++ b/playwright/src/main/java/com/microsoft/playwright/Page.java @@ -959,8 +959,10 @@ public DragAndDropOptions setTrial(boolean trial) { } class EmulateMediaOptions { /** - * Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code - * "no-preference"}. Passing {@code null} disables color scheme emulation. + * Emulates prefers-colors-scheme media + * feature, supported values are {@code "light"} and {@code "dark"}. Passing {@code null} disables color scheme emulation. + * {@code "no-preference"} is deprecated. */ public Optional colorScheme; /** @@ -980,8 +982,10 @@ class EmulateMediaOptions { public Optional reducedMotion; /** - * Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code - * "no-preference"}. Passing {@code null} disables color scheme emulation. + * Emulates prefers-colors-scheme media + * feature, supported values are {@code "light"} and {@code "dark"}. Passing {@code null} disables color scheme emulation. + * {@code "no-preference"} is deprecated. */ public EmulateMediaOptions setColorScheme(ColorScheme colorScheme) { this.colorScheme = Optional.ofNullable(colorScheme); @@ -4151,9 +4155,9 @@ default void dispatchEvent(String selector, String type) { * *

Usage *

{@code
-   * page.dragAndDrop("#source", '#target');
+   * page.dragAndDrop("#source", "#target");
    * // or specify exact positions relative to the top-left corners of the elements:
-   * page.dragAndDrop("#source", '#target', new Page.DragAndDropOptions()
+   * page.dragAndDrop("#source", "#target", new Page.DragAndDropOptions()
    *   .setSourcePosition(34, 7).setTargetPosition(10, 20));
    * }
* @@ -4172,9 +4176,9 @@ default void dragAndDrop(String source, String target) { * *

Usage *

{@code
-   * page.dragAndDrop("#source", '#target');
+   * page.dragAndDrop("#source", "#target");
    * // or specify exact positions relative to the top-left corners of the elements:
-   * page.dragAndDrop("#source", '#target', new Page.DragAndDropOptions()
+   * page.dragAndDrop("#source", "#target", new Page.DragAndDropOptions()
    *   .setSourcePosition(34, 7).setTargetPosition(10, 20));
    * }
* @@ -4214,8 +4218,6 @@ default void dragAndDrop(String source, String target) { * // → true * page.evaluate("() => matchMedia('(prefers-color-scheme: light)').matches"); * // → false - * page.evaluate("() => matchMedia('(prefers-color-scheme: no-preference)').matches"); - * // → false * }
* * @since v1.8 @@ -4252,8 +4254,6 @@ default void emulateMedia() { * // → true * page.evaluate("() => matchMedia('(prefers-color-scheme: light)').matches"); * // → false - * page.evaluate("() => matchMedia('(prefers-color-scheme: no-preference)').matches"); - * // → false * }
* * @since v1.8 @@ -4560,7 +4560,7 @@ default JSHandle evaluateHandle(String expression) { * public static void main(String[] args) { * try (Playwright playwright = Playwright.create()) { * BrowserType webkit = playwright.webkit(); - * Browser browser = webkit.launch({ headless: false }); + * Browser browser = webkit.launch(new BrowserType.LaunchOptions().setHeadless(false)); * BrowserContext context = browser.newContext(); * Page page = context.newPage(); * page.exposeBinding("pageURL", (source, args) -> source.page().url()); @@ -4610,7 +4610,7 @@ default void exposeBinding(String name, BindingCallback callback) { * public static void main(String[] args) { * try (Playwright playwright = Playwright.create()) { * BrowserType webkit = playwright.webkit(); - * Browser browser = webkit.launch({ headless: false }); + * Browser browser = webkit.launch(new BrowserType.LaunchOptions().setHeadless(false)); * BrowserContext context = browser.newContext(); * Page page = context.newPage(); * page.exposeBinding("pageURL", (source, args) -> source.page().url()); @@ -4662,26 +4662,27 @@ default void exposeBinding(String name, BindingCallback callback) { * public static void main(String[] args) { * try (Playwright playwright = Playwright.create()) { * BrowserType webkit = playwright.webkit(); - * Browser browser = webkit.launch({ headless: false }); + * Browser browser = webkit.launch(new BrowserType.LaunchOptions().setHeadless(false)); * Page page = browser.newPage(); * page.exposeFunction("sha256", args -> { - * String text = (String) args[0]; - * MessageDigest crypto; * try { - * crypto = MessageDigest.getInstance("SHA-256"); + * String text = (String) args[0]; + * MessageDigest crypto = MessageDigest.getInstance("SHA-256"); + * byte[] token = crypto.digest(text.getBytes(StandardCharsets.UTF_8)); + * return Base64.getEncoder().encodeToString(token); * } catch (NoSuchAlgorithmException e) { * return null; * } - * byte[] token = crypto.digest(text.getBytes(StandardCharsets.UTF_8)); - * return Base64.getEncoder().encodeToString(token); * }); - * page.setContent("\n" + * "\n" + - * "
\n"); + * "
" + * ); * page.click("button"); * } * } @@ -4757,7 +4758,7 @@ default void focus(String selector) { * Frame frame = page.frame("frame-name"); * }
*
{@code
-   * Frame frame = page.frameByUrl(Pattern.compile(".*domain.*");
+   * Frame frame = page.frameByUrl(Pattern.compile(".*domain.*"));
    * }
* * @param name Frame name specified in the {@code iframe}'s {@code name} attribute. @@ -5163,19 +5164,19 @@ default Locator getByRole(AriaRole role) { *

You can locate by text substring, exact string, or a regular expression: *

{@code
    * // Matches 
-   * page.getByText("world")
+   * page.getByText("world");
    *
    * // Matches first 
- * page.getByText("Hello world") + * page.getByText("Hello world"); * * // Matches second
- * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)) + * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)); * * // Matches both
s - * page.getByText(Pattern.compile("Hello")) + * page.getByText(Pattern.compile("Hello")); * * // Matches second
- * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)) + * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)); * }
* *

Details @@ -5205,19 +5206,19 @@ default Locator getByText(String text) { *

You can locate by text substring, exact string, or a regular expression: *

{@code
    * // Matches 
-   * page.getByText("world")
+   * page.getByText("world");
    *
    * // Matches first 
- * page.getByText("Hello world") + * page.getByText("Hello world"); * * // Matches second
- * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)) + * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)); * * // Matches both
s - * page.getByText(Pattern.compile("Hello")) + * page.getByText(Pattern.compile("Hello")); * * // Matches second
- * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)) + * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)); * }
* *

Details @@ -5245,19 +5246,19 @@ default Locator getByText(String text) { *

You can locate by text substring, exact string, or a regular expression: *

{@code
    * // Matches 
-   * page.getByText("world")
+   * page.getByText("world");
    *
    * // Matches first 
- * page.getByText("Hello world") + * page.getByText("Hello world"); * * // Matches second
- * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)) + * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)); * * // Matches both
s - * page.getByText(Pattern.compile("Hello")) + * page.getByText(Pattern.compile("Hello")); * * // Matches second
- * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)) + * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)); * }
* *

Details @@ -5287,19 +5288,19 @@ default Locator getByText(Pattern text) { *

You can locate by text substring, exact string, or a regular expression: *

{@code
    * // Matches 
-   * page.getByText("world")
+   * page.getByText("world");
    *
    * // Matches first 
- * page.getByText("Hello world") + * page.getByText("Hello world"); * * // Matches second
- * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)) + * page.getByText("Hello", new Page.GetByTextOptions().setExact(true)); * * // Matches both
s - * page.getByText(Pattern.compile("Hello")) + * page.getByText(Pattern.compile("Hello")); * * // Matches second
- * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)) + * page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE)); * }
* *

Details @@ -6080,24 +6081,24 @@ default ElementHandle querySelector(String selector) { *

An example that closes a "Sign up to the newsletter" dialog when it appears: *

{@code
    * // Setup the handler.
-   * page.addLocatorHandler(page.getByText("Sign up to the newsletter"), () => {
+   * page.addLocatorHandler(page.getByText("Sign up to the newsletter"), () -> {
    *   page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("No thanks")).click();
    * });
    *
    * // Write the test as usual.
-   * page.goto("https://example.com");
+   * page.navigate("https://example.com");
    * page.getByRole("button", Page.GetByRoleOptions().setName("Start here")).click();
    * }
* *

An example that skips the "Confirm your security details" page when it is shown: *

{@code
    * // Setup the handler.
-   * page.addLocatorHandler(page.getByText("Confirm your security details")), () => {
+   * page.addLocatorHandler(page.getByText("Confirm your security details"), () -> {
    *   page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Remind me later")).click();
    * });
    *
    * // Write the test as usual.
-   * page.goto("https://example.com");
+   * page.navigate("https://example.com");
    * page.getByRole("button", Page.GetByRoleOptions().setName("Start here")).click();
    * }
* @@ -6106,19 +6107,19 @@ default ElementHandle querySelector(String selector) { * handler does not hide the {@code } element. *
{@code
    * // Setup the handler.
-   * page.addLocatorHandler(page.locator("body")), () => {
+   * page.addLocatorHandler(page.locator("body"), () -> {
    *   page.evaluate("window.removeObstructionsForTestIfNeeded()");
-   * }, new Page.AddLocatorHandlerOptions.setNoWaitAfter(true));
+   * }, new Page.AddLocatorHandlerOptions().setNoWaitAfter(true));
    *
    * // Write the test as usual.
-   * page.goto("https://example.com");
+   * page.navigate("https://example.com");
    * page.getByRole("button", Page.GetByRoleOptions().setName("Start here")).click();
    * }
* *

Handler takes the original locator as an argument. You can also automatically remove the handler after a number of * invocations by setting {@code times}: *

{@code
-   * page.addLocatorHandler(page.getByLabel("Close"), locator => {
+   * page.addLocatorHandler(page.getByLabel("Close"), locator -> {
    *   locator.click();
    * }, new Page.AddLocatorHandlerOptions().setTimes(1));
    * }
@@ -6172,24 +6173,24 @@ default void addLocatorHandler(Locator locator, Consumer handler) { *

An example that closes a "Sign up to the newsletter" dialog when it appears: *

{@code
    * // Setup the handler.
-   * page.addLocatorHandler(page.getByText("Sign up to the newsletter"), () => {
+   * page.addLocatorHandler(page.getByText("Sign up to the newsletter"), () -> {
    *   page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("No thanks")).click();
    * });
    *
    * // Write the test as usual.
-   * page.goto("https://example.com");
+   * page.navigate("https://example.com");
    * page.getByRole("button", Page.GetByRoleOptions().setName("Start here")).click();
    * }
* *

An example that skips the "Confirm your security details" page when it is shown: *

{@code
    * // Setup the handler.
-   * page.addLocatorHandler(page.getByText("Confirm your security details")), () => {
+   * page.addLocatorHandler(page.getByText("Confirm your security details"), () -> {
    *   page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Remind me later")).click();
    * });
    *
    * // Write the test as usual.
-   * page.goto("https://example.com");
+   * page.navigate("https://example.com");
    * page.getByRole("button", Page.GetByRoleOptions().setName("Start here")).click();
    * }
* @@ -6198,19 +6199,19 @@ default void addLocatorHandler(Locator locator, Consumer handler) { * handler does not hide the {@code } element. *
{@code
    * // Setup the handler.
-   * page.addLocatorHandler(page.locator("body")), () => {
+   * page.addLocatorHandler(page.locator("body"), () -> {
    *   page.evaluate("window.removeObstructionsForTestIfNeeded()");
-   * }, new Page.AddLocatorHandlerOptions.setNoWaitAfter(true));
+   * }, new Page.AddLocatorHandlerOptions().setNoWaitAfter(true));
    *
    * // Write the test as usual.
-   * page.goto("https://example.com");
+   * page.navigate("https://example.com");
    * page.getByRole("button", Page.GetByRoleOptions().setName("Start here")).click();
    * }
* *

Handler takes the original locator as an argument. You can also automatically remove the handler after a number of * invocations by setting {@code times}: *

{@code
-   * page.addLocatorHandler(page.getByLabel("Close"), locator => {
+   * page.addLocatorHandler(page.getByLabel("Close"), locator -> {
    *   locator.click();
    * }, new Page.AddLocatorHandlerOptions().setTimes(1));
    * }
@@ -6641,8 +6642,8 @@ default void routeFromHAR(Path har) { * examples. *
{@code
    * page.routeWebSocket("/ws", ws -> {
-   *   ws.onMessage(message -> {
-   *     if ("request".equals(message))
+   *   ws.onMessage(frame -> {
+   *     if ("request".equals(frame.text()))
    *       ws.send("response");
    *   });
    * });
@@ -6666,8 +6667,8 @@ default void routeFromHAR(Path har) {
    * examples.
    * 
{@code
    * page.routeWebSocket("/ws", ws -> {
-   *   ws.onMessage(message -> {
-   *     if ("request".equals(message))
+   *   ws.onMessage(frame -> {
+   *     if ("request".equals(frame.text()))
    *       ws.send("response");
    *   });
    * });
@@ -6691,8 +6692,8 @@ default void routeFromHAR(Path har) {
    * examples.
    * 
{@code
    * page.routeWebSocket("/ws", ws -> {
-   *   ws.onMessage(message -> {
-   *     if ("request".equals(message))
+   *   ws.onMessage(frame -> {
+   *     if ("request".equals(frame.text()))
    *       ws.send("response");
    *   });
    * });
diff --git a/playwright/src/main/java/com/microsoft/playwright/Route.java b/playwright/src/main/java/com/microsoft/playwright/Route.java
index abb432042..ae05c816c 100644
--- a/playwright/src/main/java/com/microsoft/playwright/Route.java
+++ b/playwright/src/main/java/com/microsoft/playwright/Route.java
@@ -363,10 +363,8 @@ default void abort() {
    *
    * 

Details * - *

Note that any overrides such as {@code url} or {@code headers} only apply to the request being routed. If this request - * results in a redirect, overrides will not be applied to the new redirected request. If you want to propagate a header - * through redirects, use the combination of {@link com.microsoft.playwright.Route#fetch Route.fetch()} and {@link - * com.microsoft.playwright.Route#fulfill Route.fulfill()} instead. + *

The {@code headers} option applies to both the routed request and any redirects it initiates. However, {@code url}, + * {@code method}, and {@code postData} only apply to the original request and are not carried over to redirected requests. * *

{@link com.microsoft.playwright.Route#resume Route.resume()} will immediately send the request to the network, other * matching handlers won't be invoked. Use {@link com.microsoft.playwright.Route#fallback Route.fallback()} If you want @@ -393,10 +391,8 @@ default void resume() { * *

Details * - *

Note that any overrides such as {@code url} or {@code headers} only apply to the request being routed. If this request - * results in a redirect, overrides will not be applied to the new redirected request. If you want to propagate a header - * through redirects, use the combination of {@link com.microsoft.playwright.Route#fetch Route.fetch()} and {@link - * com.microsoft.playwright.Route#fulfill Route.fulfill()} instead. + *

The {@code headers} option applies to both the routed request and any redirects it initiates. However, {@code url}, + * {@code method}, and {@code postData} only apply to the original request and are not carried over to redirected requests. * *

{@link com.microsoft.playwright.Route#resume Route.resume()} will immediately send the request to the network, other * matching handlers won't be invoked. Use {@link com.microsoft.playwright.Route#fallback Route.fallback()} If you want diff --git a/playwright/src/main/java/com/microsoft/playwright/Tracing.java b/playwright/src/main/java/com/microsoft/playwright/Tracing.java index 82ea8d492..160b4d3f9 100644 --- a/playwright/src/main/java/com/microsoft/playwright/Tracing.java +++ b/playwright/src/main/java/com/microsoft/playwright/Tracing.java @@ -16,6 +16,7 @@ package com.microsoft.playwright; +import com.microsoft.playwright.options.*; import java.nio.file.Path; /** @@ -143,6 +144,29 @@ public StartChunkOptions setTitle(String title) { return this; } } + class GroupOptions { + /** + * Specifies a custom location for the group to be shown in the trace viewer. Defaults to the location of the {@link + * com.microsoft.playwright.Tracing#group Tracing.group()} call. + */ + public Location location; + + /** + * Specifies a custom location for the group to be shown in the trace viewer. Defaults to the location of the {@link + * com.microsoft.playwright.Tracing#group Tracing.group()} call. + */ + public GroupOptions setLocation(String file) { + return setLocation(new Location(file)); + } + /** + * Specifies a custom location for the group to be shown in the trace viewer. Defaults to the location of the {@link + * com.microsoft.playwright.Tracing#group Tracing.group()} call. + */ + public GroupOptions setLocation(Location location) { + this.location = location; + return this; + } + } class StopOptions { /** * Export trace into the file with the given path. @@ -271,6 +295,56 @@ default void startChunk() { * @since v1.15 */ void startChunk(StartChunkOptions options); + /** + * NOTE: Use {@code test.step} instead when available. + * + *

Creates a new group within the trace, assigning any subsequent API calls to this group, until {@link + * com.microsoft.playwright.Tracing#groupEnd Tracing.groupEnd()} is called. Groups can be nested and will be visible in the + * trace viewer. + * + *

Usage + *

{@code
+   * // All actions between group and groupEnd
+   * // will be shown in the trace viewer as a group.
+   * page.context().tracing.group("Open Playwright.dev > API");
+   * page.navigate("https://playwright.dev/");
+   * page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("API")).click();
+   * page.context().tracing.groupEnd();
+   * }
+ * + * @param name Group name shown in the trace viewer. + * @since v1.49 + */ + default void group(String name) { + group(name, null); + } + /** + * NOTE: Use {@code test.step} instead when available. + * + *

Creates a new group within the trace, assigning any subsequent API calls to this group, until {@link + * com.microsoft.playwright.Tracing#groupEnd Tracing.groupEnd()} is called. Groups can be nested and will be visible in the + * trace viewer. + * + *

Usage + *

{@code
+   * // All actions between group and groupEnd
+   * // will be shown in the trace viewer as a group.
+   * page.context().tracing.group("Open Playwright.dev > API");
+   * page.navigate("https://playwright.dev/");
+   * page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("API")).click();
+   * page.context().tracing.groupEnd();
+   * }
+ * + * @param name Group name shown in the trace viewer. + * @since v1.49 + */ + void group(String name, GroupOptions options); + /** + * Closes the last group created by {@link com.microsoft.playwright.Tracing#group Tracing.group()}. + * + * @since v1.49 + */ + void groupEnd(); /** * Stop tracing. * diff --git a/playwright/src/main/java/com/microsoft/playwright/WebSocketRoute.java b/playwright/src/main/java/com/microsoft/playwright/WebSocketRoute.java index fe662582a..e20fe41a0 100644 --- a/playwright/src/main/java/com/microsoft/playwright/WebSocketRoute.java +++ b/playwright/src/main/java/com/microsoft/playwright/WebSocketRoute.java @@ -31,8 +31,8 @@ * WebSocket. Here is an example that responds to a {@code "request"} with a {@code "response"}. *
{@code
  * page.routeWebSocket("wss://example.com/ws", ws -> {
- *   ws.onMessage(message -> {
- *     if ("request".equals(message))
+ *   ws.onMessage(frame -> {
+ *     if ("request".equals(frame.text()))
  *       ws.send("response");
  *   });
  * });
@@ -45,8 +45,8 @@
  * 

Here is another example that handles JSON messages: *

{@code
  * page.routeWebSocket("wss://example.com/ws", ws -> {
- *   ws.onMessage(message -> {
- *     JsonObject json = new JsonParser().parse(message).getAsJsonObject();
+ *   ws.onMessage(frame -> {
+ *     JsonObject json = new JsonParser().parse(frame.text()).getAsJsonObject();
  *     if ("question".equals(json.get("request").getAsString())) {
  *       Map result = new HashMap();
  *       result.put("response", "answer");
@@ -67,11 +67,11 @@
  * 
{@code
  * page.routeWebSocket("/ws", ws -> {
  *   WebSocketRoute server = ws.connectToServer();
- *   ws.onMessage(message -> {
- *     if ("request".equals(message))
+ *   ws.onMessage(frame -> {
+ *     if ("request".equals(frame.text()))
  *       server.send("request2");
  *     else
- *       server.send(message);
+ *       server.send(frame.text());
  *   });
  * });
  * }
@@ -92,13 +92,13 @@ *
{@code
  * page.routeWebSocket("/ws", ws -> {
  *   WebSocketRoute server = ws.connectToServer();
- *   ws.onMessage(message -> {
- *     if (!"blocked-from-the-page".equals(message))
- *       server.send(message);
+ *   ws.onMessage(frame -> {
+ *     if (!"blocked-from-the-page".equals(frame.text()))
+ *       server.send(frame.text());
  *   });
- *   server.onMessage(message -> {
- *     if (!"blocked-from-the-server".equals(message))
- *       ws.send(message);
+ *   server.onMessage(frame -> {
+ *     if (!"blocked-from-the-server".equals(frame.text()))
+ *       ws.send(frame.text());
  *   });
  * });
  * }
diff --git a/playwright/src/main/java/com/microsoft/playwright/assertions/APIResponseAssertions.java b/playwright/src/main/java/com/microsoft/playwright/assertions/APIResponseAssertions.java index 4e12a68e5..70cfd8e02 100644 --- a/playwright/src/main/java/com/microsoft/playwright/assertions/APIResponseAssertions.java +++ b/playwright/src/main/java/com/microsoft/playwright/assertions/APIResponseAssertions.java @@ -21,15 +21,15 @@ * The {@code APIResponseAssertions} class provides assertion methods that can be used to make assertions about the {@code * APIResponse} in the tests. *
{@code
- * ...
+ * // ...
  * import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
  *
  * public class TestPage {
- *   ...
+ *   // ...
  *   @Test
  *   void navigatesToLoginPage() {
- *     ...
- *     APIResponse response = page.request().get('https://playwright.dev');
+ *     // ...
+ *     APIResponse response = page.request().get("https://playwright.dev");
  *     assertThat(response).isOK();
  *   }
  * }
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 e2a81d475..cb3a0e0a9 100644
--- a/playwright/src/main/java/com/microsoft/playwright/assertions/LocatorAssertions.java
+++ b/playwright/src/main/java/com/microsoft/playwright/assertions/LocatorAssertions.java
@@ -23,14 +23,14 @@
  * The {@code LocatorAssertions} class provides assertion methods that can be used to make assertions about the {@code
  * Locator} state in the tests.
  * 
{@code
- * ...
+ * // ...
  * import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
  *
  * public class TestLocator {
- *   ...
+ *   // ...
  *   @Test
  *   void statusBecomesSubmitted() {
- *     ...
+ *     // ...
  *     page.getByRole(AriaRole.BUTTON).click();
  *     assertThat(page.locator(".status")).hasText("Submitted");
  *   }
@@ -2097,7 +2097,7 @@ default void hasValue(Pattern value) {
    *
    * 

For example, given the following element: *

{@code
-   * page.locator("id=favorite-colors").selectOption(["R", "G"]);
+   * page.locator("id=favorite-colors").selectOption(new String[]{"R", "G"});
    * assertThat(page.locator("id=favorite-colors")).hasValues(new Pattern[] { Pattern.compile("R"), Pattern.compile("G") });
    * }
* @@ -2115,7 +2115,7 @@ default void hasValues(String[] values) { * *

For example, given the following element: *

{@code
-   * page.locator("id=favorite-colors").selectOption(["R", "G"]);
+   * page.locator("id=favorite-colors").selectOption(new String[]{"R", "G"});
    * assertThat(page.locator("id=favorite-colors")).hasValues(new Pattern[] { Pattern.compile("R"), Pattern.compile("G") });
    * }
* @@ -2131,7 +2131,7 @@ default void hasValues(String[] values) { * *

For example, given the following element: *

{@code
-   * page.locator("id=favorite-colors").selectOption(["R", "G"]);
+   * page.locator("id=favorite-colors").selectOption(new String[]{"R", "G"});
    * assertThat(page.locator("id=favorite-colors")).hasValues(new Pattern[] { Pattern.compile("R"), Pattern.compile("G") });
    * }
* @@ -2149,7 +2149,7 @@ default void hasValues(Pattern[] values) { * *

For example, given the following element: *

{@code
-   * page.locator("id=favorite-colors").selectOption(["R", "G"]);
+   * page.locator("id=favorite-colors").selectOption(new String[]{"R", "G"});
    * assertThat(page.locator("id=favorite-colors")).hasValues(new Pattern[] { Pattern.compile("R"), Pattern.compile("G") });
    * }
* @@ -2157,5 +2157,21 @@ default void hasValues(Pattern[] values) { * @since v1.23 */ void hasValues(Pattern[] values, HasValuesOptions options); + /** + * Asserts that the target element matches the given accessibility snapshot. + * + *

Usage + *

{@code
+   * page.navigate("https://demo.playwright.dev/todomvc/");
+   * assertThat(page.locator("body")).matchesAriaSnapshot("""
+   *   - heading "todos"
+   *   - textbox "What needs to be done?"
+   * """);
+   * }
+ * + * @since v1.49 + */ + void matchesAriaSnapshot(String expected); } diff --git a/playwright/src/main/java/com/microsoft/playwright/assertions/PageAssertions.java b/playwright/src/main/java/com/microsoft/playwright/assertions/PageAssertions.java index 2c8e7fa77..2bfbfa447 100644 --- a/playwright/src/main/java/com/microsoft/playwright/assertions/PageAssertions.java +++ b/playwright/src/main/java/com/microsoft/playwright/assertions/PageAssertions.java @@ -22,14 +22,14 @@ * The {@code PageAssertions} class provides assertion methods that can be used to make assertions about the {@code Page} * state in the tests. *
{@code
- * ...
+ * // ...
  * import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
  *
  * public class TestPage {
- *   ...
+ *   // ...
  *   @Test
  *   void navigatesToLoginPage() {
- *     ...
+ *     // ...
  *     page.getByText("Sign in").click();
  *     assertThat(page).hasURL(Pattern.compile(".*\/login"));
  *   }
diff --git a/playwright/src/main/java/com/microsoft/playwright/assertions/PlaywrightAssertions.java b/playwright/src/main/java/com/microsoft/playwright/assertions/PlaywrightAssertions.java
index f0fdeede1..2e926d668 100644
--- a/playwright/src/main/java/com/microsoft/playwright/assertions/PlaywrightAssertions.java
+++ b/playwright/src/main/java/com/microsoft/playwright/assertions/PlaywrightAssertions.java
@@ -30,14 +30,13 @@
  *
  * 

Consider the following example: *

{@code
- * ...
  * import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
  *
  * public class TestExample {
- *   ...
+ *   // ...
  *   @Test
  *   void statusBecomesSubmitted() {
- *     ...
+ *     // ...
  *     page.locator("#submit-button").click();
  *     assertThat(page.locator(".status")).hasText("Submitted");
  *   }
diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/LocatorAssertionsImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/LocatorAssertionsImpl.java
index 83264ea3f..3e1654c6a 100644
--- a/playwright/src/main/java/com/microsoft/playwright/impl/LocatorAssertionsImpl.java
+++ b/playwright/src/main/java/com/microsoft/playwright/impl/LocatorAssertionsImpl.java
@@ -326,6 +326,15 @@ public void hasValues(Pattern[] patterns, HasValuesOptions options) {
     expectImpl("to.have.values", list, patterns, "Locator expected to have values matching regex", convertType(options, FrameExpectOptions.class));
   }
 
+  @Override
+  public void matchesAriaSnapshot(String expected) {
+    // expected = unshift(expected);
+    // TODO: timeout
+    FrameExpectOptions options = new FrameExpectOptions();
+    options.expectedValue = serializeArgument(expected);
+    expectImpl("to.match.aria", options, expected,"Locator expected to match Aria snapshot");
+  }
+
   @Override
   public void isChecked(IsCheckedOptions options) {
     boolean unchecked = options != null && options.checked != null && !options.checked;
diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/LocatorImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/LocatorImpl.java
index b97a54fb3..d72347626 100644
--- a/playwright/src/main/java/com/microsoft/playwright/impl/LocatorImpl.java
+++ b/playwright/src/main/java/com/microsoft/playwright/impl/LocatorImpl.java
@@ -119,6 +119,18 @@ public Locator and(Locator locator) {
     return new LocatorImpl(frame, selector + " >> internal:and=" + gson().toJson(other.selector), null);
   }
 
+  @Override
+  public String ariaSnapshot() {
+    return frame.withLogging("Locator.ariaSnapshot", () -> ariaSnapshotImpl());
+  }
+
+  private String ariaSnapshotImpl() {
+    JsonObject params = new JsonObject();
+    params.addProperty("selector", selector);
+    JsonObject result = frame.sendMessage("ariaSnapshot", params).getAsJsonObject();
+    return result.get("snapshot").getAsString();
+  }
+
   @Override
   public void blur(BlurOptions options) {
     frame.withLogging("Locator.blur", () -> blurImpl(options));
@@ -650,9 +662,6 @@ JsonObject toProtocol() {
   }
 
   private FrameExpectResult expectImpl(String expression, FrameExpectOptions options) {
-    if (options == null) {
-      options = new FrameExpectOptions();
-    }
     JsonObject params = gson().toJsonTree(options).getAsJsonObject();
     params.addProperty("selector", selector);
     params.addProperty("expression", expression);
diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/TracingImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/TracingImpl.java
index f88d2130a..de7575762 100644
--- a/playwright/src/main/java/com/microsoft/playwright/impl/TracingImpl.java
+++ b/playwright/src/main/java/com/microsoft/playwright/impl/TracingImpl.java
@@ -86,6 +86,25 @@ public void startChunk(StartChunkOptions options) {
     tracingStartChunk(options.name, options.title);
   }
 
+  @Override
+  public void group(String name, GroupOptions options) {
+    withLogging("Tracing.group", () -> groupImpl(name, options));
+  }
+
+  private void groupImpl(String name, GroupOptions options) {
+    if (options == null) {
+      options = new GroupOptions();
+    }
+    JsonObject params = gson().toJsonTree(options).getAsJsonObject();
+    params.addProperty("name", name);
+    sendMessage("tracingGroup", params);
+  }
+
+  @Override
+  public void groupEnd() {
+    withLogging("Tracing.groupEnd", () -> sendMessage("tracingGroupEnd"));
+  }
+
   private void tracingStartChunk(String name, String title) {
     JsonObject params = new JsonObject();
     if (name != null) {
diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/WebSocketRouteImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/WebSocketRouteImpl.java
index 53479fcf2..3fe7a72db 100644
--- a/playwright/src/main/java/com/microsoft/playwright/impl/WebSocketRouteImpl.java
+++ b/playwright/src/main/java/com/microsoft/playwright/impl/WebSocketRouteImpl.java
@@ -69,6 +69,7 @@ public String url() {
 
   WebSocketRouteImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
     super(parent, type, guid, initializer);
+    markAsInternalType();
   }
 
     @Override
diff --git a/playwright/src/main/java/com/microsoft/playwright/options/FormData.java b/playwright/src/main/java/com/microsoft/playwright/options/FormData.java
index 057758a06..a674b83fc 100644
--- a/playwright/src/main/java/com/microsoft/playwright/options/FormData.java
+++ b/playwright/src/main/java/com/microsoft/playwright/options/FormData.java
@@ -23,7 +23,7 @@
  * The {@code FormData} is used create form data that is sent via {@code APIRequestContext}.
  * 
{@code
  * import com.microsoft.playwright.options.FormData;
- * ...
+ * // ...
  * FormData form = FormData.create()
  *     .set("firstName", "John")
  *     .set("lastName", "Doe")
@@ -43,7 +43,7 @@ public interface FormData {
    * existing set of values.
    * 
{@code
    * import com.microsoft.playwright.options.FormData;
-   * ...
+   * // ...
    * FormData form = FormData.create()
    *     // Only name and value are set.
    *     .append("firstName", "John")
@@ -70,7 +70,7 @@ public interface FormData {
    * existing set of values.
    * 
{@code
    * import com.microsoft.playwright.options.FormData;
-   * ...
+   * // ...
    * FormData form = FormData.create()
    *     // Only name and value are set.
    *     .append("firstName", "John")
@@ -97,7 +97,7 @@ public interface FormData {
    * existing set of values.
    * 
{@code
    * import com.microsoft.playwright.options.FormData;
-   * ...
+   * // ...
    * FormData form = FormData.create()
    *     // Only name and value are set.
    *     .append("firstName", "John")
@@ -124,7 +124,7 @@ public interface FormData {
    * existing set of values.
    * 
{@code
    * import com.microsoft.playwright.options.FormData;
-   * ...
+   * // ...
    * FormData form = FormData.create()
    *     // Only name and value are set.
    *     .append("firstName", "John")
@@ -151,7 +151,7 @@ public interface FormData {
    * existing set of values.
    * 
{@code
    * import com.microsoft.playwright.options.FormData;
-   * ...
+   * // ...
    * FormData form = FormData.create()
    *     // Only name and value are set.
    *     .append("firstName", "John")
@@ -179,7 +179,7 @@ static FormData create() {
    * Sets a field on the form. File values can be passed either as {@code Path} or as {@code FilePayload}.
    * 
{@code
    * import com.microsoft.playwright.options.FormData;
-   * ...
+   * // ...
    * FormData form = FormData.create()
    *     // Only name and value are set.
    *     .set("firstName", "John")
@@ -200,7 +200,7 @@ static FormData create() {
    * Sets a field on the form. File values can be passed either as {@code Path} or as {@code FilePayload}.
    * 
{@code
    * import com.microsoft.playwright.options.FormData;
-   * ...
+   * // ...
    * FormData form = FormData.create()
    *     // Only name and value are set.
    *     .set("firstName", "John")
@@ -221,7 +221,7 @@ static FormData create() {
    * Sets a field on the form. File values can be passed either as {@code Path} or as {@code FilePayload}.
    * 
{@code
    * import com.microsoft.playwright.options.FormData;
-   * ...
+   * // ...
    * FormData form = FormData.create()
    *     // Only name and value are set.
    *     .set("firstName", "John")
@@ -242,7 +242,7 @@ static FormData create() {
    * Sets a field on the form. File values can be passed either as {@code Path} or as {@code FilePayload}.
    * 
{@code
    * import com.microsoft.playwright.options.FormData;
-   * ...
+   * // ...
    * FormData form = FormData.create()
    *     // Only name and value are set.
    *     .set("firstName", "John")
@@ -263,7 +263,7 @@ static FormData create() {
    * Sets a field on the form. File values can be passed either as {@code Path} or as {@code FilePayload}.
    * 
{@code
    * import com.microsoft.playwright.options.FormData;
-   * ...
+   * // ...
    * FormData form = FormData.create()
    *     // Only name and value are set.
    *     .set("firstName", "John")
diff --git a/playwright/src/main/java/com/microsoft/playwright/options/Location.java b/playwright/src/main/java/com/microsoft/playwright/options/Location.java
new file mode 100644
index 000000000..4ce62f8e7
--- /dev/null
+++ b/playwright/src/main/java/com/microsoft/playwright/options/Location.java
@@ -0,0 +1,35 @@
+/*
+ * 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.options;
+
+public class Location {
+  public String file;
+  public Integer line;
+  public Integer column;
+
+  public Location(String file) {
+    this.file = file;
+  }
+  public Location setLine(int line) {
+    this.line = line;
+    return this;
+  }
+  public Location setColumn(int column) {
+    this.column = column;
+    return this;
+  }
+}
\ No newline at end of file
diff --git a/playwright/src/test/java/com/microsoft/playwright/TestPageAriaSnapshot.java b/playwright/src/test/java/com/microsoft/playwright/TestPageAriaSnapshot.java
new file mode 100644
index 000000000..cab73b242
--- /dev/null
+++ b/playwright/src/test/java/com/microsoft/playwright/TestPageAriaSnapshot.java
@@ -0,0 +1,53 @@
+package com.microsoft.playwright;
+
+import com.microsoft.playwright.junit.FixtureTest;
+import com.microsoft.playwright.junit.UsePlaywright;
+import org.junit.jupiter.api.Test;
+
+import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+@FixtureTest
+@UsePlaywright
+public class TestPageAriaSnapshot {
+  private static void checkAndMatchSnapshot(Locator locator, String snapshot) {
+    assertEquals(snapshot, locator.ariaSnapshot());
+    assertThat(locator).matchesAriaSnapshot(snapshot);
+  }
+
+  @Test
+  void shouldSnapshot(Page page) {
+    page.setContent("

title

"); + checkAndMatchSnapshot(page.locator("body"), "- heading \"title\" [level=1]"); + } + + @Test + void shouldSnapshotList(Page page) { + page.setContent("

title

title 2

"); + checkAndMatchSnapshot(page.locator("body"), "- heading \"title\" [level=1]\n- heading \"title 2\" [level=1]"); + } + + @Test + void shouldSnapshotListWithAccessibleName(Page page) { + page.setContent("
  • one
  • two
"); + checkAndMatchSnapshot(page.locator("body"), "- list \"my list\":\n - listitem: one\n - listitem: two"); + } + + @Test + void shouldSnapshotComplex(Page page) { + page.setContent(""); + checkAndMatchSnapshot(page.locator("body"), "- list:\n - listitem:\n - link \"link\""); + } + + @Test + void shouldAllowTextNodes(Page page) { + page.setContent("

Microsoft

Open source projects and samples from Microsoft
"); + checkAndMatchSnapshot(page.locator("body"), "- heading \"Microsoft\" [level=1]\n- text: Open source projects and samples from Microsoft"); + } + + @Test + void shouldSnapshotDetailsVisibility(Page page) { + page.setContent("
Summary
Details
"); + checkAndMatchSnapshot(page.locator("body"), "- group: Summary"); + } +} diff --git a/playwright/src/test/java/com/microsoft/playwright/TestTracing.java b/playwright/src/test/java/com/microsoft/playwright/TestTracing.java index 4a0640381..2da398f97 100644 --- a/playwright/src/test/java/com/microsoft/playwright/TestTracing.java +++ b/playwright/src/test/java/com/microsoft/playwright/TestTracing.java @@ -16,6 +16,9 @@ package com.microsoft.playwright; +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.microsoft.playwright.options.Location; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -26,12 +29,14 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.*; public class TestTracing extends TestBase { @Override @@ -154,4 +159,68 @@ void shouldRespectTracesDirAndName(@TempDir Path tempDir) { } } + @Test + void canCallTracingGroupGroupEndAtAnyTimeAndAutoClose(@TempDir Path tempDir) throws Exception { + context.tracing().group("ignored"); + context.tracing().groupEnd(); + context.tracing().group("ignored2"); + + context.tracing().start(new Tracing.StartOptions()); + context.tracing().group("actual"); + page.navigate(server.EMPTY_PAGE); + Path traceFile1 = tempDir.resolve("trace1.zip"); + context.tracing().stopChunk(new Tracing.StopChunkOptions().setPath(traceFile1)); + + context.tracing().group("ignored3"); + context.tracing().groupEnd(); + context.tracing().groupEnd(); + context.tracing().groupEnd(); + + List events = parseTraceEvents(traceFile1); + List groups = events.stream().filter(e -> "tracingGroup".equals(e.method)).collect(Collectors.toList()); + assertEquals(1, groups.size()); + assertEquals("actual", groups.get(0).apiName); + + } + + @Test + void traceGroupGroupEnd(@TempDir Path tempDir) throws Exception { + context.tracing().start(new Tracing.StartOptions()); + context.tracing().group("outer group"); + page.navigate("data:text/html,
Hello world
"); + context.tracing().group("inner group 1", new Tracing.GroupOptions().setLocation(new Location("foo.java").setLine(17).setColumn(1))); + page.locator("body").click(); + context.tracing().groupEnd(); + context.tracing().group("inner group 2"); + assertTrue(page.locator("text=Hello").isVisible()); + context.tracing().groupEnd(); + context.tracing().groupEnd(); + + Path traceFile1 = tempDir.resolve("trace1.zip"); + context.tracing().stop(new Tracing.StopOptions().setPath(traceFile1)); + + List events = parseTraceEvents(traceFile1); + List calls = events.stream().filter(e -> e.apiName != null).map(e -> e.apiName).collect(Collectors.toList()); + assertEquals(asList("outer group", "Page.navigate", "inner group 1", "Frame.click", "inner group 2", "Page.isVisible"), calls); + } + + private static class TraceEvent { + String type; + String name; + String apiName; + String method; + Double startTime; + Double endTime; + String callId; + } + + private static List parseTraceEvents(Path traceFile) throws IOException { + Map files = Utils.parseZip(traceFile); + Map traces = files.entrySet().stream().filter(e -> e.getKey().endsWith(".trace")).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + assertNotNull(traces.get("trace.trace")); + return Arrays.stream(new String(traces.get("trace.trace"), UTF_8) + .split("\n")) + .map(s -> new Gson().fromJson(s, TraceEvent.class)) + .collect(Collectors.toList()); + } } diff --git a/scripts/DRIVER_VERSION b/scripts/DRIVER_VERSION index 5525f03fa..de6633e1c 100644 --- a/scripts/DRIVER_VERSION +++ b/scripts/DRIVER_VERSION @@ -1 +1 @@ -1.48.1 +1.49.0-beta-1731595428000 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 f6d811695..c0b299240 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 @@ -986,7 +986,7 @@ void writeTo(List output, String offset) { if (methods.stream().anyMatch(m -> "create".equals(m.jsonName))) { output.add("import com.microsoft.playwright.impl." + jsonName + "Impl;"); } - if (asList("Page", "Request", "Response", "APIRequestContext", "APIRequest", "APIResponse", "FileChooser", "Frame", "FrameLocator", "ElementHandle", "Locator", "Browser", "BrowserContext", "BrowserType", "Mouse", "Keyboard").contains(jsonName)) { + if (asList("Page", "Request", "Response", "APIRequestContext", "APIRequest", "APIResponse", "FileChooser", "Frame", "FrameLocator", "ElementHandle", "Locator", "Browser", "BrowserContext", "BrowserType", "Mouse", "Keyboard", "Tracing").contains(jsonName)) { output.add("import com.microsoft.playwright.options.*;"); } if ("Download".equals(jsonName)) { From 02863c59e6df00c8a5d110d88b7021165e59ad5c Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Thu, 14 Nov 2024 14:31:16 -0800 Subject: [PATCH 2/7] unshift --- .../playwright/TestPageAriaSnapshot.java | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/playwright/src/test/java/com/microsoft/playwright/TestPageAriaSnapshot.java b/playwright/src/test/java/com/microsoft/playwright/TestPageAriaSnapshot.java index cab73b242..11b6cc0f5 100644 --- a/playwright/src/test/java/com/microsoft/playwright/TestPageAriaSnapshot.java +++ b/playwright/src/test/java/com/microsoft/playwright/TestPageAriaSnapshot.java @@ -4,14 +4,43 @@ import com.microsoft.playwright.junit.UsePlaywright; import org.junit.jupiter.api.Test; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; @FixtureTest @UsePlaywright public class TestPageAriaSnapshot { + public static String unshift(String snapshot) { + List lines = Arrays.asList(snapshot.split("\n")); + int whitespacePrefixLength = 100; + Pattern pattern = Pattern.compile("^(\\s*).*"); + for (String line : lines) { + if (line.trim().isEmpty()) + continue; + Matcher matcher = pattern.matcher(line); + if (!matcher.matches()) { + continue; + } + String match = matcher.group(1); + if (match.length() < whitespacePrefixLength) { + whitespacePrefixLength = match.length(); + } + } + final int prefixLength = whitespacePrefixLength; + return lines.stream() + .filter(line -> !line.trim().isEmpty()) + .map(line -> line.substring(prefixLength)) + .collect(Collectors.joining("\n")); + } + private static void checkAndMatchSnapshot(Locator locator, String snapshot) { - assertEquals(snapshot, locator.ariaSnapshot()); + assertEquals(unshift(snapshot), locator.ariaSnapshot()); assertThat(locator).matchesAriaSnapshot(snapshot); } @@ -24,7 +53,9 @@ void shouldSnapshot(Page page) { @Test void shouldSnapshotList(Page page) { page.setContent("

title

title 2

"); - checkAndMatchSnapshot(page.locator("body"), "- heading \"title\" [level=1]\n- heading \"title 2\" [level=1]"); + checkAndMatchSnapshot(page.locator("body"), "" + + " - heading \"title\" [level=1]\n" + + " - heading \"title 2\" [level=1]"); } @Test @@ -42,7 +73,8 @@ void shouldSnapshotComplex(Page page) { @Test void shouldAllowTextNodes(Page page) { page.setContent("

Microsoft

Open source projects and samples from Microsoft
"); - checkAndMatchSnapshot(page.locator("body"), "- heading \"Microsoft\" [level=1]\n- text: Open source projects and samples from Microsoft"); + checkAndMatchSnapshot(page.locator("body"), "- heading \"Microsoft\" [level=1]\n" + + "- text: Open source projects and samples from Microsoft"); } @Test From 1f07b32071323b01207de4f7e17515013b2b1f04 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Thu, 14 Nov 2024 15:04:25 -0800 Subject: [PATCH 3/7] install browsers as separate step --- .github/workflows/test.yml | 4 ++ .github/workflows/verify_api.yml | 2 + .../com/microsoft/playwright/Locator.java | 53 ++++++++++++++++++- .../assertions/LocatorAssertions.java | 34 +++++++++++- .../impl/LocatorAssertionsImpl.java | 6 +-- .../playwright/impl/LocatorImpl.java | 11 ++-- .../playwright/TestPageAriaSnapshot.java | 5 +- scripts/DRIVER_VERSION | 2 +- 8 files changed, 104 insertions(+), 13 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 384d24d26..649396d1c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -30,6 +30,8 @@ jobs: run: scripts/download_driver.sh - name: Build & Install run: mvn -B install -D skipTests --no-transfer-progress + - name: Install browsers + run: mvn compile exec:java -f playwright -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" - name: Run tests run: mvn test --no-transfer-progress --fail-at-end -D org.slf4j.simpleLogger.showDateTime=true -D org.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss env: @@ -78,6 +80,8 @@ jobs: run: scripts/download_driver.sh - name: Build & Install run: mvn -B install -D skipTests --no-transfer-progress + - name: Install browsers + run: mvn compile exec:java -f playwright/pom.xml -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" - name: Install MS Edge if: matrix.browser-channel == 'msedge' && matrix.os == 'macos-latest' shell: bash diff --git a/.github/workflows/verify_api.yml b/.github/workflows/verify_api.yml index 398345490..a42ad4b6b 100644 --- a/.github/workflows/verify_api.yml +++ b/.github/workflows/verify_api.yml @@ -25,6 +25,8 @@ jobs: run: scripts/download_driver.sh - name: Regenerate APIs run: scripts/generate_api.sh + - name: Install browsers + run: mvn compile exec:java -f playwright/pom.xml -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" - name: Update browser versions in README run: scripts/update_readme.sh - name: Verify API is up to date diff --git a/playwright/src/main/java/com/microsoft/playwright/Locator.java b/playwright/src/main/java/com/microsoft/playwright/Locator.java index 3bc2b70a3..ad16fbf1f 100644 --- a/playwright/src/main/java/com/microsoft/playwright/Locator.java +++ b/playwright/src/main/java/com/microsoft/playwright/Locator.java @@ -29,6 +29,26 @@ *

Learn more about locators. */ public interface Locator { + class AriaSnapshotOptions { + /** + * 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. + */ + 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. + */ + public AriaSnapshotOptions setTimeout(double timeout) { + this.timeout = timeout; + return this; + } + } class BlurOptions { /** * Maximum time in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default @@ -2230,7 +2250,38 @@ public WaitForOptions setTimeout(double timeout) { * * @since v1.49 */ - String ariaSnapshot(); + default String ariaSnapshot() { + return ariaSnapshot(null); + } + /** + * Captures the aria snapshot of the given element. Read more about aria snapshots and {@link + * com.microsoft.playwright.assertions.LocatorAssertions#matchesAriaSnapshot LocatorAssertions.matchesAriaSnapshot()} for + * the corresponding assertion. + * + *

Usage + *

{@code
+   * page.getByRole(AriaRole.LINK).ariaSnapshot();
+   * }
+ * + *

Details + * + *

This method captures the aria snapshot of the given element. The snapshot is a string that represents the state of the + * element and its children. The snapshot can be used to assert the state of the element in the test, or to compare it to + * state in the future. + * + *

The ARIA snapshot is represented using YAML markup language: + *

    + *
  • The keys of the objects are the roles and optional accessible names of the elements.
  • + *
  • The values are either text content or an array of child elements.
  • + *
  • Generic static text can be represented with the {@code text} key.
  • + *
+ * + *

Below is the HTML markup and the respective ARIA snapshot: + * + * @since v1.49 + */ + String ariaSnapshot(AriaSnapshotOptions options); /** * Calls blur on the element. * 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 cb3a0e0a9..ea34fc2f2 100644 --- a/playwright/src/main/java/com/microsoft/playwright/assertions/LocatorAssertions.java +++ b/playwright/src/main/java/com/microsoft/playwright/assertions/LocatorAssertions.java @@ -485,6 +485,20 @@ public HasValuesOptions setTimeout(double timeout) { return this; } } + class MatchesAriaSnapshotOptions { + /** + * 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 MatchesAriaSnapshotOptions setTimeout(double timeout) { + this.timeout = timeout; + return this; + } + } /** * Makes the assertion check for the opposite condition. For example, this code tests that the Locator doesn't contain text * {@code "error"}: @@ -2172,6 +2186,24 @@ default void hasValues(Pattern[] values) { * * @since v1.49 */ - void matchesAriaSnapshot(String expected); + default void matchesAriaSnapshot(String expected) { + matchesAriaSnapshot(expected, null); + } + /** + * Asserts that the target element matches the given accessibility snapshot. + * + *

Usage + *

{@code
+   * page.navigate("https://demo.playwright.dev/todomvc/");
+   * assertThat(page.locator("body")).matchesAriaSnapshot("""
+   *   - heading "todos"
+   *   - textbox "What needs to be done?"
+   * """);
+   * }
+ * + * @since v1.49 + */ + void matchesAriaSnapshot(String expected, MatchesAriaSnapshotOptions options); } diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/LocatorAssertionsImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/LocatorAssertionsImpl.java index 3e1654c6a..7bf592f0b 100644 --- a/playwright/src/main/java/com/microsoft/playwright/impl/LocatorAssertionsImpl.java +++ b/playwright/src/main/java/com/microsoft/playwright/impl/LocatorAssertionsImpl.java @@ -327,10 +327,8 @@ public void hasValues(Pattern[] patterns, HasValuesOptions options) { } @Override - public void matchesAriaSnapshot(String expected) { - // expected = unshift(expected); - // TODO: timeout - FrameExpectOptions options = new FrameExpectOptions(); + public void matchesAriaSnapshot(String expected, MatchesAriaSnapshotOptions snapshotOptions) { + FrameExpectOptions options = convertType(snapshotOptions, FrameExpectOptions.class); options.expectedValue = serializeArgument(expected); expectImpl("to.match.aria", options, expected,"Locator expected to match Aria snapshot"); } diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/LocatorImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/LocatorImpl.java index d72347626..9bb3eb197 100644 --- a/playwright/src/main/java/com/microsoft/playwright/impl/LocatorImpl.java +++ b/playwright/src/main/java/com/microsoft/playwright/impl/LocatorImpl.java @@ -120,12 +120,15 @@ public Locator and(Locator locator) { } @Override - public String ariaSnapshot() { - return frame.withLogging("Locator.ariaSnapshot", () -> ariaSnapshotImpl()); + public String ariaSnapshot(AriaSnapshotOptions options) { + return frame.withLogging("Locator.ariaSnapshot", () -> ariaSnapshotImpl(options)); } - private String ariaSnapshotImpl() { - JsonObject params = new JsonObject(); + private String ariaSnapshotImpl(AriaSnapshotOptions options) { + if (options == null) { + options = new AriaSnapshotOptions(); + } + JsonObject params = gson().toJsonTree(options).getAsJsonObject(); params.addProperty("selector", selector); JsonObject result = frame.sendMessage("ariaSnapshot", params).getAsJsonObject(); return result.get("snapshot").getAsString(); diff --git a/playwright/src/test/java/com/microsoft/playwright/TestPageAriaSnapshot.java b/playwright/src/test/java/com/microsoft/playwright/TestPageAriaSnapshot.java index 11b6cc0f5..8dc68e166 100644 --- a/playwright/src/test/java/com/microsoft/playwright/TestPageAriaSnapshot.java +++ b/playwright/src/test/java/com/microsoft/playwright/TestPageAriaSnapshot.java @@ -73,8 +73,9 @@ void shouldSnapshotComplex(Page page) { @Test void shouldAllowTextNodes(Page page) { page.setContent("

Microsoft

Open source projects and samples from Microsoft
"); - checkAndMatchSnapshot(page.locator("body"), "- heading \"Microsoft\" [level=1]\n" + - "- text: Open source projects and samples from Microsoft"); + checkAndMatchSnapshot(page.locator("body"), "" + + " - heading \"Microsoft\" [level=1]\n" + + " - text: Open source projects and samples from Microsoft"); } @Test diff --git a/scripts/DRIVER_VERSION b/scripts/DRIVER_VERSION index de6633e1c..90269c3ed 100644 --- a/scripts/DRIVER_VERSION +++ b/scripts/DRIVER_VERSION @@ -1 +1 @@ -1.49.0-beta-1731595428000 +1.49.0-beta-1731616844000 From a2ba1f67716e0bb0112b76381a3cc58ef5dd81d7 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Thu, 14 Nov 2024 15:15:09 -0800 Subject: [PATCH 4/7] fix errors --- .github/workflows/test.yml | 6 ++++-- .github/workflows/verify_api.yml | 2 +- .../microsoft/playwright/impl/LocatorAssertionsImpl.java | 3 +++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 649396d1c..92ddefc64 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,7 +31,7 @@ jobs: - name: Build & Install run: mvn -B install -D skipTests --no-transfer-progress - name: Install browsers - run: mvn compile exec:java -f playwright -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" + run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" -f playwright/pom.xml - name: Run tests run: mvn test --no-transfer-progress --fail-at-end -D org.slf4j.simpleLogger.showDateTime=true -D org.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss env: @@ -81,7 +81,7 @@ jobs: - name: Build & Install run: mvn -B install -D skipTests --no-transfer-progress - name: Install browsers - run: mvn compile exec:java -f playwright/pom.xml -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" + run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" -f playwright/pom.xml - name: Install MS Edge if: matrix.browser-channel == 'msedge' && matrix.os == 'macos-latest' shell: bash @@ -112,6 +112,8 @@ jobs: run: scripts/download_driver.sh - name: Build & Install run: mvn -B install -D skipTests --no-transfer-progress + - name: Install browsers + run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" -f playwright/pom.xml - name: Run tests run: mvn test --no-transfer-progress --fail-at-end env: diff --git a/.github/workflows/verify_api.yml b/.github/workflows/verify_api.yml index a42ad4b6b..5493e4dd5 100644 --- a/.github/workflows/verify_api.yml +++ b/.github/workflows/verify_api.yml @@ -26,7 +26,7 @@ jobs: - name: Regenerate APIs run: scripts/generate_api.sh - name: Install browsers - run: mvn compile exec:java -f playwright/pom.xml -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" + run: mvn compile exec:java --no-transfer-progress -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" -f playwright/pom.xml - name: Update browser versions in README run: scripts/update_readme.sh - name: Verify API is up to date diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/LocatorAssertionsImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/LocatorAssertionsImpl.java index 7bf592f0b..d7e654219 100644 --- a/playwright/src/main/java/com/microsoft/playwright/impl/LocatorAssertionsImpl.java +++ b/playwright/src/main/java/com/microsoft/playwright/impl/LocatorAssertionsImpl.java @@ -328,6 +328,9 @@ public void hasValues(Pattern[] patterns, HasValuesOptions options) { @Override public void matchesAriaSnapshot(String expected, MatchesAriaSnapshotOptions snapshotOptions) { + if (snapshotOptions == null) { + snapshotOptions = new MatchesAriaSnapshotOptions(); + } FrameExpectOptions options = convertType(snapshotOptions, FrameExpectOptions.class); options.expectedValue = serializeArgument(expected); expectImpl("to.match.aria", options, expected,"Locator expected to match Aria snapshot"); From 726e3d62f75b05adf8b04993272174769f3c9886 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Thu, 14 Nov 2024 15:27:48 -0800 Subject: [PATCH 5/7] Build project in verify action --- .github/workflows/verify_api.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/verify_api.yml b/.github/workflows/verify_api.yml index 5493e4dd5..a692f84ab 100644 --- a/.github/workflows/verify_api.yml +++ b/.github/workflows/verify_api.yml @@ -25,8 +25,10 @@ jobs: run: scripts/download_driver.sh - name: Regenerate APIs run: scripts/generate_api.sh + - name: Build & Install + run: mvn -B install -D skipTests --no-transfer-progress - name: Install browsers - run: mvn compile exec:java --no-transfer-progress -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" -f playwright/pom.xml + run: mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install --with-deps" -f playwright/pom.xml - name: Update browser versions in README run: scripts/update_readme.sh - name: Verify API is up to date From ee3fe47a1b9803b02dba6578760078e4d92a30e0 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Thu, 14 Nov 2024 16:30:21 -0800 Subject: [PATCH 6/7] Fix tests on channels --- .../TestBrowserContextCDPSession.java | 30 +++++++++++++++---- .../TestBrowserContextCredentials.java | 7 +++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextCDPSession.java b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextCDPSession.java index eeba7b6d0..8fafe50f5 100644 --- a/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextCDPSession.java +++ b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextCDPSession.java @@ -16,6 +16,7 @@ package com.microsoft.playwright; +import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import org.junit.jupiter.api.Test; @@ -49,7 +50,12 @@ void shouldSendEvents() { cdpSession.send("Network.enable"); List events = new ArrayList<>(); - cdpSession.on("Network.requestWillBeSent", events::add); + cdpSession.on("Network.requestWillBeSent", (JsonObject jsonObject) -> { + // Only register main request, ignore favicon requests. + if ("Document".equals(jsonObject.get("type").getAsString())) { + events.add(jsonObject); + } + }); page.navigate(server.EMPTY_PAGE); assertEquals(1, events.size()); @@ -136,8 +142,14 @@ void shouldAddMultipleEventListeners() { cdpSession.send("Network.enable"); List events = new ArrayList<>(); - cdpSession.on("Network.requestWillBeSent", events::add); - cdpSession.on("Network.requestWillBeSent", events::add); + Consumer listener1 = (JsonObject jsonObject) -> { + // Only register main request, ignore favicon requests. + if ("Document".equals(jsonObject.get("type").getAsString())) { + events.add(jsonObject); + } + }; + cdpSession.on("Network.requestWillBeSent", listener1); + cdpSession.on("Network.requestWillBeSent", listener1); page.navigate(server.EMPTY_PAGE); assertEquals(2, events.size()); @@ -149,9 +161,15 @@ void shouldRemoveEventListeners() { cdpSession.send("Network.enable"); List events = new ArrayList<>(); - Consumer listener1 = events::add; + Consumer listener1 = (JsonObject jsonObject) -> { + // Only register main request, ignore favicon requests. + if ("Document".equals(jsonObject.get("type").getAsString())) { + events.add(jsonObject); + } + }; + Consumer listener2 = listener1::accept; cdpSession.on("Network.requestWillBeSent", listener1); - cdpSession.on("Network.requestWillBeSent", events::add); + cdpSession.on("Network.requestWillBeSent", listener2); page.navigate(server.EMPTY_PAGE); assertEquals(2, events.size()); @@ -160,6 +178,6 @@ void shouldRemoveEventListeners() { events.clear(); page.navigate(server.EMPTY_PAGE); - assertEquals(1, events.size()); + assertEquals(1, events.size(), new Gson().toJson(events)); } } diff --git a/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextCredentials.java b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextCredentials.java index e9ce80aa4..a024c5746 100644 --- a/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextCredentials.java +++ b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextCredentials.java @@ -29,6 +29,13 @@ static boolean isChromiumHeadful() { return isChromium() && isHeadful(); } + static boolean isChromiumChannel() { + // net::ERR_INVALID_AUTH_CREDENTIALS is thrown in --headless=new which + // is the default in all Chromium channels. + return isChromium() && getBrowserChannelFromEnv() != null; + } + + @Test @DisabledIf(value="isChromiumHeadful", disabledReason="fail") void shouldFailWithoutCredentials() { From 073ca161cc2f82bb70fa8a59f2c44651662aa67a Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Thu, 14 Nov 2024 16:56:26 -0800 Subject: [PATCH 7/7] Skip headed like --- .../TestBrowserContextCredentials.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextCredentials.java b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextCredentials.java index a024c5746..ce556273e 100644 --- a/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextCredentials.java +++ b/playwright/src/test/java/com/microsoft/playwright/TestBrowserContextCredentials.java @@ -25,20 +25,15 @@ public class TestBrowserContextCredentials extends TestBase { - static boolean isChromiumHeadful() { - return isChromium() && isHeadful(); + static boolean isChromiumHeadedLike() { + // --headless=new, the default in all Chromium channels, is like headless. + return isChromium() && (isHeadful() || getBrowserChannelFromEnv() != null); } - static boolean isChromiumChannel() { - // net::ERR_INVALID_AUTH_CREDENTIALS is thrown in --headless=new which - // is the default in all Chromium channels. - return isChromium() && getBrowserChannelFromEnv() != null; - } - - @Test - @DisabledIf(value="isChromiumHeadful", disabledReason="fail") + @DisabledIf(value="isChromiumHeadedLike", disabledReason="fail") void shouldFailWithoutCredentials() { + System.out.println("channel2 " + getBrowserChannelFromEnv()); server.setAuth("/empty.html", "user", "pass"); Response response = page.navigate(server.EMPTY_PAGE); assertEquals(401, response.status()); @@ -110,6 +105,7 @@ void shouldWorkWithCorrectCredentialsAndMatchingOriginCaseInsensitive() { } @Test + @DisabledIf(value="isChromiumHeadedLike", disabledReason="fail") void shouldFailWithCorrectCredentialsAndWrongOriginScheme() { server.setAuth("/empty.html", "user", "pass"); final HttpCredentials httpCredentials = new HttpCredentials("user", "pass"); @@ -122,6 +118,7 @@ void shouldFailWithCorrectCredentialsAndWrongOriginScheme() { } @Test + @DisabledIf(value="isChromiumHeadedLike", disabledReason="fail") void shouldFailWithCorrectCredentialsAndWrongOriginHostname() { server.setAuth("/empty.html", "user", "pass"); final HttpCredentials httpCredentials = new HttpCredentials("user", "pass"); @@ -134,6 +131,7 @@ void shouldFailWithCorrectCredentialsAndWrongOriginHostname() { } @Test + @DisabledIf(value="isChromiumHeadedLike", disabledReason="fail") void shouldFailWithCorrectCredentialsAndWrongOriginPort() { server.setAuth("/empty.html", "user", "pass"); final HttpCredentials httpCredentials = new HttpCredentials("user", "pass");