1
0
mirror of synced 2026-05-23 03:03:15 +00:00

Compare commits

...

9 Commits

Author SHA1 Message Date
Yury Semikhatsky 80fa0c6e98 chore: roll driver to 1.31.1 (#1219) 2023-02-27 19:58:18 -08:00
Yury Semikhatsky 3d9dc8429c chore: set release version to 1.31.0 (#1211) 2023-02-22 08:57:24 -08:00
Karl Heinz Marbaise 4762ad9768 devops: Improve plugin configuration inheritance usage (#1201) (#1202)
devops: Improve plugin configuration inheritance usage. (#1201)
 - removing duplication of plugin definition in modules
 - using single location to define all (parent)
 - defined all used plugins via pluginManagement with
   most recent versions.
 - removed life cycle binding from pluginManagement
 - moved life cycle binding to default location
 - using jar-no-fork of maven-source-plugin.
2023-02-17 15:38:52 -08:00
Karl Heinz Marbaise 0fb77bbc81 fix: Improve maven plugin configuration (#1200) 2023-02-17 09:48:45 -08:00
Yury Semikhatsky c4b27febd4 feat: roll driver 1.31.0-beta-1676591072000 (#1207) 2023-02-16 19:09:22 -08:00
Yury Semikhatsky a478acf6b2 test: response.finished() respects page.close (#1206) 2023-02-16 15:18:54 -08:00
Yury Semikhatsky da36841809 fix: properly escape slash inside attributes (#1205)
https://github.com/microsoft/playwright/issues/20471
2023-02-16 13:02:22 -08:00
Yury Semikhatsky 8dfb745da9 fix: page.pause should not throw (#1204) 2023-02-16 11:21:24 -08:00
Yury Semikhatsky e81b874bbb chore: set dev version 1.31.0-SNAPSHOT (#1186) 2023-01-23 11:55:55 -08:00
38 changed files with 476 additions and 203 deletions
+2 -2
View File
@@ -11,9 +11,9 @@ Playwright is a Java library to automate [Chromium](https://www.chromium.org/Hom
| | Linux | macOS | Windows |
| :--- | :---: | :---: | :---: |
| Chromium <!-- GEN:chromium-version -->110.0.5481.38<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Chromium <!-- GEN:chromium-version -->111.0.5563.19<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| WebKit <!-- GEN:webkit-version -->16.4<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->108.0.2<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Firefox <!-- GEN:firefox-version -->109.0<!-- GEN:stop --> | :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/next/intro/#system-requirements) for details.
+1 -20
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>com.microsoft.playwright</groupId>
<artifactId>parent-pom</artifactId>
<version>1.30.0-SNAPSHOT</version>
<version>1.31.0</version>
</parent>
<artifactId>driver-bundle</artifactId>
@@ -16,25 +16,6 @@
It is intended to be used on the systems where Playwright driver is not preinstalled.
</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<configuration>
<excludeResources>true</excludeResources>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.microsoft.playwright</groupId>
+1 -17
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>com.microsoft.playwright</groupId>
<artifactId>parent-pom</artifactId>
<version>1.30.0-SNAPSHOT</version>
<version>1.31.0</version>
</parent>
<artifactId>driver</artifactId>
@@ -15,22 +15,6 @@
This module provides API for discovery and launching of Playwright driver.
</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
+2 -2
View File
@@ -6,7 +6,7 @@
<groupId>org.example</groupId>
<artifactId>examples</artifactId>
<version>1.30.0-SNAPSHOT</version>
<version>1.31.0</version>
<name>Playwright Client Examples</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -15,7 +15,7 @@
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>1.22.0</version>
<version>1.30.0</version>
</dependency>
</dependencies>
<build>
+2 -14
View File
@@ -7,7 +7,7 @@
<parent>
<groupId>com.microsoft.playwright</groupId>
<artifactId>parent-pom</artifactId>
<version>1.30.0-SNAPSHOT</version>
<version>1.31.0</version>
</parent>
<artifactId>playwright</artifactId>
@@ -21,26 +21,14 @@
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<configuration combine.self="append">
<subpackages>com.microsoft.playwright</subpackages>
<excludePackageNames>com.microsoft.playwright.impl</excludePackageNames>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
@@ -227,8 +227,11 @@ public interface Browser extends AutoCloseable {
*/
public String userAgent;
/**
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default
* viewport.
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. Use {@code null} to disable the consistent
* viewport emulation.
*
* <p> <strong>NOTE:</strong> The {@code null} value opts out from the default presets, makes viewport depend on the host window size defined by the
* operating system. It makes the execution of the tests non-deterministic.
*/
public Optional<ViewportSize> viewportSize;
@@ -536,15 +539,21 @@ public interface Browser extends AutoCloseable {
return this;
}
/**
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default
* viewport.
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. Use {@code null} to disable the consistent
* viewport emulation.
*
* <p> <strong>NOTE:</strong> The {@code null} value opts out from the default presets, makes viewport depend on the host window size defined by the
* operating system. It makes the execution of the tests non-deterministic.
*/
public NewContextOptions setViewportSize(int width, int height) {
return setViewportSize(new ViewportSize(width, height));
}
/**
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default
* viewport.
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. Use {@code null} to disable the consistent
* viewport emulation.
*
* <p> <strong>NOTE:</strong> The {@code null} value opts out from the default presets, makes viewport depend on the host window size defined by the
* operating system. It makes the execution of the tests non-deterministic.
*/
public NewContextOptions setViewportSize(ViewportSize viewportSize) {
this.viewportSize = Optional.ofNullable(viewportSize);
@@ -722,8 +731,11 @@ public interface Browser extends AutoCloseable {
*/
public String userAgent;
/**
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default
* viewport.
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. Use {@code null} to disable the consistent
* viewport emulation.
*
* <p> <strong>NOTE:</strong> The {@code null} value opts out from the default presets, makes viewport depend on the host window size defined by the
* operating system. It makes the execution of the tests non-deterministic.
*/
public Optional<ViewportSize> viewportSize;
@@ -1031,15 +1043,21 @@ public interface Browser extends AutoCloseable {
return this;
}
/**
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default
* viewport.
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. Use {@code null} to disable the consistent
* viewport emulation.
*
* <p> <strong>NOTE:</strong> The {@code null} value opts out from the default presets, makes viewport depend on the host window size defined by the
* operating system. It makes the execution of the tests non-deterministic.
*/
public NewPageOptions setViewportSize(int width, int height) {
return setViewportSize(new ViewportSize(width, height));
}
/**
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default
* viewport.
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. Use {@code null} to disable the consistent
* viewport emulation.
*
* <p> <strong>NOTE:</strong> The {@code null} value opts out from the default presets, makes viewport depend on the host window size defined by the
* operating system. It makes the execution of the tests non-deterministic.
*/
public NewPageOptions setViewportSize(ViewportSize viewportSize) {
this.viewportSize = Optional.ofNullable(viewportSize);
@@ -601,8 +601,11 @@ public interface BrowserType {
*/
public String userAgent;
/**
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default
* viewport.
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. Use {@code null} to disable the consistent
* viewport emulation.
*
* <p> <strong>NOTE:</strong> The {@code null} value opts out from the default presets, makes viewport depend on the host window size defined by the
* operating system. It makes the execution of the tests non-deterministic.
*/
public Optional<ViewportSize> viewportSize;
@@ -1021,15 +1024,21 @@ public interface BrowserType {
return this;
}
/**
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default
* viewport.
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. Use {@code null} to disable the consistent
* viewport emulation.
*
* <p> <strong>NOTE:</strong> The {@code null} value opts out from the default presets, makes viewport depend on the host window size defined by the
* operating system. It makes the execution of the tests non-deterministic.
*/
public LaunchPersistentContextOptions setViewportSize(int width, int height) {
return setViewportSize(new ViewportSize(width, height));
}
/**
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default
* viewport.
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. Use {@code null} to disable the consistent
* viewport emulation.
*
* <p> <strong>NOTE:</strong> The {@code null} value opts out from the default presets, makes viewport depend on the host window size defined by the
* operating system. It makes the execution of the tests non-deterministic.
*/
public LaunchPersistentContextOptions setViewportSize(ViewportSize viewportSize) {
this.viewportSize = Optional.ofNullable(viewportSize);
@@ -2283,7 +2283,7 @@ public interface Locator {
*/
void dblclick(DblclickOptions options);
/**
* Programmaticaly dispatch an event on the matching element.
* Programmatically dispatch an event on the matching element.
*
* <p> **Usage**
* <pre>{@code
@@ -2328,7 +2328,7 @@ public interface Locator {
dispatchEvent(type, eventInit, null);
}
/**
* Programmaticaly dispatch an event on the matching element.
* Programmatically dispatch an event on the matching element.
*
* <p> **Usage**
* <pre>{@code
@@ -2372,7 +2372,7 @@ public interface Locator {
dispatchEvent(type, null);
}
/**
* Programmaticaly dispatch an event on the matching element.
* Programmatically dispatch an event on the matching element.
*
* <p> **Usage**
* <pre>{@code
@@ -3717,7 +3717,7 @@ public interface Locator {
*/
Page page();
/**
* Focuses the mathing element and presses a combintation of the keys.
* Focuses the matching element and presses a combination of the keys.
*
* <p> **Usage**
* <pre>{@code
@@ -3756,7 +3756,7 @@ public interface Locator {
press(key, null);
}
/**
* Focuses the mathing element and presses a combintation of the keys.
* Focuses the matching element and presses a combination of the keys.
*
* <p> **Usage**
* <pre>{@code
@@ -5441,6 +5441,45 @@ public interface Page extends AutoCloseable {
* @since v1.8
*/
Mouse mouse();
/**
* Adds one-off {@code Dialog} handler. The handler will be removed immediately after next {@code Dialog} is created.
* <pre>{@code
* page.onceDialog(dialog -> {
* dialog.accept("foo");
* });
*
* // prints 'foo'
* System.out.println(page.evaluate("prompt('Enter string:')"));
*
* // prints 'null' as the dialog will be auto-dismissed because there are no handlers.
* System.out.println(page.evaluate("prompt('Enter string:')"));
* }</pre>
*
* <p> This code above is equivalent to:
* <pre>{@code
* Consumer<Dialog> handler = new Consumer<Dialog>() {
* @Override
* public void accept(Dialog dialog) {
* dialog.accept("foo");
* page.offDialog(this);
* }
* };
* page.onDialog(handler);
*
* // prints 'foo'
* System.out.println(page.evaluate("prompt('Enter string:')"));
*
* // prints 'null' as the dialog will be auto-dismissed because there are no handlers.
* System.out.println(page.evaluate("prompt('Enter string:')"));
* }</pre>
*
* @param handler Receives the {@code Dialog} object, it **must** either {@link Dialog#accept Dialog.accept()} or {@link Dialog#dismiss
* Dialog.dismiss()} the dialog - otherwise the page will <a
* href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#never_blocking">freeze</a> waiting for the
* dialog, and actions like click will never finish.
* @since v1.10
*/
void onceDialog(Consumer<Dialog> handler);
/**
* Returns the opener for popup pages and {@code null} for others. If the opener has been closed already the returns {@code
* null}.
@@ -6727,7 +6766,7 @@ public interface Page extends AutoCloseable {
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code
* TimeoutError}. Passing zero timeout disables this.
*
* <p> <strong>NOTE:</strong> {@link Page#tap Page.tap()} requires that the {@code hasTouch} option of the browser context be set to true.
* <p> <strong>NOTE:</strong> {@link Page#tap Page.tap()} the method will throw if {@code hasTouch} option of the browser context is false.
*
* @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be used.
* @since v1.8
@@ -6749,7 +6788,7 @@ public interface Page extends AutoCloseable {
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code
* TimeoutError}. Passing zero timeout disables this.
*
* <p> <strong>NOTE:</strong> {@link Page#tap Page.tap()} requires that the {@code hasTouch} option of the browser context be set to true.
* <p> <strong>NOTE:</strong> {@link Page#tap Page.tap()} the method will throw if {@code hasTouch} option of the browser context is false.
*
* @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be used.
* @since v1.8
@@ -7838,44 +7877,5 @@ public interface Page extends AutoCloseable {
* @since v1.8
*/
List<Worker> workers();
/**
* Adds one-off {@code Dialog} handler. The handler will be removed immediately after next {@code Dialog} is created.
* <pre>{@code
* page.onceDialog(dialog -> {
* dialog.accept("foo");
* });
*
* // prints 'foo'
* System.out.println(page.evaluate("prompt('Enter string:')"));
*
* // prints 'null' as the dialog will be auto-dismissed because there are no handlers.
* System.out.println(page.evaluate("prompt('Enter string:')"));
* }</pre>
*
* <p> This code above is equivalent to:
* <pre>{@code
* Consumer<Dialog> handler = new Consumer<Dialog>() {
* @Override
* public void accept(Dialog dialog) {
* dialog.accept("foo");
* page.offDialog(this);
* }
* };
* page.onDialog(handler);
*
* // prints 'foo'
* System.out.println(page.evaluate("prompt('Enter string:')"));
*
* // prints 'null' as the dialog will be auto-dismissed because there are no handlers.
* System.out.println(page.evaluate("prompt('Enter string:')"));
* }</pre>
*
* @param handler Receives the {@code Dialog} object, it **must** either {@link Dialog#accept Dialog.accept()} or {@link Dialog#dismiss
* Dialog.dismiss()} the dialog - otherwise the page will <a
* href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#never_blocking">freeze</a> waiting for the
* dialog, and actions like click will never finish.
* @since v1.10
*/
void onceDialog(Consumer<Dialog> handler);
}
@@ -97,7 +97,7 @@ public interface Playwright extends AutoCloseable {
* Launches new Playwright driver process and connects to it. {@link Playwright#close Playwright.close()} should be called
* when the instance is no longer needed.
* <pre>{@code
* Playwright playwright = Playwright.create()) {
* Playwright playwright = Playwright.create();
* Browser browser = playwright.webkit().launch();
* Page page = browser.newPage();
* page.navigate("https://www.w3.org/");
@@ -141,6 +141,11 @@ public interface Route {
* If set changes the request HTTP headers. Header values will be converted to a string.
*/
public Map<String, String> headers;
/**
* Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is
* exceeded. Defaults to {@code 20}. Pass {@code 0} to not follow redirects.
*/
public Integer maxRedirects;
/**
* If set changes the request method (e.g. GET or POST).
*/
@@ -161,6 +166,14 @@ public interface Route {
this.headers = headers;
return this;
}
/**
* Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is
* exceeded. Defaults to {@code 20}. Pass {@code 0} to not follow redirects.
*/
public FetchOptions setMaxRedirects(int maxRedirects) {
this.maxRedirects = maxRedirects;
return this;
}
/**
* If set changes the request method (e.g. GET or POST).
*/
@@ -321,6 +334,13 @@ public interface Route {
* });
* }</pre>
*
* <p> **Details**
*
* <p> 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 Route#fetch Route.fetch()} and {@link Route#fulfill Route.fulfill()}
* instead.
*
* @since v1.8
*/
default void resume() {
@@ -340,6 +360,13 @@ public interface Route {
* });
* }</pre>
*
* <p> **Details**
*
* <p> 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 Route#fetch Route.fetch()} and {@link Route#fulfill Route.fulfill()}
* instead.
*
* @since v1.8
*/
void resume(ResumeOptions options);
@@ -488,6 +515,12 @@ public interface Route {
* });
* }</pre>
*
* <p> **Details**
*
* <p> Note that {@code headers} option will apply to the fetched request as well as any redirects initiated by it. If you want
* to only apply {@code headers} to the original request, but not to redirects, look into {@link Route#resume
* Route.resume()} instead.
*
* @since v1.29
*/
default APIResponse fetch() {
@@ -510,6 +543,12 @@ public interface Route {
* });
* }</pre>
*
* <p> **Details**
*
* <p> Note that {@code headers} option will apply to the fetched request as well as any redirects initiated by it. If you want
* to only apply {@code headers} to the original request, but not to redirects, look into {@link Route#resume
* Route.resume()} instead.
*
* @since v1.29
*/
APIResponse fetch(FetchOptions options);
@@ -42,7 +42,9 @@ public interface Selectors {
}
}
/**
* **Usage**
* Selectors must be registered before creating the page.
*
* <p> **Usage**
*
* <p> An example of registering selector engine that queries elements based on a tag name:
* <pre>{@code
@@ -64,8 +66,8 @@ public interface Selectors {
* page.setContent("<div><button>Click me</button></div>");
* // Use the selector prefixed with its name.
* Locator button = page.locator("tag=button");
* // Combine it with other selector engines.
* page.locator("tag=div >> text=\"Click me\"").click();
* // Combine it with built-in locators.
* page.locator("tag=div").getByText("Click me").click();
* // Can use it in any methods supporting selectors.
* int buttonCount = (int) page.locator("tag=button").count();
* browser.close();
@@ -80,7 +82,9 @@ public interface Selectors {
register(name, script, null);
}
/**
* **Usage**
* Selectors must be registered before creating the page.
*
* <p> **Usage**
*
* <p> An example of registering selector engine that queries elements based on a tag name:
* <pre>{@code
@@ -102,8 +106,8 @@ public interface Selectors {
* page.setContent("<div><button>Click me</button></div>");
* // Use the selector prefixed with its name.
* Locator button = page.locator("tag=button");
* // Combine it with other selector engines.
* page.locator("tag=div >> text=\"Click me\"").click();
* // Combine it with built-in locators.
* page.locator("tag=div").getByText("Click me").click();
* // Can use it in any methods supporting selectors.
* int buttonCount = (int) page.locator("tag=button").count();
* browser.close();
@@ -116,7 +120,9 @@ public interface Selectors {
*/
void register(String name, String script, RegisterOptions options);
/**
* **Usage**
* Selectors must be registered before creating the page.
*
* <p> **Usage**
*
* <p> An example of registering selector engine that queries elements based on a tag name:
* <pre>{@code
@@ -138,8 +144,8 @@ public interface Selectors {
* page.setContent("<div><button>Click me</button></div>");
* // Use the selector prefixed with its name.
* Locator button = page.locator("tag=button");
* // Combine it with other selector engines.
* page.locator("tag=div >> text=\"Click me\"").click();
* // Combine it with built-in locators.
* page.locator("tag=div").getByText("Click me").click();
* // Can use it in any methods supporting selectors.
* int buttonCount = (int) page.locator("tag=button").count();
* browser.close();
@@ -154,7 +160,9 @@ public interface Selectors {
register(name, script, null);
}
/**
* **Usage**
* Selectors must be registered before creating the page.
*
* <p> **Usage**
*
* <p> An example of registering selector engine that queries elements based on a tag name:
* <pre>{@code
@@ -176,8 +184,8 @@ public interface Selectors {
* page.setContent("<div><button>Click me</button></div>");
* // Use the selector prefixed with its name.
* Locator button = page.locator("tag=button");
* // Combine it with other selector engines.
* page.locator("tag=div >> text=\"Click me\"").click();
* // Combine it with built-in locators.
* page.locator("tag=div").getByText("Click me").click();
* // Can use it in any methods supporting selectors.
* int buttonCount = (int) page.locator("tag=button").count();
* browser.close();
@@ -25,6 +25,8 @@ public interface Touchscreen {
/**
* Dispatches a {@code touchstart} and {@code touchend} event with a single touch at the position ({@code x},{@code y}).
*
* <p> <strong>NOTE:</strong> {@link Page#tap Page.tap()} the method will throw if {@code hasTouch} option of the browser context is false.
*
* @since v1.8
*/
void tap(double x, double y);
@@ -19,8 +19,7 @@ package com.microsoft.playwright.assertions;
/**
* The {@code APIResponseAssertions} class provides assertion methods that can be used to make assertions about the {@code
* APIResponse} in the tests. A new instance of {@code APIResponseAssertions} is created by calling {@link
* PlaywrightAssertions#assertThat PlaywrightAssertions.assertThat()}:
* APIResponse} in the tests.
* <pre>{@code
* ...
* import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
@@ -20,8 +20,7 @@ import java.util.regex.Pattern;
/**
* The {@code LocatorAssertions} class provides assertion methods that can be used to make assertions about the {@code
* Locator} state in the tests. A new instance of {@code LocatorAssertions} is created by calling {@link
* PlaywrightAssertions#assertThat PlaywrightAssertions.assertThat()}:
* Locator} state in the tests.
* <pre>{@code
* ...
* import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
@@ -151,6 +150,33 @@ public interface LocatorAssertions {
return this;
}
}
class IsInViewportOptions {
/**
* The minimal ratio of the element to intersect viewport. If equals to {@code 0}, then element should intersect viewport
* at any positive ratio. Defaults to {@code 0}.
*/
public Double ratio;
/**
* Time to retry the assertion for.
*/
public Double timeout;
/**
* The minimal ratio of the element to intersect viewport. If equals to {@code 0}, then element should intersect viewport
* at any positive ratio. Defaults to {@code 0}.
*/
public IsInViewportOptions setRatio(double ratio) {
this.ratio = ratio;
return this;
}
/**
* Time to retry the assertion for.
*/
public IsInViewportOptions setTimeout(double timeout) {
this.timeout = timeout;
return this;
}
}
class IsVisibleOptions {
/**
* Time to retry the assertion for.
@@ -548,6 +574,44 @@ public interface LocatorAssertions {
* @since v1.20
*/
void isHidden(IsHiddenOptions options);
/**
* Ensures the {@code Locator} points to an element that intersects viewport, according to the <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API">intersection observer API</a>.
*
* <p> **Usage**
* <pre>{@code
* Locator locator = page.getByRole(AriaRole.BUTTON);
* // Make sure at least some part of element intersects viewport.
* assertThat(locator).isInViewport();
* // Make sure element is fully outside of viewport.
* assertThat(locator).not().isInViewport();
* // Make sure that at least half of the element intersects viewport.
* assertThat(locator).isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.5));
* }</pre>
*
* @since v1.31
*/
default void isInViewport() {
isInViewport(null);
}
/**
* Ensures the {@code Locator} points to an element that intersects viewport, according to the <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API">intersection observer API</a>.
*
* <p> **Usage**
* <pre>{@code
* Locator locator = page.getByRole(AriaRole.BUTTON);
* // Make sure at least some part of element intersects viewport.
* assertThat(locator).isInViewport();
* // Make sure element is fully outside of viewport.
* assertThat(locator).not().isInViewport();
* // Make sure that at least half of the element intersects viewport.
* assertThat(locator).isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.5));
* }</pre>
*
* @since v1.31
*/
void isInViewport(IsInViewportOptions options);
/**
* Ensures that {@code Locator} points to an <a href="https://playwright.dev/java/docs/actionability#attached">attached</a>
* and <a href="https://playwright.dev/java/docs/actionability#visible">visible</a> DOM node.
@@ -20,8 +20,7 @@ import java.util.regex.Pattern;
/**
* The {@code PageAssertions} class provides assertion methods that can be used to make assertions about the {@code Page}
* state in the tests. A new instance of {@code PageAssertions} is created by calling {@link
* PlaywrightAssertions#assertThat PlaywrightAssertions.assertThat()}:
* state in the tests.
* <pre>{@code
* ...
* import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
@@ -399,11 +399,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
private void route(UrlMatcher matcher, Consumer<Route> handler, RouteOptions options) {
withLogging("BrowserContext.route", () -> {
routes.add(matcher, handler, options == null ? null : options.times);
if (routes.size() == 1) {
JsonObject params = new JsonObject();
params.addProperty("enabled", true);
sendMessage("setNetworkInterceptionEnabled", params);
}
updateInterceptionPatterns();
});
}
@@ -525,22 +521,18 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
private void unroute(UrlMatcher matcher, Consumer<Route> handler) {
withLogging("BrowserContext.unroute", () -> {
routes.remove(matcher, handler);
maybeDisableNetworkInterception();
updateInterceptionPatterns();
});
}
private void maybeDisableNetworkInterception() {
if (routes.size() == 0) {
JsonObject params = new JsonObject();
params.addProperty("enabled", false);
sendMessage("setNetworkInterceptionEnabled", params);
}
private void updateInterceptionPatterns() {
sendMessage("setNetworkInterceptionPatterns", routes.interceptionPatterns());
}
void handleRoute(RouteImpl route) {
Router.HandleResult handled = routes.handle(route);
if (handled != Router.HandleResult.NoMatchingHandler) {
maybeDisableNetworkInterception();
updateInterceptionPatterns();
}
if (handled == Router.HandleResult.NoMatchingHandler || handled == Router.HandleResult.Fallback) {
route.resume();
@@ -148,7 +148,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
options = new HasCountOptions();
}
FrameExpectOptions commonOptions = convertType(options, FrameExpectOptions.class);
commonOptions.expectedNumber = count;
commonOptions.expectedNumber = (double) count;
List<ExpectedTextValue> expectedText = null;
expectImpl("to.have.count", expectedText, count, "Locator expected to have count", commonOptions);
}
@@ -326,6 +326,15 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
expectTrue("to.be.hidden", "Locator expected to be hidden", convertType(options, FrameExpectOptions.class));
}
@Override
public void isInViewport(IsInViewportOptions options) {
FrameExpectOptions expectOptions = convertType(options, FrameExpectOptions.class);
if (options != null && options.ratio != null) {
expectOptions.expectedNumber = options.ratio;
}
expectTrue("to.be.in.viewport", "Locator expected to be in viewport", expectOptions);
}
@Override
public void isVisible(IsVisibleOptions options) {
FrameExpectOptions frameOptions = convertType(options, FrameExpectOptions.class);
@@ -118,7 +118,7 @@ public class LocatorUtils {
// cssEscape(value).replace(/\\ /g, ' ')
// However, our attribute selectors do not conform to CSS parsing spec,
// so we escape them differently.
return '"' + value.replaceAll("\"", "\\\\\"") + '"' + (exact ? "" : "i");
return '"' + value.replaceAll("\\\\", "\\\\\\\\").replaceAll("\"", "\\\\\"") + '"' + (exact ? "" : "i");
}
private static String toJsRegExp(Pattern pattern) {
@@ -189,7 +189,7 @@ public class PageImpl extends ChannelOwner implements Page {
RouteImpl route = connection.getExistingObject(params.getAsJsonObject("route").get("guid").getAsString());
Router.HandleResult handled = routes.handle(route);
if (handled != Router.HandleResult.NoMatchingHandler) {
maybeDisableNetworkInterception();
updateInterceptionPatterns();
}
if (handled == Router.HandleResult.NoMatchingHandler || handled == Router.HandleResult.Fallback) {
browserContext.handleRoute(route);
@@ -949,8 +949,8 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public void pause() {
withLogging("BrowserContext.pause", () -> {
new WaitableRace<>(asList(context().pause(), (Waitable<JsonElement>) waitableClosedOrCrashed)).get();
withLogging("Page.pause", () -> {
runUntil(() -> {}, new WaitableRace<>(asList(context().pause(), (Waitable<JsonElement>) waitableClosedOrCrashed)));
});
}
@@ -1037,11 +1037,7 @@ public class PageImpl extends ChannelOwner implements Page {
private void route(UrlMatcher matcher, Consumer<Route> handler, RouteOptions options) {
withLogging("Page.route", () -> {
routes.add(matcher, handler, options == null ? null : options.times);
if (routes.size() == 1) {
JsonObject params = new JsonObject();
params.addProperty("enabled", true);
sendMessage("setNetworkInterceptionEnabled", params);
}
updateInterceptionPatterns();
});
}
@@ -1256,16 +1252,12 @@ public class PageImpl extends ChannelOwner implements Page {
private void unroute(UrlMatcher matcher, Consumer<Route> handler) {
withLogging("Page.unroute", () -> {
routes.remove(matcher, handler);
maybeDisableNetworkInterception();
updateInterceptionPatterns();
});
}
private void maybeDisableNetworkInterception() {
if (routes.size() == 0) {
JsonObject params = new JsonObject();
params.addProperty("enabled", false);
sendMessage("setNetworkInterceptionEnabled", params);
}
private void updateInterceptionPatterns() {
sendMessage("setNetworkInterceptionPatterns", routes.interceptionPatterns());
}
@Override
@@ -94,7 +94,7 @@ class ExpectedTextValue {
class FrameExpectOptions {
Object expressionArg;
List<ExpectedTextValue> expectedText;
Integer expectedNumber;
Double expectedNumber;
SerializedArgument expectedValue;
Boolean useInnerText;
boolean isNot;
@@ -16,14 +16,19 @@
package com.microsoft.playwright.impl;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.microsoft.playwright.Route;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
class Router {
private List<RouteInfo> routes = new ArrayList<>();
@@ -92,4 +97,29 @@ class Router {
}
return result;
}
JsonObject interceptionPatterns() {
JsonArray jsonPatterns = new JsonArray();
for (RouteInfo route : routes) {
JsonObject jsonPattern = new JsonObject();
Object urlFilter = route.matcher.rawSource;
if (urlFilter instanceof String) {
jsonPattern.addProperty("glob", (String) urlFilter);
} else if (urlFilter instanceof Pattern) {
Pattern pattern = (Pattern) urlFilter;
jsonPattern.addProperty("regexSource", pattern.pattern());
jsonPattern.addProperty("regexFlags", toJsRegexFlags(pattern));
} else {
// Match all requests.
jsonPattern.addProperty("glob", "**/*");
jsonPatterns = new JsonArray();
jsonPatterns.add(jsonPattern);
break;
}
jsonPatterns.add(jsonPattern);
}
JsonObject result = new JsonObject();
result.add("patterns", jsonPatterns);
return result;
}
}
@@ -27,7 +27,7 @@ import java.util.regex.Pattern;
import static com.microsoft.playwright.impl.Utils.globToRegex;
class UrlMatcher {
private final Object rawSource;
final Object rawSource;
private final Predicate<String> predicate;
private static Predicate<String> toPredicate(Pattern pattern) {
@@ -110,7 +110,8 @@ public interface RequestOptions {
*/
RequestOptions setForm(FormData form);
/**
* Sets an HTTP header to the request.
* Sets an HTTP header to the request. This header will apply to the fetched request as well as any redirects initiated by
* it.
*
* @param name Header name.
* @param value Header value.
@@ -0,0 +1,54 @@
package com.microsoft.playwright;
import com.microsoft.playwright.assertions.LocatorAssertions;
import org.junit.jupiter.api.Test;
import org.opentest4j.AssertionFailedError;
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
// Copied from expect-misc.spec.ts > toBeInViewport
public class TestAssertThatIsInViewport extends TestBase {
@Test
void shouldWork() {
page.setContent("<div id=big style=\"height: 10000px;\"></div>\n" +
" <div id=small>foo</div>");
assertThat(page.locator("#big")).isInViewport();
assertThat(page.locator("#small")).not().isInViewport();
page.locator("#small").scrollIntoViewIfNeeded();
assertThat(page.locator("#small")).isInViewport();
assertThat(page.locator("#small")).isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(1));
}
@Test
void shouldRespectRatioOption() {
page.setContent("<style>body, div, html { padding: 0; margin: 0; }</style>\n" +
" <div id=big style=\"height: 400vh;\"></div>");
assertThat(page.locator("div")).isInViewport();
assertThat(page.locator("div")).isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.1));
assertThat(page.locator("div")).isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.2));
assertThat(page.locator("div")).isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.24));
// In this test, element's ratio is 0.25.
assertThat(page.locator("div")).isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.25));
assertThat(page.locator("div")).not().isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.26));
assertThat(page.locator("div")).not().isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.3));
assertThat(page.locator("div")).not().isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.7));
assertThat(page.locator("div")).not().isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.8));
}
@Test
void shouldHaveGoodStack() {
AssertionFailedError error = assertThrows(AssertionFailedError.class, () -> assertThat(page.locator("body")).not().isInViewport(new LocatorAssertions.IsInViewportOptions().setTimeout(100)));
assertNotNull(error);
assertTrue(error.getMessage().contains("Locator expected not to be in viewport"), error.getMessage());
}
@Test
void shouldReportIntersectionEvenIfFullyCoveredByOtherElement() {
page.setContent("<h1>hello</h1>\n" +
" <div style=\"position: relative; height: 10000px; top: -5000px;></div>");
assertThat(page.locator("h1")).isInViewport();
}
}
@@ -17,6 +17,7 @@
package com.microsoft.playwright;
import com.microsoft.playwright.options.AriaRole;
import com.microsoft.playwright.options.WaitUntilState;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledIf;
import org.junit.jupiter.api.condition.EnabledIf;
@@ -92,4 +92,17 @@ public class TestPageInterception extends TestBase {
page.navigate(server.PREFIX + "/empty.html");
assertEquals("{ \"foo\": \"bar\" }", new String(request.get().postBody));
}
@Test
void shouldNotFollowRedirectsWhenMaxRedirectsIsSetTo0InRouteFetch() {
server.setRedirect("/foo", "/empty.html");
page.route("**/*", route -> {
APIResponse response = route.fetch(new Route.FetchOptions().setMaxRedirects(0));
assertEquals("/empty.html", response.headers().get("location"));
assertEquals(302, response.status());
route.fulfill(new Route.FulfillOptions().setBody("hello"));
});
page.navigate(server.PREFIX + "/foo");
assertTrue(page.content().contains("hello"));
}
}
@@ -19,11 +19,12 @@ package com.microsoft.playwright;
import com.microsoft.playwright.options.HttpHeader;
import org.junit.jupiter.api.Test;
import java.io.OutputStreamWriter;
import java.util.List;
import java.util.stream.Collectors;
import static java.util.Arrays.asList;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.*;
public class TestPageNetworkResponse extends TestBase {
@Test
@@ -45,4 +46,51 @@ public class TestPageNetworkResponse extends TestBase {
assertEquals(asList("a=b", "c=d"), response.headerValues("set-cookie"));
}
@Test
void shouldRejectResponseFinishedIfPageCloses() {
page.navigate(server.EMPTY_PAGE);
server.setRoute("/get", exchange -> {
// In Firefox, |fetch| will be hanging until it receives |Content-Type| header
// from server.
exchange.getResponseHeaders().add("Content-Type", "text/plain; charset=utf-8");
exchange.sendResponseHeaders(200, 0);
OutputStreamWriter writer = new OutputStreamWriter(exchange.getResponseBody());
writer.write("hello ");
});
// send request and wait for server response
Response pageResponse = page.waitForResponse("**/get", () -> {
page.evaluate("() => fetch('./get', { method: 'GET' })");
});
// In 1s send a request which will trigger a request event while pageResponse.finished() is still
// on the callstack.
page.onRequest(request -> page.close());
page.evaluate("() => setTimeout(() => fetch('./empty.html', { method: 'GET' }), 1000)");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> pageResponse.finished());
assertTrue(e.getMessage().contains("closed"), e.getMessage());
}
@Test
void shouldRejectResponseFinishedIfContextCloses() {
page.navigate(server.EMPTY_PAGE);
server.setRoute("/get", exchange -> {
// In Firefox, |fetch| will be hanging until it receives |Content-Type| header
// from server.
exchange.getResponseHeaders().add("Content-Type", "text/plain; charset=utf-8");
exchange.sendResponseHeaders(200, 0);
OutputStreamWriter writer = new OutputStreamWriter(exchange.getResponseBody());
writer.write("hello ");
});
// send request and wait for server response
Response pageResponse = page.waitForResponse("**/get", () -> {
page.evaluate("() => fetch('./get', { method: 'GET' })");
});
// In 1s send a request which will trigger a request event while pageResponse.finished() is still
// on the callstack.
page.onRequest(request -> context.close());
page.evaluate("() => setTimeout(() => fetch('./empty.html', { method: 'GET' }), 1000)");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> pageResponse.finished());
assertTrue(e.getMessage().contains("closed"), e.getMessage());
}
}
@@ -73,7 +73,7 @@ public class TestPageRequestContinue extends TestBase {
done[0] = true;
});
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.navigate(server.EMPTY_PAGE));
assertTrue(e.getMessage().contains("Navigation failed because page was closed") ||
assertTrue(e.getMessage().contains("Target page, context or browser has been closed") ||
e.getMessage().contains("frame was detached"), e.getMessage());
assertTrue(done[0]);
}
@@ -1,5 +1,6 @@
package com.microsoft.playwright;
import com.microsoft.playwright.assertions.LocatorAssertions;
import com.microsoft.playwright.options.AriaRole;
import org.junit.jupiter.api.Test;
@@ -147,6 +148,11 @@ public class TestSelectorsGetBy extends TestBase {
assertThat(page.getByPlaceholder("hello my\nworld")).hasAttribute("id", "control");
assertThat(page.getByAltText("hello my\nworld")).hasAttribute("id", "control");
assertThat(page.getByTitle("hello my\nworld")).hasAttribute("id", "control");
page.setContent("<div id=target title='my title'>Text here</div>");
assertThat(page.getByTitle("my title", new Page.GetByTitleOptions().setExact(true))).hasCount(1, new LocatorAssertions.HasCountOptions().setTimeout(500));
assertThat(page.getByTitle("my t\\itle", new Page.GetByTitleOptions().setExact(true))).hasCount(0, new LocatorAssertions.HasCountOptions().setTimeout(500));
assertThat(page.getByTitle("my t\\\\itle", new Page.GetByTitleOptions().setExact(true))).hasCount(0, new LocatorAssertions.HasCountOptions().setTimeout(500));
}
@Test
@@ -178,6 +184,16 @@ public class TestSelectorsGetBy extends TestBase {
assertEquals(
asList("<a href=\"https://playwright.dev\">he llo 56</a>"),
page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName(" he \n llo 56 ").setExact(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(
asList("<button>Click me</button>"),
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Click me").setExact(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(
asList(),
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Click \\me").setExact(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(
asList(),
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Click \\\\me").setExact(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
}
@Test
+49 -23
View File
@@ -6,7 +6,7 @@
<groupId>com.microsoft.playwright</groupId>
<artifactId>parent-pom</artifactId>
<version>1.30.0-SNAPSHOT</version>
<version>1.31.0</version>
<packaging>pom</packaging>
<name>Playwright Parent Project</name>
<description>Java library to automate Chromium, Firefox and WebKit with a single API.
@@ -42,7 +42,8 @@
</modules>
<properties>
<compiler.version>1.8</compiler.version>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<gson.version>2.8.9</gson.version>
<junit.version>5.7.0</junit.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -90,26 +91,35 @@
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>3.2.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${compiler.version}</source>
<target>${compiler.version}</target>
</configuration>
<version>3.10.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -119,14 +129,6 @@
<additionalOptions>--allow-script-in-comments</additionalOptions>
<failOnError>false</failOnError>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -156,7 +158,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
@@ -167,6 +169,30 @@
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
+1 -1
View File
@@ -1 +1 @@
1.30.0-beta-1674276599000
1.31.1
+1 -1
View File
@@ -6,7 +6,7 @@
<groupId>com.microsoft.playwright</groupId>
<artifactId>api-generator</artifactId>
<version>1.30.0-SNAPSHOT</version>
<version>1.31.0</version>
<name>Playwright - API Generator</name>
<description>
This is an internal module used to generate Java API from the upstream Playwright
+1 -1
View File
@@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.microsoft.playwright</groupId>
<artifactId>test-cli-fatjar</artifactId>
<version>1.30.0-SNAPSHOT</version>
<version>1.31.0</version>
<name>Test Playwright Command Line FatJar</name>
<properties>
<compiler.version>1.8</compiler.version>
+1 -1
View File
@@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.microsoft.playwright</groupId>
<artifactId>test-cli-version</artifactId>
<version>1.30.0-SNAPSHOT</version>
<version>1.31.0</version>
<name>Test Playwright Command Line Version</name>
<properties>
<compiler.version>1.8</compiler.version>
+1 -1
View File
@@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.microsoft.playwright</groupId>
<artifactId>test-local-installation</artifactId>
<version>1.30.0-SNAPSHOT</version>
<version>1.31.0</version>
<name>Test local installation</name>
<description>Runs Playwright test suite (copied from playwright module) against locally cached Playwright</description>
<properties>
+1 -1
View File
@@ -9,7 +9,7 @@
</parent>
<groupId>com.microsoft.playwright</groupId>
<artifactId>test-spring-boot-starter</artifactId>
<version>1.30.0-SNAPSHOT</version>
<version>1.31.0</version>
<name>Test Playwright With Spring Boot</name>
<properties>
<spring.version>2.4.3</spring.version>
+1 -1
View File
@@ -6,7 +6,7 @@
<groupId>com.microsoft.playwright</groupId>
<artifactId>update-version</artifactId>
<version>1.30.0-SNAPSHOT</version>
<version>1.31.0</version>
<name>Playwright - Update Version in Documentation</name>
<description>
This is an internal module used to update versions in the documentation based on