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

Compare commits

...

10 Commits

Author SHA1 Message Date
Yury Semikhatsky 5229812d9b chore: set version to 1.27.1 (#1097) 2022-10-12 09:02:59 -07:00
Yury Semikhatsky 58bd1a968a chore: roll driver to 1.27.1 (#1096) 2022-10-12 08:41:07 -07:00
Yury Semikhatsky dce0fa3ccf chore: set version to 1.27.0 (#1093) 2022-10-07 18:09:48 -07:00
Jonathan Leitschuh 9ac9347dc5 [SECURITY] Fix Zip Slip Vulnerability (#1078) 2022-10-07 17:21:37 -07:00
Yury Semikhatsky 02ac0380a8 chore: roll driver to 1.27.0 (#1092) 2022-10-07 17:21:15 -07:00
Yury Semikhatsky bb4f3297e8 feat: roll 1.27.0 alpha oct 5 2022 (#1091) 2022-10-07 16:20:04 -07:00
Yury Semikhatsky ae54a7da55 docs: update gradle snippet 2022-09-20 16:23:54 -07:00
Yury Semikhatsky c6192db180 docs: update version in README.md to 1.26.0 2022-09-20 16:21:18 -07:00
Yury Semikhatsky b5c09a3141 chore: set dev version to 1.27.0-SNAPSHOT (#1073) 2022-09-20 15:32:03 -07:00
Yury Semikhatsky 8ef960a5f7 chore: mark 1.26.0 (#1072) 2022-09-20 14:28:40 -07:00
44 changed files with 3136 additions and 245 deletions
+5 -5
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 -->106.0.5249.30<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Chromium <!-- GEN:chromium-version -->107.0.5304.18<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| WebKit <!-- GEN:webkit-version -->16.0<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->104.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Firefox <!-- GEN:firefox-version -->105.0.1<!-- 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.
@@ -43,15 +43,15 @@ To run Playwright simply add following dependency to your Maven project:
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>1.17.0</version>
<version>1.26.0</version>
</dependency>
```
To run Playwright using Gradle add following dependency to your build.gradle file:
```json lines
```gradle
dependencies {
implementation group: 'com.microsoft.playwright', name: 'playwright', version: '1.25.0'
implementation group: 'com.microsoft.playwright', name: 'playwright', version: '1.26.0'
}
```
+1 -1
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>com.microsoft.playwright</groupId>
<artifactId>parent-pom</artifactId>
<version>1.26.0-SNAPSHOT</version>
<version>1.27.1</version>
</parent>
<artifactId>driver-bundle</artifactId>
+1 -1
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>com.microsoft.playwright</groupId>
<artifactId>parent-pom</artifactId>
<version>1.26.0-SNAPSHOT</version>
<version>1.27.1</version>
</parent>
<artifactId>driver</artifactId>
+1 -1
View File
@@ -6,7 +6,7 @@
<groupId>org.example</groupId>
<artifactId>examples</artifactId>
<version>1.26.0-SNAPSHOT</version>
<version>1.27.1</version>
<name>Playwright Client Examples</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+1 -1
View File
@@ -7,7 +7,7 @@
<parent>
<groupId>com.microsoft.playwright</groupId>
<artifactId>parent-pom</artifactId>
<version>1.26.0-SNAPSHOT</version>
<version>1.27.1</version>
</parent>
<artifactId>playwright</artifactId>
@@ -86,6 +86,31 @@ public interface APIRequestContext {
* Sends HTTP(S) request and returns its response. The method will populate request cookies from the context and update
* context cookies from the response. The method will automatically follow redirects.
*
* <p> JSON objects can be passed directly to the request:
* <pre>{@code
* Map<String, Object> data = new HashMap();
* data.put("title", "Book Title");
* data.put("body", "John Doe");
* request.fetch("https://example.com/api/createBook", RequestOptions.create().setMethod("post").setData(data));
* }</pre>
*
* <p> The common way to send file(s) in the body of a request is to encode it as form fields with {@code multipart/form-data}
* encoding. You can achieve that with Playwright API like this:
* <pre>{@code
* // Pass file path to the form data constructor:
* Path file = Paths.get("team.csv");
* APIResponse response = request.fetch("https://example.com/api/uploadTeamList",
* RequestOptions.create().setMethod("post").setMultipart(
* FormData.create().set("fileField", file)));
*
* // Or you can pass the file content directly as FilePayload object:
* FilePayload filePayload = new FilePayload("f.js", "text/javascript",
* "console.log(2022);".getBytes(StandardCharsets.UTF_8));
* APIResponse response = request.fetch("https://example.com/api/uploadTeamList",
* RequestOptions.create().setMethod("post").setMultipart(
* FormData.create().set("fileField", filePayload)));
* }</pre>
*
* @param urlOrRequest Target URL or Request to get all parameters from.
*/
default APIResponse fetch(String urlOrRequest) {
@@ -95,6 +120,31 @@ public interface APIRequestContext {
* Sends HTTP(S) request and returns its response. The method will populate request cookies from the context and update
* context cookies from the response. The method will automatically follow redirects.
*
* <p> JSON objects can be passed directly to the request:
* <pre>{@code
* Map<String, Object> data = new HashMap();
* data.put("title", "Book Title");
* data.put("body", "John Doe");
* request.fetch("https://example.com/api/createBook", RequestOptions.create().setMethod("post").setData(data));
* }</pre>
*
* <p> The common way to send file(s) in the body of a request is to encode it as form fields with {@code multipart/form-data}
* encoding. You can achieve that with Playwright API like this:
* <pre>{@code
* // Pass file path to the form data constructor:
* Path file = Paths.get("team.csv");
* APIResponse response = request.fetch("https://example.com/api/uploadTeamList",
* RequestOptions.create().setMethod("post").setMultipart(
* FormData.create().set("fileField", file)));
*
* // Or you can pass the file content directly as FilePayload object:
* FilePayload filePayload = new FilePayload("f.js", "text/javascript",
* "console.log(2022);".getBytes(StandardCharsets.UTF_8));
* APIResponse response = request.fetch("https://example.com/api/uploadTeamList",
* RequestOptions.create().setMethod("post").setMultipart(
* FormData.create().set("fileField", filePayload)));
* }</pre>
*
* @param urlOrRequest Target URL or Request to get all parameters from.
* @param params Optional request parameters.
*/
@@ -103,6 +153,31 @@ public interface APIRequestContext {
* Sends HTTP(S) request and returns its response. The method will populate request cookies from the context and update
* context cookies from the response. The method will automatically follow redirects.
*
* <p> JSON objects can be passed directly to the request:
* <pre>{@code
* Map<String, Object> data = new HashMap();
* data.put("title", "Book Title");
* data.put("body", "John Doe");
* request.fetch("https://example.com/api/createBook", RequestOptions.create().setMethod("post").setData(data));
* }</pre>
*
* <p> The common way to send file(s) in the body of a request is to encode it as form fields with {@code multipart/form-data}
* encoding. You can achieve that with Playwright API like this:
* <pre>{@code
* // Pass file path to the form data constructor:
* Path file = Paths.get("team.csv");
* APIResponse response = request.fetch("https://example.com/api/uploadTeamList",
* RequestOptions.create().setMethod("post").setMultipart(
* FormData.create().set("fileField", file)));
*
* // Or you can pass the file content directly as FilePayload object:
* FilePayload filePayload = new FilePayload("f.js", "text/javascript",
* "console.log(2022);".getBytes(StandardCharsets.UTF_8));
* APIResponse response = request.fetch("https://example.com/api/uploadTeamList",
* RequestOptions.create().setMethod("post").setMultipart(
* FormData.create().set("fileField", filePayload)));
* }</pre>
*
* @param urlOrRequest Target URL or Request to get all parameters from.
*/
default APIResponse fetch(Request urlOrRequest) {
@@ -112,6 +187,31 @@ public interface APIRequestContext {
* Sends HTTP(S) request and returns its response. The method will populate request cookies from the context and update
* context cookies from the response. The method will automatically follow redirects.
*
* <p> JSON objects can be passed directly to the request:
* <pre>{@code
* Map<String, Object> data = new HashMap();
* data.put("title", "Book Title");
* data.put("body", "John Doe");
* request.fetch("https://example.com/api/createBook", RequestOptions.create().setMethod("post").setData(data));
* }</pre>
*
* <p> The common way to send file(s) in the body of a request is to encode it as form fields with {@code multipart/form-data}
* encoding. You can achieve that with Playwright API like this:
* <pre>{@code
* // Pass file path to the form data constructor:
* Path file = Paths.get("team.csv");
* APIResponse response = request.fetch("https://example.com/api/uploadTeamList",
* RequestOptions.create().setMethod("post").setMultipart(
* FormData.create().set("fileField", file)));
*
* // Or you can pass the file content directly as FilePayload object:
* FilePayload filePayload = new FilePayload("f.js", "text/javascript",
* "console.log(2022);".getBytes(StandardCharsets.UTF_8));
* APIResponse response = request.fetch("https://example.com/api/uploadTeamList",
* RequestOptions.create().setMethod("post").setMultipart(
* FormData.create().set("fileField", filePayload)));
* }</pre>
*
* @param urlOrRequest Target URL or Request to get all parameters from.
* @param params Optional request parameters.
*/
@@ -121,6 +221,13 @@ public interface APIRequestContext {
* response. The method will populate request cookies from the context and update context cookies from the response. The
* method will automatically follow redirects.
*
* <p> Request parameters can be configured with {@code params} option, they will be serialized into the URL search parameters:
* <pre>{@code
* request.get("https://example.com/api/getText", RequestOptions.create()
* .setQueryParam("isbn", "1234")
* .setQueryParam("page", 23));
* }</pre>
*
* @param url Target URL.
*/
default APIResponse get(String url) {
@@ -131,6 +238,13 @@ public interface APIRequestContext {
* response. The method will populate request cookies from the context and update context cookies from the response. The
* method will automatically follow redirects.
*
* <p> Request parameters can be configured with {@code params} option, they will be serialized into the URL search parameters:
* <pre>{@code
* request.get("https://example.com/api/getText", RequestOptions.create()
* .setQueryParam("isbn", "1234")
* .setQueryParam("page", 23));
* }</pre>
*
* @param url Target URL.
* @param params Optional request parameters.
*/
@@ -178,6 +292,39 @@ public interface APIRequestContext {
* response. The method will populate request cookies from the context and update context cookies from the response. The
* method will automatically follow redirects.
*
* <p> JSON objects can be passed directly to the request:
* <pre>{@code
* Map<String, Object> data = new HashMap();
* data.put("title", "Book Title");
* data.put("body", "John Doe");
* request.post("https://example.com/api/createBook", RequestOptions.create().setData(data));
* }</pre>
*
* <p> To send form data to the server use {@code form} option. Its value will be encoded into the request body with
* {@code application/x-www-form-urlencoded} encoding (see below how to use {@code multipart/form-data} form encoding to send files):
* <pre>{@code
* request.post("https://example.com/api/findBook", RequestOptions.create().setForm(
* FormData.create().set("title", "Book Title").set("body", "John Doe")
* ));
* }</pre>
*
* <p> The common way to send file(s) in the body of a request is to upload them as form fields with {@code multipart/form-data}
* encoding. You can achieve that with Playwright API like this:
* <pre>{@code
* // Pass file path to the form data constructor:
* Path file = Paths.get("team.csv");
* APIResponse response = request.post("https://example.com/api/uploadTeamList",
* RequestOptions.create().setMultipart(
* FormData.create().set("fileField", file)));
*
* // Or you can pass the file content directly as FilePayload object:
* FilePayload filePayload = new FilePayload("f.js", "text/javascript",
* "console.log(2022);".getBytes(StandardCharsets.UTF_8));
* APIResponse response = request.post("https://example.com/api/uploadTeamList",
* RequestOptions.create().setMultipart(
* FormData.create().set("fileField", filePayload)));
* }</pre>
*
* @param url Target URL.
*/
default APIResponse post(String url) {
@@ -188,6 +335,39 @@ public interface APIRequestContext {
* response. The method will populate request cookies from the context and update context cookies from the response. The
* method will automatically follow redirects.
*
* <p> JSON objects can be passed directly to the request:
* <pre>{@code
* Map<String, Object> data = new HashMap();
* data.put("title", "Book Title");
* data.put("body", "John Doe");
* request.post("https://example.com/api/createBook", RequestOptions.create().setData(data));
* }</pre>
*
* <p> To send form data to the server use {@code form} option. Its value will be encoded into the request body with
* {@code application/x-www-form-urlencoded} encoding (see below how to use {@code multipart/form-data} form encoding to send files):
* <pre>{@code
* request.post("https://example.com/api/findBook", RequestOptions.create().setForm(
* FormData.create().set("title", "Book Title").set("body", "John Doe")
* ));
* }</pre>
*
* <p> The common way to send file(s) in the body of a request is to upload them as form fields with {@code multipart/form-data}
* encoding. You can achieve that with Playwright API like this:
* <pre>{@code
* // Pass file path to the form data constructor:
* Path file = Paths.get("team.csv");
* APIResponse response = request.post("https://example.com/api/uploadTeamList",
* RequestOptions.create().setMultipart(
* FormData.create().set("fileField", file)));
*
* // Or you can pass the file content directly as FilePayload object:
* FilePayload filePayload = new FilePayload("f.js", "text/javascript",
* "console.log(2022);".getBytes(StandardCharsets.UTF_8));
* APIResponse response = request.post("https://example.com/api/uploadTeamList",
* RequestOptions.create().setMultipart(
* FormData.create().set("fileField", filePayload)));
* }</pre>
*
* @param url Target URL.
* @param params Optional request parameters.
*/
@@ -143,7 +143,7 @@ public interface Browser extends AutoCloseable {
public Proxy proxy;
/**
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If {@code attach}
* is specified, resources are persistet as separate files and all of these files are archived along with the HAR file.
* is specified, resources are persisted as separate files and all of these files are archived along with the HAR file.
* Defaults to {@code embed}, which stores content inline the HAR file as per HAR specification.
*/
public HarContentPolicy recordHarContent;
@@ -381,7 +381,7 @@ public interface Browser extends AutoCloseable {
}
/**
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If {@code attach}
* is specified, resources are persistet as separate files and all of these files are archived along with the HAR file.
* is specified, resources are persisted as separate files and all of these files are archived along with the HAR file.
* Defaults to {@code embed}, which stores content inline the HAR file as per HAR specification.
*/
public NewContextOptions setRecordHarContent(HarContentPolicy recordHarContent) {
@@ -623,7 +623,7 @@ public interface Browser extends AutoCloseable {
public Proxy proxy;
/**
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If {@code attach}
* is specified, resources are persistet as separate files and all of these files are archived along with the HAR file.
* is specified, resources are persisted as separate files and all of these files are archived along with the HAR file.
* Defaults to {@code embed}, which stores content inline the HAR file as per HAR specification.
*/
public HarContentPolicy recordHarContent;
@@ -861,7 +861,7 @@ public interface Browser extends AutoCloseable {
}
/**
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If {@code attach}
* is specified, resources are persistet as separate files and all of these files are archived along with the HAR file.
* is specified, resources are persisted as separate files and all of these files are archived along with the HAR file.
* Defaults to {@code embed}, which stores content inline the HAR file as per HAR specification.
*/
public NewPageOptions setRecordHarContent(HarContentPolicy recordHarContent) {
@@ -404,7 +404,7 @@ public interface BrowserContext extends AutoCloseable {
* "</script>\n" +
* "<button onclick=\"onClick()\">Click me</button>\n" +
* "<div></div>");
* page.locator("button").click();
* page.getByRole("button").click();
* }
* }
* }
@@ -463,7 +463,7 @@ public interface BrowserContext extends AutoCloseable {
* "</script>\n" +
* "<button onclick=\"onClick()\">Click me</button>\n" +
* "<div></div>");
* page.locator("button").click();
* page.getByRole("button").click();
* }
* }
* }
@@ -533,7 +533,7 @@ public interface BrowserContext extends AutoCloseable {
* "</script>\n" +
* "<button onclick=\"onClick()\">Click me</button>\n" +
* "<div></div>\n");
* page.locator("button").click();
* page.getByRole("button").click();
* }
* }
* }
@@ -515,7 +515,7 @@ public interface BrowserType {
public Proxy proxy;
/**
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If {@code attach}
* is specified, resources are persistet as separate files and all of these files are archived along with the HAR file.
* is specified, resources are persisted as separate files and all of these files are archived along with the HAR file.
* Defaults to {@code embed}, which stores content inline the HAR file as per HAR specification.
*/
public HarContentPolicy recordHarContent;
@@ -861,7 +861,7 @@ public interface BrowserType {
}
/**
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If {@code attach}
* is specified, resources are persistet as separate files and all of these files are archived along with the HAR file.
* is specified, resources are persisted as separate files and all of these files are archived along with the HAR file.
* Defaults to {@code embed}, which stores content inline the HAR file as per HAR specification.
*/
public LaunchPersistentContextOptions setRecordHarContent(HarContentPolicy recordHarContent) {
@@ -27,14 +27,8 @@ import java.nio.file.Path;
* <p> Download event is emitted once the download starts. Download path becomes available once download completes:
* <pre>{@code
* // wait for download to start
* Download download = page.waitForDownload(() -> page.locator("a").click());
* // wait for download to complete
* Path path = download.path();
* }</pre>
* <pre>{@code
* // wait for download to start
* Download download = page.waitForDownload(() -> {
* page.locator("a").click();
* page.getByText("Download file").click();
* });
* // wait for download to complete
* Path path = download.path();
@@ -51,7 +51,7 @@ import java.util.*;
* <p> With the locator, every time the {@code element} is used, up-to-date DOM element is located in the page using the selector. So
* in the snippet below, underlying DOM element is going to be located twice.
* <pre>{@code
* Locator locator = page.locator("text=Submit");
* Locator locator = page.getByText("Submit");
* locator.hover();
* locator.click();
* }</pre>
@@ -1438,8 +1438,8 @@ public interface ElementHandle extends JSHandle {
*
* @param selector A selector to query for. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more
* details.
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
*/
default Object evalOnSelector(String selector, String expression) {
return evalOnSelector(selector, expression, null);
@@ -1464,8 +1464,8 @@ public interface ElementHandle extends JSHandle {
*
* @param selector A selector to query for. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more
* details.
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
Object evalOnSelector(String selector, String expression, Object arg);
@@ -1489,8 +1489,8 @@ public interface ElementHandle extends JSHandle {
*
* @param selector A selector to query for. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more
* details.
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
*/
default Object evalOnSelectorAll(String selector, String expression) {
return evalOnSelectorAll(selector, expression, null);
@@ -1515,8 +1515,8 @@ public interface ElementHandle extends JSHandle {
*
* @param selector A selector to query for. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more
* details.
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
Object evalOnSelectorAll(String selector, String expression, Object arg);
@@ -22,7 +22,7 @@ import java.nio.file.Path;
/**
* {@code FileChooser} objects are dispatched by the page in the {@link Page#onFileChooser Page.onFileChooser()} event.
* <pre>{@code
* FileChooser fileChooser = page.waitForFileChooser(() -> page.locator("upload").click());
* FileChooser fileChooser = page.waitForFileChooser(() -> page.getByText("Upload").click());
* fileChooser.setFiles(Paths.get("myfile.pdf"));
* }</pre>
*/
@@ -794,6 +794,226 @@ public interface Frame {
return this;
}
}
class GetByAltTextOptions {
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public Boolean exact;
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public GetByAltTextOptions setExact(boolean exact) {
this.exact = exact;
return this;
}
}
class GetByLabelOptions {
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public Boolean exact;
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public GetByLabelOptions setExact(boolean exact) {
this.exact = exact;
return this;
}
}
class GetByPlaceholderOptions {
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public Boolean exact;
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public GetByPlaceholderOptions setExact(boolean exact) {
this.exact = exact;
return this;
}
}
class GetByRoleOptions {
/**
* An attribute that is usually set by {@code aria-checked} or native {@code <input type=checkbox>} controls. Available values for
* checked are {@code true}, {@code false} and {@code "mixed"}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-checked">{@code aria-checked}</a>.
*/
public Boolean checked;
/**
* A boolean attribute that is usually set by {@code aria-disabled} or {@code disabled}.
*
* <p> <strong>NOTE:</strong> Unlike most other attributes, {@code disabled} is inherited through the DOM hierarchy. Learn more about <a
* href="https://www.w3.org/TR/wai-aria-1.2/#aria-disabled">{@code aria-disabled}</a>.
*/
public Boolean disabled;
/**
* A boolean attribute that is usually set by {@code aria-expanded}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-expanded">{@code aria-expanded}</a>.
*/
public Boolean expanded;
/**
* A boolean attribute that controls whether hidden elements are matched. By default, only non-hidden elements, as <a
* href="https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion">defined by ARIA</a>, are matched by role selector.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-hidden">{@code aria-hidden}</a>.
*/
public Boolean includeHidden;
/**
* A number attribute that is usually present for roles {@code heading}, {@code listitem}, {@code row}, {@code treeitem}, with default values for
* {@code <h1>-<h6>} elements.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-level">{@code aria-level}</a>.
*/
public Integer level;
/**
* A string attribute that matches <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*
* <p> Learn more about <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*/
public Object name;
/**
* An attribute that is usually set by {@code aria-pressed}. Available values for pressed are {@code true}, {@code false} and {@code "mixed"}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-pressed">{@code aria-pressed}</a>.
*/
public Boolean pressed;
/**
* A boolean attribute that is usually set by {@code aria-selected}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-selected">{@code aria-selected}</a>.
*/
public Boolean selected;
/**
* An attribute that is usually set by {@code aria-checked} or native {@code <input type=checkbox>} controls. Available values for
* checked are {@code true}, {@code false} and {@code "mixed"}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-checked">{@code aria-checked}</a>.
*/
public GetByRoleOptions setChecked(boolean checked) {
this.checked = checked;
return this;
}
/**
* A boolean attribute that is usually set by {@code aria-disabled} or {@code disabled}.
*
* <p> <strong>NOTE:</strong> Unlike most other attributes, {@code disabled} is inherited through the DOM hierarchy. Learn more about <a
* href="https://www.w3.org/TR/wai-aria-1.2/#aria-disabled">{@code aria-disabled}</a>.
*/
public GetByRoleOptions setDisabled(boolean disabled) {
this.disabled = disabled;
return this;
}
/**
* A boolean attribute that is usually set by {@code aria-expanded}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-expanded">{@code aria-expanded}</a>.
*/
public GetByRoleOptions setExpanded(boolean expanded) {
this.expanded = expanded;
return this;
}
/**
* A boolean attribute that controls whether hidden elements are matched. By default, only non-hidden elements, as <a
* href="https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion">defined by ARIA</a>, are matched by role selector.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-hidden">{@code aria-hidden}</a>.
*/
public GetByRoleOptions setIncludeHidden(boolean includeHidden) {
this.includeHidden = includeHidden;
return this;
}
/**
* A number attribute that is usually present for roles {@code heading}, {@code listitem}, {@code row}, {@code treeitem}, with default values for
* {@code <h1>-<h6>} elements.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-level">{@code aria-level}</a>.
*/
public GetByRoleOptions setLevel(int level) {
this.level = level;
return this;
}
/**
* A string attribute that matches <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*
* <p> Learn more about <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*/
public GetByRoleOptions setName(String name) {
this.name = name;
return this;
}
/**
* A string attribute that matches <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*
* <p> Learn more about <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*/
public GetByRoleOptions setName(Pattern name) {
this.name = name;
return this;
}
/**
* An attribute that is usually set by {@code aria-pressed}. Available values for pressed are {@code true}, {@code false} and {@code "mixed"}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-pressed">{@code aria-pressed}</a>.
*/
public GetByRoleOptions setPressed(boolean pressed) {
this.pressed = pressed;
return this;
}
/**
* A boolean attribute that is usually set by {@code aria-selected}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-selected">{@code aria-selected}</a>.
*/
public GetByRoleOptions setSelected(boolean selected) {
this.selected = selected;
return this;
}
}
class GetByTextOptions {
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public Boolean exact;
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public GetByTextOptions setExact(boolean exact) {
this.exact = exact;
return this;
}
}
class GetByTitleOptions {
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public Boolean exact;
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public GetByTitleOptions setExact(boolean exact) {
this.exact = exact;
return this;
}
}
class NavigateOptions {
/**
* Referer header value. If provided it will take preference over the referer header value set by {@link
@@ -2409,8 +2629,8 @@ public interface Frame {
*
* @param selector A selector to query for. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more
* details.
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
default Object evalOnSelector(String selector, String expression, Object arg) {
@@ -2439,8 +2659,8 @@ public interface Frame {
*
* @param selector A selector to query for. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more
* details.
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
*/
default Object evalOnSelector(String selector, String expression) {
return evalOnSelector(selector, expression, null);
@@ -2468,8 +2688,8 @@ public interface Frame {
*
* @param selector A selector to query for. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more
* details.
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
Object evalOnSelector(String selector, String expression, Object arg, EvalOnSelectorOptions options);
@@ -2494,8 +2714,8 @@ public interface Frame {
*
* @param selector A selector to query for. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more
* details.
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
*/
default Object evalOnSelectorAll(String selector, String expression) {
return evalOnSelectorAll(selector, expression, null);
@@ -2521,8 +2741,8 @@ public interface Frame {
*
* @param selector A selector to query for. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more
* details.
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
Object evalOnSelectorAll(String selector, String expression, Object arg);
@@ -2555,8 +2775,8 @@ public interface Frame {
* bodyHandle.dispose();
* }</pre>
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
*/
default Object evaluate(String expression) {
return evaluate(expression, null);
@@ -2590,8 +2810,8 @@ public interface Frame {
* bodyHandle.dispose();
* }</pre>
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
Object evaluate(String expression, Object arg);
@@ -2622,8 +2842,8 @@ public interface Frame {
* resultHandle.dispose();
* }</pre>
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
*/
default JSHandle evaluateHandle(String expression) {
return evaluateHandle(expression, null);
@@ -2655,8 +2875,8 @@ public interface Frame {
* resultHandle.dispose();
* }</pre>
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
JSHandle evaluateHandle(String expression, Object arg);
@@ -2733,7 +2953,7 @@ public interface Frame {
* that iframe. Following snippet locates element with text "Submit" in the iframe with id {@code my-frame}, like {@code <iframe
* id="my-frame">}:
* <pre>{@code
* Locator locator = frame.frameLocator("#my-iframe").locator("text=Submit");
* Locator locator = frame.frameLocator("#my-iframe").getByText("Submit");
* locator.click();
* }</pre>
*
@@ -2759,6 +2979,193 @@ public interface Frame {
* @param name Attribute name to get the value for.
*/
String getAttribute(String selector, String name, GetAttributeOptions options);
/**
* Allows locating elements by their alt text. For example, this method will find the image by alt text "Castle":
*
* @param text Text to locate the element for.
*/
default Locator getByAltText(String text) {
return getByAltText(text, null);
}
/**
* Allows locating elements by their alt text. For example, this method will find the image by alt text "Castle":
*
* @param text Text to locate the element for.
*/
Locator getByAltText(String text, GetByAltTextOptions options);
/**
* Allows locating elements by their alt text. For example, this method will find the image by alt text "Castle":
*
* @param text Text to locate the element for.
*/
default Locator getByAltText(Pattern text) {
return getByAltText(text, null);
}
/**
* Allows locating elements by their alt text. For example, this method will find the image by alt text "Castle":
*
* @param text Text to locate the element for.
*/
Locator getByAltText(Pattern text, GetByAltTextOptions options);
/**
* Allows locating input elements by the text of the associated label. For example, this method will find the input by
* label text Password in the following DOM:
*
* @param text Text to locate the element for.
*/
default Locator getByLabel(String text) {
return getByLabel(text, null);
}
/**
* Allows locating input elements by the text of the associated label. For example, this method will find the input by
* label text Password in the following DOM:
*
* @param text Text to locate the element for.
*/
Locator getByLabel(String text, GetByLabelOptions options);
/**
* Allows locating input elements by the text of the associated label. For example, this method will find the input by
* label text Password in the following DOM:
*
* @param text Text to locate the element for.
*/
default Locator getByLabel(Pattern text) {
return getByLabel(text, null);
}
/**
* Allows locating input elements by the text of the associated label. For example, this method will find the input by
* label text Password in the following DOM:
*
* @param text Text to locate the element for.
*/
Locator getByLabel(Pattern text, GetByLabelOptions options);
/**
* Allows locating input elements by the placeholder text. For example, this method will find the input by placeholder
* "Country":
*
* @param text Text to locate the element for.
*/
default Locator getByPlaceholder(String text) {
return getByPlaceholder(text, null);
}
/**
* Allows locating input elements by the placeholder text. For example, this method will find the input by placeholder
* "Country":
*
* @param text Text to locate the element for.
*/
Locator getByPlaceholder(String text, GetByPlaceholderOptions options);
/**
* Allows locating input elements by the placeholder text. For example, this method will find the input by placeholder
* "Country":
*
* @param text Text to locate the element for.
*/
default Locator getByPlaceholder(Pattern text) {
return getByPlaceholder(text, null);
}
/**
* Allows locating input elements by the placeholder text. For example, this method will find the input by placeholder
* "Country":
*
* @param text Text to locate the element for.
*/
Locator getByPlaceholder(Pattern text, GetByPlaceholderOptions options);
/**
* Allows locating elements by their <a href="https://www.w3.org/TR/wai-aria-1.2/#roles">ARIA role</a>, <a
* href="https://www.w3.org/TR/wai-aria-1.2/#aria-attributes">ARIA attributes</a> and <a
* href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>. Note that role selector **does not
* replace** accessibility audits and conformance tests, but rather gives early feedback about the ARIA guidelines.
*
* <p> Note that many html elements have an implicitly <a
* href="https://w3c.github.io/html-aam/#html-element-role-mappings">defined role</a> that is recognized by the role
* selector. You can find all the <a href="https://www.w3.org/TR/wai-aria-1.2/#role_definitions">supported roles here</a>.
* ARIA guidelines **do not recommend** duplicating implicit roles and attributes by setting {@code role} and/or {@code aria-*}
* attributes to default values.
*
* @param role Required aria role.
*/
default Locator getByRole(AriaRole role) {
return getByRole(role, null);
}
/**
* Allows locating elements by their <a href="https://www.w3.org/TR/wai-aria-1.2/#roles">ARIA role</a>, <a
* href="https://www.w3.org/TR/wai-aria-1.2/#aria-attributes">ARIA attributes</a> and <a
* href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>. Note that role selector **does not
* replace** accessibility audits and conformance tests, but rather gives early feedback about the ARIA guidelines.
*
* <p> Note that many html elements have an implicitly <a
* href="https://w3c.github.io/html-aam/#html-element-role-mappings">defined role</a> that is recognized by the role
* selector. You can find all the <a href="https://www.w3.org/TR/wai-aria-1.2/#role_definitions">supported roles here</a>.
* ARIA guidelines **do not recommend** duplicating implicit roles and attributes by setting {@code role} and/or {@code aria-*}
* attributes to default values.
*
* @param role Required aria role.
*/
Locator getByRole(AriaRole role, GetByRoleOptions options);
/**
* Locate element by the test id. By default, the {@code data-testid} attribute is used as a test id. Use {@link
* Selectors#setTestIdAttribute Selectors.setTestIdAttribute()} to configure a different test id attribute if necessary.
*
* @param testId Id to locate the element by.
*/
Locator getByTestId(String testId);
/**
* Allows locating elements that contain given text.
*
* @param text Text to locate the element for.
*/
default Locator getByText(String text) {
return getByText(text, null);
}
/**
* Allows locating elements that contain given text.
*
* @param text Text to locate the element for.
*/
Locator getByText(String text, GetByTextOptions options);
/**
* Allows locating elements that contain given text.
*
* @param text Text to locate the element for.
*/
default Locator getByText(Pattern text) {
return getByText(text, null);
}
/**
* Allows locating elements that contain given text.
*
* @param text Text to locate the element for.
*/
Locator getByText(Pattern text, GetByTextOptions options);
/**
* Allows locating elements by their title. For example, this method will find the button by its title "Submit":
*
* @param text Text to locate the element for.
*/
default Locator getByTitle(String text) {
return getByTitle(text, null);
}
/**
* Allows locating elements by their title. For example, this method will find the button by its title "Submit":
*
* @param text Text to locate the element for.
*/
Locator getByTitle(String text, GetByTitleOptions options);
/**
* Allows locating elements by their title. For example, this method will find the button by its title "Submit":
*
* @param text Text to locate the element for.
*/
default Locator getByTitle(Pattern text) {
return getByTitle(text, null);
}
/**
* Allows locating elements by their title. For example, this method will find the button by its title "Submit":
*
* @param text Text to locate the element for.
*/
Locator getByTitle(Pattern text, GetByTitleOptions options);
/**
* Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the
* last redirect.
@@ -3016,9 +3423,11 @@ public interface Frame {
*/
boolean isVisible(String selector, IsVisibleOptions options);
/**
* The method returns an element locator that can be used to perform actions in the frame. Locator is resolved to the
* element immediately before performing an action, so a series of actions on the same locator can in fact be performed on
* different DOM elements. That would happen if the DOM structure between those actions has changed.
* The method returns an element locator that can be used to perform actions on this page / frame. Locator is resolved to
* the element immediately before performing an action, so a series of actions on the same locator can in fact be performed
* on different DOM elements. That would happen if the DOM structure between those actions has changed.
*
* <p> <a href="https://playwright.dev/java/docs/locators">Learn more about locators</a>.
*
* <p> <a href="https://playwright.dev/java/docs/locators">Learn more about locators</a>.
*
@@ -3029,9 +3438,11 @@ public interface Frame {
return locator(selector, null);
}
/**
* The method returns an element locator that can be used to perform actions in the frame. Locator is resolved to the
* element immediately before performing an action, so a series of actions on the same locator can in fact be performed on
* different DOM elements. That would happen if the DOM structure between those actions has changed.
* The method returns an element locator that can be used to perform actions on this page / frame. Locator is resolved to
* the element immediately before performing an action, so a series of actions on the same locator can in fact be performed
* on different DOM elements. That would happen if the DOM structure between those actions has changed.
*
* <p> <a href="https://playwright.dev/java/docs/locators">Learn more about locators</a>.
*
* <p> <a href="https://playwright.dev/java/docs/locators">Learn more about locators</a>.
*
@@ -3859,8 +4270,8 @@ public interface Frame {
* frame.waitForFunction("selector => !!document.querySelector(selector)", selector);
* }</pre>
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
default JSHandle waitForFunction(String expression, Object arg) {
@@ -3893,8 +4304,8 @@ public interface Frame {
* frame.waitForFunction("selector => !!document.querySelector(selector)", selector);
* }</pre>
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
*/
default JSHandle waitForFunction(String expression) {
return waitForFunction(expression, null);
@@ -3926,8 +4337,8 @@ public interface Frame {
* frame.waitForFunction("selector => !!document.querySelector(selector)", selector);
* }</pre>
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
JSHandle waitForFunction(String expression, Object arg, WaitForFunctionOptions options);
@@ -16,6 +16,7 @@
package com.microsoft.playwright;
import com.microsoft.playwright.options.*;
import java.util.regex.Pattern;
/**
@@ -33,10 +34,10 @@ import java.util.regex.Pattern;
* a given selector.
* <pre>{@code
* // Throws if there are several frames in DOM:
* page.frame_locator(".result-frame").locator("button").click();
* page.frame_locator(".result-frame").getByRole("button").click();
*
* // Works because we explicitly tell locator to pick the first frame:
* page.frame_locator(".result-frame").first().locator("button").click();
* page.frame_locator(".result-frame").first().getByRole("button").click();
* }</pre>
*
* <p> **Converting Locator to FrameLocator**
@@ -48,6 +49,226 @@ import java.util.regex.Pattern;
* }</pre>
*/
public interface FrameLocator {
class GetByAltTextOptions {
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public Boolean exact;
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public GetByAltTextOptions setExact(boolean exact) {
this.exact = exact;
return this;
}
}
class GetByLabelOptions {
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public Boolean exact;
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public GetByLabelOptions setExact(boolean exact) {
this.exact = exact;
return this;
}
}
class GetByPlaceholderOptions {
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public Boolean exact;
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public GetByPlaceholderOptions setExact(boolean exact) {
this.exact = exact;
return this;
}
}
class GetByRoleOptions {
/**
* An attribute that is usually set by {@code aria-checked} or native {@code <input type=checkbox>} controls. Available values for
* checked are {@code true}, {@code false} and {@code "mixed"}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-checked">{@code aria-checked}</a>.
*/
public Boolean checked;
/**
* A boolean attribute that is usually set by {@code aria-disabled} or {@code disabled}.
*
* <p> <strong>NOTE:</strong> Unlike most other attributes, {@code disabled} is inherited through the DOM hierarchy. Learn more about <a
* href="https://www.w3.org/TR/wai-aria-1.2/#aria-disabled">{@code aria-disabled}</a>.
*/
public Boolean disabled;
/**
* A boolean attribute that is usually set by {@code aria-expanded}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-expanded">{@code aria-expanded}</a>.
*/
public Boolean expanded;
/**
* A boolean attribute that controls whether hidden elements are matched. By default, only non-hidden elements, as <a
* href="https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion">defined by ARIA</a>, are matched by role selector.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-hidden">{@code aria-hidden}</a>.
*/
public Boolean includeHidden;
/**
* A number attribute that is usually present for roles {@code heading}, {@code listitem}, {@code row}, {@code treeitem}, with default values for
* {@code <h1>-<h6>} elements.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-level">{@code aria-level}</a>.
*/
public Integer level;
/**
* A string attribute that matches <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*
* <p> Learn more about <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*/
public Object name;
/**
* An attribute that is usually set by {@code aria-pressed}. Available values for pressed are {@code true}, {@code false} and {@code "mixed"}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-pressed">{@code aria-pressed}</a>.
*/
public Boolean pressed;
/**
* A boolean attribute that is usually set by {@code aria-selected}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-selected">{@code aria-selected}</a>.
*/
public Boolean selected;
/**
* An attribute that is usually set by {@code aria-checked} or native {@code <input type=checkbox>} controls. Available values for
* checked are {@code true}, {@code false} and {@code "mixed"}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-checked">{@code aria-checked}</a>.
*/
public GetByRoleOptions setChecked(boolean checked) {
this.checked = checked;
return this;
}
/**
* A boolean attribute that is usually set by {@code aria-disabled} or {@code disabled}.
*
* <p> <strong>NOTE:</strong> Unlike most other attributes, {@code disabled} is inherited through the DOM hierarchy. Learn more about <a
* href="https://www.w3.org/TR/wai-aria-1.2/#aria-disabled">{@code aria-disabled}</a>.
*/
public GetByRoleOptions setDisabled(boolean disabled) {
this.disabled = disabled;
return this;
}
/**
* A boolean attribute that is usually set by {@code aria-expanded}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-expanded">{@code aria-expanded}</a>.
*/
public GetByRoleOptions setExpanded(boolean expanded) {
this.expanded = expanded;
return this;
}
/**
* A boolean attribute that controls whether hidden elements are matched. By default, only non-hidden elements, as <a
* href="https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion">defined by ARIA</a>, are matched by role selector.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-hidden">{@code aria-hidden}</a>.
*/
public GetByRoleOptions setIncludeHidden(boolean includeHidden) {
this.includeHidden = includeHidden;
return this;
}
/**
* A number attribute that is usually present for roles {@code heading}, {@code listitem}, {@code row}, {@code treeitem}, with default values for
* {@code <h1>-<h6>} elements.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-level">{@code aria-level}</a>.
*/
public GetByRoleOptions setLevel(int level) {
this.level = level;
return this;
}
/**
* A string attribute that matches <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*
* <p> Learn more about <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*/
public GetByRoleOptions setName(String name) {
this.name = name;
return this;
}
/**
* A string attribute that matches <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*
* <p> Learn more about <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*/
public GetByRoleOptions setName(Pattern name) {
this.name = name;
return this;
}
/**
* An attribute that is usually set by {@code aria-pressed}. Available values for pressed are {@code true}, {@code false} and {@code "mixed"}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-pressed">{@code aria-pressed}</a>.
*/
public GetByRoleOptions setPressed(boolean pressed) {
this.pressed = pressed;
return this;
}
/**
* A boolean attribute that is usually set by {@code aria-selected}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-selected">{@code aria-selected}</a>.
*/
public GetByRoleOptions setSelected(boolean selected) {
this.selected = selected;
return this;
}
}
class GetByTextOptions {
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public Boolean exact;
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public GetByTextOptions setExact(boolean exact) {
this.exact = exact;
return this;
}
}
class GetByTitleOptions {
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public Boolean exact;
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public GetByTitleOptions setExact(boolean exact) {
this.exact = exact;
return this;
}
}
class LocatorOptions {
/**
* Matches elements containing an element that matches an inner locator. Inner locator is queried against the outer one.
@@ -104,12 +325,202 @@ public interface FrameLocator {
* selectors</a> for more details.
*/
FrameLocator frameLocator(String selector);
/**
* Allows locating elements by their alt text. For example, this method will find the image by alt text "Castle":
*
* @param text Text to locate the element for.
*/
default Locator getByAltText(String text) {
return getByAltText(text, null);
}
/**
* Allows locating elements by their alt text. For example, this method will find the image by alt text "Castle":
*
* @param text Text to locate the element for.
*/
Locator getByAltText(String text, GetByAltTextOptions options);
/**
* Allows locating elements by their alt text. For example, this method will find the image by alt text "Castle":
*
* @param text Text to locate the element for.
*/
default Locator getByAltText(Pattern text) {
return getByAltText(text, null);
}
/**
* Allows locating elements by their alt text. For example, this method will find the image by alt text "Castle":
*
* @param text Text to locate the element for.
*/
Locator getByAltText(Pattern text, GetByAltTextOptions options);
/**
* Allows locating input elements by the text of the associated label. For example, this method will find the input by
* label text Password in the following DOM:
*
* @param text Text to locate the element for.
*/
default Locator getByLabel(String text) {
return getByLabel(text, null);
}
/**
* Allows locating input elements by the text of the associated label. For example, this method will find the input by
* label text Password in the following DOM:
*
* @param text Text to locate the element for.
*/
Locator getByLabel(String text, GetByLabelOptions options);
/**
* Allows locating input elements by the text of the associated label. For example, this method will find the input by
* label text Password in the following DOM:
*
* @param text Text to locate the element for.
*/
default Locator getByLabel(Pattern text) {
return getByLabel(text, null);
}
/**
* Allows locating input elements by the text of the associated label. For example, this method will find the input by
* label text Password in the following DOM:
*
* @param text Text to locate the element for.
*/
Locator getByLabel(Pattern text, GetByLabelOptions options);
/**
* Allows locating input elements by the placeholder text. For example, this method will find the input by placeholder
* "Country":
*
* @param text Text to locate the element for.
*/
default Locator getByPlaceholder(String text) {
return getByPlaceholder(text, null);
}
/**
* Allows locating input elements by the placeholder text. For example, this method will find the input by placeholder
* "Country":
*
* @param text Text to locate the element for.
*/
Locator getByPlaceholder(String text, GetByPlaceholderOptions options);
/**
* Allows locating input elements by the placeholder text. For example, this method will find the input by placeholder
* "Country":
*
* @param text Text to locate the element for.
*/
default Locator getByPlaceholder(Pattern text) {
return getByPlaceholder(text, null);
}
/**
* Allows locating input elements by the placeholder text. For example, this method will find the input by placeholder
* "Country":
*
* @param text Text to locate the element for.
*/
Locator getByPlaceholder(Pattern text, GetByPlaceholderOptions options);
/**
* Allows locating elements by their <a href="https://www.w3.org/TR/wai-aria-1.2/#roles">ARIA role</a>, <a
* href="https://www.w3.org/TR/wai-aria-1.2/#aria-attributes">ARIA attributes</a> and <a
* href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>. Note that role selector **does not
* replace** accessibility audits and conformance tests, but rather gives early feedback about the ARIA guidelines.
*
* <p> Note that many html elements have an implicitly <a
* href="https://w3c.github.io/html-aam/#html-element-role-mappings">defined role</a> that is recognized by the role
* selector. You can find all the <a href="https://www.w3.org/TR/wai-aria-1.2/#role_definitions">supported roles here</a>.
* ARIA guidelines **do not recommend** duplicating implicit roles and attributes by setting {@code role} and/or {@code aria-*}
* attributes to default values.
*
* @param role Required aria role.
*/
default Locator getByRole(AriaRole role) {
return getByRole(role, null);
}
/**
* Allows locating elements by their <a href="https://www.w3.org/TR/wai-aria-1.2/#roles">ARIA role</a>, <a
* href="https://www.w3.org/TR/wai-aria-1.2/#aria-attributes">ARIA attributes</a> and <a
* href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>. Note that role selector **does not
* replace** accessibility audits and conformance tests, but rather gives early feedback about the ARIA guidelines.
*
* <p> Note that many html elements have an implicitly <a
* href="https://w3c.github.io/html-aam/#html-element-role-mappings">defined role</a> that is recognized by the role
* selector. You can find all the <a href="https://www.w3.org/TR/wai-aria-1.2/#role_definitions">supported roles here</a>.
* ARIA guidelines **do not recommend** duplicating implicit roles and attributes by setting {@code role} and/or {@code aria-*}
* attributes to default values.
*
* @param role Required aria role.
*/
Locator getByRole(AriaRole role, GetByRoleOptions options);
/**
* Locate element by the test id. By default, the {@code data-testid} attribute is used as a test id. Use {@link
* Selectors#setTestIdAttribute Selectors.setTestIdAttribute()} to configure a different test id attribute if necessary.
*
* @param testId Id to locate the element by.
*/
Locator getByTestId(String testId);
/**
* Allows locating elements that contain given text.
*
* @param text Text to locate the element for.
*/
default Locator getByText(String text) {
return getByText(text, null);
}
/**
* Allows locating elements that contain given text.
*
* @param text Text to locate the element for.
*/
Locator getByText(String text, GetByTextOptions options);
/**
* Allows locating elements that contain given text.
*
* @param text Text to locate the element for.
*/
default Locator getByText(Pattern text) {
return getByText(text, null);
}
/**
* Allows locating elements that contain given text.
*
* @param text Text to locate the element for.
*/
Locator getByText(Pattern text, GetByTextOptions options);
/**
* Allows locating elements by their title. For example, this method will find the button by its title "Submit":
*
* @param text Text to locate the element for.
*/
default Locator getByTitle(String text) {
return getByTitle(text, null);
}
/**
* Allows locating elements by their title. For example, this method will find the button by its title "Submit":
*
* @param text Text to locate the element for.
*/
Locator getByTitle(String text, GetByTitleOptions options);
/**
* Allows locating elements by their title. For example, this method will find the button by its title "Submit":
*
* @param text Text to locate the element for.
*/
default Locator getByTitle(Pattern text) {
return getByTitle(text, null);
}
/**
* Allows locating elements by their title. For example, this method will find the button by its title "Submit":
*
* @param text Text to locate the element for.
*/
Locator getByTitle(Pattern text, GetByTitleOptions options);
/**
* Returns locator to the last matching frame.
*/
FrameLocator last();
/**
* The method finds an element matching the specified selector in the FrameLocator's subtree.
* The method finds an element matching the specified selector in the locator's subtree. It also accepts filter options,
* similar to {@link Locator#filter Locator.filter()} method.
*
* <p> <a href="https://playwright.dev/java/docs/locators">Learn more about locators</a>.
*
* @param selector A selector to use when resolving DOM element. See <a href="https://playwright.dev/java/docs/selectors">working with
* selectors</a> for more details.
@@ -118,7 +529,10 @@ public interface FrameLocator {
return locator(selector, null);
}
/**
* The method finds an element matching the specified selector in the FrameLocator's subtree.
* The method finds an element matching the specified selector in the locator's subtree. It also accepts filter options,
* similar to {@link Locator#filter Locator.filter()} method.
*
* <p> <a href="https://playwright.dev/java/docs/locators">Learn more about locators</a>.
*
* @param selector A selector to use when resolving DOM element. See <a href="https://playwright.dev/java/docs/selectors">working with
* selectors</a> for more details.
@@ -57,8 +57,8 @@ public interface JSHandle {
* assertEquals("10 retweets", tweetHandle.evaluate("node => node.innerText"));
* }</pre>
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
*/
default Object evaluate(String expression) {
return evaluate(expression, null);
@@ -78,8 +78,8 @@ public interface JSHandle {
* assertEquals("10 retweets", tweetHandle.evaluate("node => node.innerText"));
* }</pre>
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
Object evaluate(String expression, Object arg);
@@ -97,8 +97,8 @@ public interface JSHandle {
*
* <p> See {@link Page#evaluateHandle Page.evaluateHandle()} for more details.
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
*/
default JSHandle evaluateHandle(String expression) {
return evaluateHandle(expression, null);
@@ -117,8 +117,8 @@ public interface JSHandle {
*
* <p> See {@link Page#evaluateHandle Page.evaluateHandle()} for more details.
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
JSHandle evaluateHandle(String expression, Object arg);
@@ -670,6 +670,226 @@ public interface Locator {
return this;
}
}
class GetByAltTextOptions {
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public Boolean exact;
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public GetByAltTextOptions setExact(boolean exact) {
this.exact = exact;
return this;
}
}
class GetByLabelOptions {
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public Boolean exact;
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public GetByLabelOptions setExact(boolean exact) {
this.exact = exact;
return this;
}
}
class GetByPlaceholderOptions {
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public Boolean exact;
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public GetByPlaceholderOptions setExact(boolean exact) {
this.exact = exact;
return this;
}
}
class GetByRoleOptions {
/**
* An attribute that is usually set by {@code aria-checked} or native {@code <input type=checkbox>} controls. Available values for
* checked are {@code true}, {@code false} and {@code "mixed"}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-checked">{@code aria-checked}</a>.
*/
public Boolean checked;
/**
* A boolean attribute that is usually set by {@code aria-disabled} or {@code disabled}.
*
* <p> <strong>NOTE:</strong> Unlike most other attributes, {@code disabled} is inherited through the DOM hierarchy. Learn more about <a
* href="https://www.w3.org/TR/wai-aria-1.2/#aria-disabled">{@code aria-disabled}</a>.
*/
public Boolean disabled;
/**
* A boolean attribute that is usually set by {@code aria-expanded}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-expanded">{@code aria-expanded}</a>.
*/
public Boolean expanded;
/**
* A boolean attribute that controls whether hidden elements are matched. By default, only non-hidden elements, as <a
* href="https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion">defined by ARIA</a>, are matched by role selector.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-hidden">{@code aria-hidden}</a>.
*/
public Boolean includeHidden;
/**
* A number attribute that is usually present for roles {@code heading}, {@code listitem}, {@code row}, {@code treeitem}, with default values for
* {@code <h1>-<h6>} elements.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-level">{@code aria-level}</a>.
*/
public Integer level;
/**
* A string attribute that matches <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*
* <p> Learn more about <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*/
public Object name;
/**
* An attribute that is usually set by {@code aria-pressed}. Available values for pressed are {@code true}, {@code false} and {@code "mixed"}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-pressed">{@code aria-pressed}</a>.
*/
public Boolean pressed;
/**
* A boolean attribute that is usually set by {@code aria-selected}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-selected">{@code aria-selected}</a>.
*/
public Boolean selected;
/**
* An attribute that is usually set by {@code aria-checked} or native {@code <input type=checkbox>} controls. Available values for
* checked are {@code true}, {@code false} and {@code "mixed"}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-checked">{@code aria-checked}</a>.
*/
public GetByRoleOptions setChecked(boolean checked) {
this.checked = checked;
return this;
}
/**
* A boolean attribute that is usually set by {@code aria-disabled} or {@code disabled}.
*
* <p> <strong>NOTE:</strong> Unlike most other attributes, {@code disabled} is inherited through the DOM hierarchy. Learn more about <a
* href="https://www.w3.org/TR/wai-aria-1.2/#aria-disabled">{@code aria-disabled}</a>.
*/
public GetByRoleOptions setDisabled(boolean disabled) {
this.disabled = disabled;
return this;
}
/**
* A boolean attribute that is usually set by {@code aria-expanded}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-expanded">{@code aria-expanded}</a>.
*/
public GetByRoleOptions setExpanded(boolean expanded) {
this.expanded = expanded;
return this;
}
/**
* A boolean attribute that controls whether hidden elements are matched. By default, only non-hidden elements, as <a
* href="https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion">defined by ARIA</a>, are matched by role selector.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-hidden">{@code aria-hidden}</a>.
*/
public GetByRoleOptions setIncludeHidden(boolean includeHidden) {
this.includeHidden = includeHidden;
return this;
}
/**
* A number attribute that is usually present for roles {@code heading}, {@code listitem}, {@code row}, {@code treeitem}, with default values for
* {@code <h1>-<h6>} elements.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-level">{@code aria-level}</a>.
*/
public GetByRoleOptions setLevel(int level) {
this.level = level;
return this;
}
/**
* A string attribute that matches <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*
* <p> Learn more about <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*/
public GetByRoleOptions setName(String name) {
this.name = name;
return this;
}
/**
* A string attribute that matches <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*
* <p> Learn more about <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*/
public GetByRoleOptions setName(Pattern name) {
this.name = name;
return this;
}
/**
* An attribute that is usually set by {@code aria-pressed}. Available values for pressed are {@code true}, {@code false} and {@code "mixed"}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-pressed">{@code aria-pressed}</a>.
*/
public GetByRoleOptions setPressed(boolean pressed) {
this.pressed = pressed;
return this;
}
/**
* A boolean attribute that is usually set by {@code aria-selected}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-selected">{@code aria-selected}</a>.
*/
public GetByRoleOptions setSelected(boolean selected) {
this.selected = selected;
return this;
}
}
class GetByTextOptions {
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public Boolean exact;
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public GetByTextOptions setExact(boolean exact) {
this.exact = exact;
return this;
}
}
class GetByTitleOptions {
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public Boolean exact;
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public GetByTitleOptions setExact(boolean exact) {
this.exact = exact;
return this;
}
}
class HoverOptions {
/**
* Whether to bypass the <a href="https://playwright.dev/java/docs/actionability">actionability</a> checks. Defaults to
@@ -1899,7 +2119,17 @@ public interface Locator {
*/
void dispatchEvent(String type, Object eventInit, DispatchEventOptions options);
/**
* This method drags the locator to another target locator or target position. It will first move to the source element,
* perform a {@code mousedown}, then move to the target element or position and perform a {@code mouseup}.
* <pre>{@code
* Locator source = page.locator("#source");
* Locator target = page.locator("#target");
*
* source.dragTo(target);
* // or specify exact positions relative to the top-left corners of the elements:
* source.dragTo(target, new Locator.DragToOptions()
* .setSourcePosition(34, 7).setTargetPosition(10, 20));
* }</pre>
*
* @param target Locator of the element to drag to.
*/
@@ -1907,7 +2137,17 @@ public interface Locator {
dragTo(target, null);
}
/**
* This method drags the locator to another target locator or target position. It will first move to the source element,
* perform a {@code mousedown}, then move to the target element or position and perform a {@code mouseup}.
* <pre>{@code
* Locator source = page.locator("#source");
* Locator target = page.locator("#target");
*
* source.dragTo(target);
* // or specify exact positions relative to the top-left corners of the elements:
* source.dragTo(target, new Locator.DragToOptions()
* .setSourcePosition(34, 7).setTargetPosition(10, 20));
* }</pre>
*
* @param target Locator of the element to drag to.
*/
@@ -1943,8 +2183,8 @@ public interface Locator {
* assertEquals("10 retweets", tweets.evaluate("node => node.innerText"));
* }</pre>
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
default Object evaluate(String expression, Object arg) {
@@ -1965,8 +2205,8 @@ public interface Locator {
* assertEquals("10 retweets", tweets.evaluate("node => node.innerText"));
* }</pre>
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
*/
default Object evaluate(String expression) {
return evaluate(expression, null);
@@ -1986,8 +2226,8 @@ public interface Locator {
* assertEquals("10 retweets", tweets.evaluate("node => node.innerText"));
* }</pre>
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
Object evaluate(String expression, Object arg, EvaluateOptions options);
@@ -2005,8 +2245,8 @@ public interface Locator {
* boolean divCounts = (boolean) elements.evaluateAll("(divs, min) => divs.length >= min", 10);
* }</pre>
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
*/
default Object evaluateAll(String expression) {
return evaluateAll(expression, null);
@@ -2025,8 +2265,8 @@ public interface Locator {
* boolean divCounts = (boolean) elements.evaluateAll("(divs, min) => divs.length >= min", 10);
* }</pre>
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
Object evaluateAll(String expression, Object arg);
@@ -2044,8 +2284,8 @@ public interface Locator {
*
* <p> See {@link Page#evaluateHandle Page.evaluateHandle()} for more details.
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
default JSHandle evaluateHandle(String expression, Object arg) {
@@ -2065,8 +2305,8 @@ public interface Locator {
*
* <p> See {@link Page#evaluateHandle Page.evaluateHandle()} for more details.
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
*/
default JSHandle evaluateHandle(String expression) {
return evaluateHandle(expression, null);
@@ -2085,8 +2325,8 @@ public interface Locator {
*
* <p> See {@link Page#evaluateHandle Page.evaluateHandle()} for more details.
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
JSHandle evaluateHandle(String expression, Object arg, EvaluateHandleOptions options);
@@ -2131,7 +2371,7 @@ public interface Locator {
* rowLocator
* .filter(new Locator.FilterOptions().setHasText("text in column 1"))
* .filter(new Locator.FilterOptions().setHas(
* page.locator("button", new Page.LocatorOptions().setHasText("column 2 button"))
* page.getByRole("button", new Page.GetByRoleOptions().setName("column 2 button"))
* ))
* .screenshot();
* }</pre>
@@ -2148,7 +2388,7 @@ public interface Locator {
* rowLocator
* .filter(new Locator.FilterOptions().setHasText("text in column 1"))
* .filter(new Locator.FilterOptions().setHas(
* page.locator("button", new Page.LocatorOptions().setHasText("column 2 button"))
* page.getByRole("button", new Page.GetByRoleOptions().setName("column 2 button"))
* ))
* .screenshot();
* }</pre>
@@ -2172,7 +2412,7 @@ public interface Locator {
* When working with iframes, you can create a frame locator that will enter the iframe and allow selecting elements in
* that iframe:
* <pre>{@code
* Locator locator = page.frameLocator("iframe").locator("text=Submit");
* Locator locator = page.frameLocator("iframe").getByText("Submit");
* locator.click();
* }</pre>
*
@@ -2194,6 +2434,193 @@ public interface Locator {
* @param name Attribute name to get the value for.
*/
String getAttribute(String name, GetAttributeOptions options);
/**
* Allows locating elements by their alt text. For example, this method will find the image by alt text "Castle":
*
* @param text Text to locate the element for.
*/
default Locator getByAltText(String text) {
return getByAltText(text, null);
}
/**
* Allows locating elements by their alt text. For example, this method will find the image by alt text "Castle":
*
* @param text Text to locate the element for.
*/
Locator getByAltText(String text, GetByAltTextOptions options);
/**
* Allows locating elements by their alt text. For example, this method will find the image by alt text "Castle":
*
* @param text Text to locate the element for.
*/
default Locator getByAltText(Pattern text) {
return getByAltText(text, null);
}
/**
* Allows locating elements by their alt text. For example, this method will find the image by alt text "Castle":
*
* @param text Text to locate the element for.
*/
Locator getByAltText(Pattern text, GetByAltTextOptions options);
/**
* Allows locating input elements by the text of the associated label. For example, this method will find the input by
* label text Password in the following DOM:
*
* @param text Text to locate the element for.
*/
default Locator getByLabel(String text) {
return getByLabel(text, null);
}
/**
* Allows locating input elements by the text of the associated label. For example, this method will find the input by
* label text Password in the following DOM:
*
* @param text Text to locate the element for.
*/
Locator getByLabel(String text, GetByLabelOptions options);
/**
* Allows locating input elements by the text of the associated label. For example, this method will find the input by
* label text Password in the following DOM:
*
* @param text Text to locate the element for.
*/
default Locator getByLabel(Pattern text) {
return getByLabel(text, null);
}
/**
* Allows locating input elements by the text of the associated label. For example, this method will find the input by
* label text Password in the following DOM:
*
* @param text Text to locate the element for.
*/
Locator getByLabel(Pattern text, GetByLabelOptions options);
/**
* Allows locating input elements by the placeholder text. For example, this method will find the input by placeholder
* "Country":
*
* @param text Text to locate the element for.
*/
default Locator getByPlaceholder(String text) {
return getByPlaceholder(text, null);
}
/**
* Allows locating input elements by the placeholder text. For example, this method will find the input by placeholder
* "Country":
*
* @param text Text to locate the element for.
*/
Locator getByPlaceholder(String text, GetByPlaceholderOptions options);
/**
* Allows locating input elements by the placeholder text. For example, this method will find the input by placeholder
* "Country":
*
* @param text Text to locate the element for.
*/
default Locator getByPlaceholder(Pattern text) {
return getByPlaceholder(text, null);
}
/**
* Allows locating input elements by the placeholder text. For example, this method will find the input by placeholder
* "Country":
*
* @param text Text to locate the element for.
*/
Locator getByPlaceholder(Pattern text, GetByPlaceholderOptions options);
/**
* Allows locating elements by their <a href="https://www.w3.org/TR/wai-aria-1.2/#roles">ARIA role</a>, <a
* href="https://www.w3.org/TR/wai-aria-1.2/#aria-attributes">ARIA attributes</a> and <a
* href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>. Note that role selector **does not
* replace** accessibility audits and conformance tests, but rather gives early feedback about the ARIA guidelines.
*
* <p> Note that many html elements have an implicitly <a
* href="https://w3c.github.io/html-aam/#html-element-role-mappings">defined role</a> that is recognized by the role
* selector. You can find all the <a href="https://www.w3.org/TR/wai-aria-1.2/#role_definitions">supported roles here</a>.
* ARIA guidelines **do not recommend** duplicating implicit roles and attributes by setting {@code role} and/or {@code aria-*}
* attributes to default values.
*
* @param role Required aria role.
*/
default Locator getByRole(AriaRole role) {
return getByRole(role, null);
}
/**
* Allows locating elements by their <a href="https://www.w3.org/TR/wai-aria-1.2/#roles">ARIA role</a>, <a
* href="https://www.w3.org/TR/wai-aria-1.2/#aria-attributes">ARIA attributes</a> and <a
* href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>. Note that role selector **does not
* replace** accessibility audits and conformance tests, but rather gives early feedback about the ARIA guidelines.
*
* <p> Note that many html elements have an implicitly <a
* href="https://w3c.github.io/html-aam/#html-element-role-mappings">defined role</a> that is recognized by the role
* selector. You can find all the <a href="https://www.w3.org/TR/wai-aria-1.2/#role_definitions">supported roles here</a>.
* ARIA guidelines **do not recommend** duplicating implicit roles and attributes by setting {@code role} and/or {@code aria-*}
* attributes to default values.
*
* @param role Required aria role.
*/
Locator getByRole(AriaRole role, GetByRoleOptions options);
/**
* Locate element by the test id. By default, the {@code data-testid} attribute is used as a test id. Use {@link
* Selectors#setTestIdAttribute Selectors.setTestIdAttribute()} to configure a different test id attribute if necessary.
*
* @param testId Id to locate the element by.
*/
Locator getByTestId(String testId);
/**
* Allows locating elements that contain given text.
*
* @param text Text to locate the element for.
*/
default Locator getByText(String text) {
return getByText(text, null);
}
/**
* Allows locating elements that contain given text.
*
* @param text Text to locate the element for.
*/
Locator getByText(String text, GetByTextOptions options);
/**
* Allows locating elements that contain given text.
*
* @param text Text to locate the element for.
*/
default Locator getByText(Pattern text) {
return getByText(text, null);
}
/**
* Allows locating elements that contain given text.
*
* @param text Text to locate the element for.
*/
Locator getByText(Pattern text, GetByTextOptions options);
/**
* Allows locating elements by their title. For example, this method will find the button by its title "Submit":
*
* @param text Text to locate the element for.
*/
default Locator getByTitle(String text) {
return getByTitle(text, null);
}
/**
* Allows locating elements by their title. For example, this method will find the button by its title "Submit":
*
* @param text Text to locate the element for.
*/
Locator getByTitle(String text, GetByTitleOptions options);
/**
* Allows locating elements by their title. For example, this method will find the button by its title "Submit":
*
* @param text Text to locate the element for.
*/
default Locator getByTitle(Pattern text) {
return getByTitle(text, null);
}
/**
* Allows locating elements by their title. For example, this method will find the button by its title "Submit":
*
* @param text Text to locate the element for.
*/
Locator getByTitle(Pattern text, GetByTitleOptions options);
/**
* Highlight the corresponding element(s) on the screen. Useful for debugging, don't commit the code that uses {@link
* Locator#highlight Locator.highlight()}.
@@ -2340,9 +2767,11 @@ public interface Locator {
*/
Locator last();
/**
* The method finds an element matching the specified selector in the {@code Locator}'s subtree. It also accepts filter options,
* The method finds an element matching the specified selector in the locator's subtree. It also accepts filter options,
* similar to {@link Locator#filter Locator.filter()} method.
*
* <p> <a href="https://playwright.dev/java/docs/locators">Learn more about locators</a>.
*
* @param selector A selector to use when resolving DOM element. See <a href="https://playwright.dev/java/docs/selectors">working with
* selectors</a> for more details.
*/
@@ -2350,9 +2779,11 @@ public interface Locator {
return locator(selector, null);
}
/**
* The method finds an element matching the specified selector in the {@code Locator}'s subtree. It also accepts filter options,
* The method finds an element matching the specified selector in the locator's subtree. It also accepts filter options,
* similar to {@link Locator#filter Locator.filter()} method.
*
* <p> <a href="https://playwright.dev/java/docs/locators">Learn more about locators</a>.
*
* @param selector A selector to use when resolving DOM element. See <a href="https://playwright.dev/java/docs/selectors">working with
* selectors</a> for more details.
*/
@@ -2992,8 +3423,8 @@ public interface Locator {
*
* <p> An example of typing into a text field and then submitting the form:
* <pre>{@code
* Locator element = page.locator("input");
* element.type("some text");
* Locator element = page.getByLabel("Password");
* element.type("my password");
* element.press("Enter");
* }</pre>
*
@@ -3013,8 +3444,8 @@ public interface Locator {
*
* <p> An example of typing into a text field and then submitting the form:
* <pre>{@code
* Locator element = page.locator("input");
* element.type("some text");
* Locator element = page.getByLabel("Password");
* element.type("my password");
* element.press("Enter");
* }</pre>
*
@@ -1142,6 +1142,226 @@ public interface Page extends AutoCloseable {
return this;
}
}
class GetByAltTextOptions {
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public Boolean exact;
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public GetByAltTextOptions setExact(boolean exact) {
this.exact = exact;
return this;
}
}
class GetByLabelOptions {
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public Boolean exact;
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public GetByLabelOptions setExact(boolean exact) {
this.exact = exact;
return this;
}
}
class GetByPlaceholderOptions {
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public Boolean exact;
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public GetByPlaceholderOptions setExact(boolean exact) {
this.exact = exact;
return this;
}
}
class GetByRoleOptions {
/**
* An attribute that is usually set by {@code aria-checked} or native {@code <input type=checkbox>} controls. Available values for
* checked are {@code true}, {@code false} and {@code "mixed"}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-checked">{@code aria-checked}</a>.
*/
public Boolean checked;
/**
* A boolean attribute that is usually set by {@code aria-disabled} or {@code disabled}.
*
* <p> <strong>NOTE:</strong> Unlike most other attributes, {@code disabled} is inherited through the DOM hierarchy. Learn more about <a
* href="https://www.w3.org/TR/wai-aria-1.2/#aria-disabled">{@code aria-disabled}</a>.
*/
public Boolean disabled;
/**
* A boolean attribute that is usually set by {@code aria-expanded}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-expanded">{@code aria-expanded}</a>.
*/
public Boolean expanded;
/**
* A boolean attribute that controls whether hidden elements are matched. By default, only non-hidden elements, as <a
* href="https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion">defined by ARIA</a>, are matched by role selector.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-hidden">{@code aria-hidden}</a>.
*/
public Boolean includeHidden;
/**
* A number attribute that is usually present for roles {@code heading}, {@code listitem}, {@code row}, {@code treeitem}, with default values for
* {@code <h1>-<h6>} elements.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-level">{@code aria-level}</a>.
*/
public Integer level;
/**
* A string attribute that matches <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*
* <p> Learn more about <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*/
public Object name;
/**
* An attribute that is usually set by {@code aria-pressed}. Available values for pressed are {@code true}, {@code false} and {@code "mixed"}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-pressed">{@code aria-pressed}</a>.
*/
public Boolean pressed;
/**
* A boolean attribute that is usually set by {@code aria-selected}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-selected">{@code aria-selected}</a>.
*/
public Boolean selected;
/**
* An attribute that is usually set by {@code aria-checked} or native {@code <input type=checkbox>} controls. Available values for
* checked are {@code true}, {@code false} and {@code "mixed"}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-checked">{@code aria-checked}</a>.
*/
public GetByRoleOptions setChecked(boolean checked) {
this.checked = checked;
return this;
}
/**
* A boolean attribute that is usually set by {@code aria-disabled} or {@code disabled}.
*
* <p> <strong>NOTE:</strong> Unlike most other attributes, {@code disabled} is inherited through the DOM hierarchy. Learn more about <a
* href="https://www.w3.org/TR/wai-aria-1.2/#aria-disabled">{@code aria-disabled}</a>.
*/
public GetByRoleOptions setDisabled(boolean disabled) {
this.disabled = disabled;
return this;
}
/**
* A boolean attribute that is usually set by {@code aria-expanded}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-expanded">{@code aria-expanded}</a>.
*/
public GetByRoleOptions setExpanded(boolean expanded) {
this.expanded = expanded;
return this;
}
/**
* A boolean attribute that controls whether hidden elements are matched. By default, only non-hidden elements, as <a
* href="https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion">defined by ARIA</a>, are matched by role selector.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-hidden">{@code aria-hidden}</a>.
*/
public GetByRoleOptions setIncludeHidden(boolean includeHidden) {
this.includeHidden = includeHidden;
return this;
}
/**
* A number attribute that is usually present for roles {@code heading}, {@code listitem}, {@code row}, {@code treeitem}, with default values for
* {@code <h1>-<h6>} elements.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-level">{@code aria-level}</a>.
*/
public GetByRoleOptions setLevel(int level) {
this.level = level;
return this;
}
/**
* A string attribute that matches <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*
* <p> Learn more about <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*/
public GetByRoleOptions setName(String name) {
this.name = name;
return this;
}
/**
* A string attribute that matches <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*
* <p> Learn more about <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*/
public GetByRoleOptions setName(Pattern name) {
this.name = name;
return this;
}
/**
* An attribute that is usually set by {@code aria-pressed}. Available values for pressed are {@code true}, {@code false} and {@code "mixed"}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-pressed">{@code aria-pressed}</a>.
*/
public GetByRoleOptions setPressed(boolean pressed) {
this.pressed = pressed;
return this;
}
/**
* A boolean attribute that is usually set by {@code aria-selected}.
*
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-selected">{@code aria-selected}</a>.
*/
public GetByRoleOptions setSelected(boolean selected) {
this.selected = selected;
return this;
}
}
class GetByTextOptions {
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public Boolean exact;
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public GetByTextOptions setExact(boolean exact) {
this.exact = exact;
return this;
}
}
class GetByTitleOptions {
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public Boolean exact;
/**
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
* expression.
*/
public GetByTitleOptions setExact(boolean exact) {
this.exact = exact;
return this;
}
}
class GoBackOptions {
/**
* Maximum operation time in milliseconds, defaults to 30 seconds, pass {@code 0} to disable timeout. The default value can be
@@ -3576,7 +3796,14 @@ public interface Page extends AutoCloseable {
*/
void dispatchEvent(String selector, String type, Object eventInit, DispatchEventOptions options);
/**
*
* This method drags the source element to the target element. It will first move to the source element, perform a
* {@code mousedown}, then move to the target element and perform a {@code mouseup}.
* <pre>{@code
* page.dragAndDrop("#source", '#target');
* // or specify exact positions relative to the top-left corners of the elements:
* page.dragAndDrop("#source", '#target', new Page.DragAndDropOptions()
* .setSourcePosition(34, 7).setTargetPosition(10, 20));
* }</pre>
*
* @param source A selector to search for an element to drag. If there are multiple elements satisfying the selector, the first will be
* used. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more details.
@@ -3587,7 +3814,14 @@ public interface Page extends AutoCloseable {
dragAndDrop(source, target, null);
}
/**
*
* This method drags the source element to the target element. It will first move to the source element, perform a
* {@code mousedown}, then move to the target element and perform a {@code mouseup}.
* <pre>{@code
* page.dragAndDrop("#source", '#target');
* // or specify exact positions relative to the top-left corners of the elements:
* page.dragAndDrop("#source", '#target', new Page.DragAndDropOptions()
* .setSourcePosition(34, 7).setTargetPosition(10, 20));
* }</pre>
*
* @param source A selector to search for an element to drag. If there are multiple elements satisfying the selector, the first will be
* used. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more details.
@@ -3683,8 +3917,8 @@ public interface Page extends AutoCloseable {
*
* @param selector A selector to query for. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more
* details.
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
default Object evalOnSelector(String selector, String expression, Object arg) {
@@ -3712,8 +3946,8 @@ public interface Page extends AutoCloseable {
*
* @param selector A selector to query for. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more
* details.
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
*/
default Object evalOnSelector(String selector, String expression) {
return evalOnSelector(selector, expression, null);
@@ -3740,8 +3974,8 @@ public interface Page extends AutoCloseable {
*
* @param selector A selector to query for. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more
* details.
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
Object evalOnSelector(String selector, String expression, Object arg, EvalOnSelectorOptions options);
@@ -3763,8 +3997,8 @@ public interface Page extends AutoCloseable {
*
* @param selector A selector to query for. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more
* details.
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
*/
default Object evalOnSelectorAll(String selector, String expression) {
return evalOnSelectorAll(selector, expression, null);
@@ -3787,8 +4021,8 @@ public interface Page extends AutoCloseable {
*
* @param selector A selector to query for. See <a href="https://playwright.dev/java/docs/selectors">working with selectors</a> for more
* details.
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
Object evalOnSelectorAll(String selector, String expression, Object arg);
@@ -3825,8 +4059,8 @@ public interface Page extends AutoCloseable {
*
* <p> Shortcut for main frame's {@link Frame#evaluate Frame.evaluate()}.
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
*/
default Object evaluate(String expression) {
return evaluate(expression, null);
@@ -3864,8 +4098,8 @@ public interface Page extends AutoCloseable {
*
* <p> Shortcut for main frame's {@link Frame#evaluate Frame.evaluate()}.
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
Object evaluate(String expression, Object arg);
@@ -3896,8 +4130,8 @@ public interface Page extends AutoCloseable {
* resultHandle.dispose();
* }</pre>
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
*/
default JSHandle evaluateHandle(String expression) {
return evaluateHandle(expression, null);
@@ -3929,8 +4163,8 @@ public interface Page extends AutoCloseable {
* resultHandle.dispose();
* }</pre>
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
JSHandle evaluateHandle(String expression, Object arg);
@@ -4208,7 +4442,7 @@ public interface Page extends AutoCloseable {
* that iframe. Following snippet locates element with text "Submit" in the iframe with id {@code my-frame}, like {@code <iframe
* id="my-frame">}:
* <pre>{@code
* Locator locator = page.frameLocator("#my-iframe").locator("text=Submit");
* Locator locator = page.frameLocator("#my-iframe").getByText("Submit");
* locator.click();
* }</pre>
*
@@ -4238,6 +4472,193 @@ public interface Page extends AutoCloseable {
* @param name Attribute name to get the value for.
*/
String getAttribute(String selector, String name, GetAttributeOptions options);
/**
* Allows locating elements by their alt text. For example, this method will find the image by alt text "Castle":
*
* @param text Text to locate the element for.
*/
default Locator getByAltText(String text) {
return getByAltText(text, null);
}
/**
* Allows locating elements by their alt text. For example, this method will find the image by alt text "Castle":
*
* @param text Text to locate the element for.
*/
Locator getByAltText(String text, GetByAltTextOptions options);
/**
* Allows locating elements by their alt text. For example, this method will find the image by alt text "Castle":
*
* @param text Text to locate the element for.
*/
default Locator getByAltText(Pattern text) {
return getByAltText(text, null);
}
/**
* Allows locating elements by their alt text. For example, this method will find the image by alt text "Castle":
*
* @param text Text to locate the element for.
*/
Locator getByAltText(Pattern text, GetByAltTextOptions options);
/**
* Allows locating input elements by the text of the associated label. For example, this method will find the input by
* label text Password in the following DOM:
*
* @param text Text to locate the element for.
*/
default Locator getByLabel(String text) {
return getByLabel(text, null);
}
/**
* Allows locating input elements by the text of the associated label. For example, this method will find the input by
* label text Password in the following DOM:
*
* @param text Text to locate the element for.
*/
Locator getByLabel(String text, GetByLabelOptions options);
/**
* Allows locating input elements by the text of the associated label. For example, this method will find the input by
* label text Password in the following DOM:
*
* @param text Text to locate the element for.
*/
default Locator getByLabel(Pattern text) {
return getByLabel(text, null);
}
/**
* Allows locating input elements by the text of the associated label. For example, this method will find the input by
* label text Password in the following DOM:
*
* @param text Text to locate the element for.
*/
Locator getByLabel(Pattern text, GetByLabelOptions options);
/**
* Allows locating input elements by the placeholder text. For example, this method will find the input by placeholder
* "Country":
*
* @param text Text to locate the element for.
*/
default Locator getByPlaceholder(String text) {
return getByPlaceholder(text, null);
}
/**
* Allows locating input elements by the placeholder text. For example, this method will find the input by placeholder
* "Country":
*
* @param text Text to locate the element for.
*/
Locator getByPlaceholder(String text, GetByPlaceholderOptions options);
/**
* Allows locating input elements by the placeholder text. For example, this method will find the input by placeholder
* "Country":
*
* @param text Text to locate the element for.
*/
default Locator getByPlaceholder(Pattern text) {
return getByPlaceholder(text, null);
}
/**
* Allows locating input elements by the placeholder text. For example, this method will find the input by placeholder
* "Country":
*
* @param text Text to locate the element for.
*/
Locator getByPlaceholder(Pattern text, GetByPlaceholderOptions options);
/**
* Allows locating elements by their <a href="https://www.w3.org/TR/wai-aria-1.2/#roles">ARIA role</a>, <a
* href="https://www.w3.org/TR/wai-aria-1.2/#aria-attributes">ARIA attributes</a> and <a
* href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>. Note that role selector **does not
* replace** accessibility audits and conformance tests, but rather gives early feedback about the ARIA guidelines.
*
* <p> Note that many html elements have an implicitly <a
* href="https://w3c.github.io/html-aam/#html-element-role-mappings">defined role</a> that is recognized by the role
* selector. You can find all the <a href="https://www.w3.org/TR/wai-aria-1.2/#role_definitions">supported roles here</a>.
* ARIA guidelines **do not recommend** duplicating implicit roles and attributes by setting {@code role} and/or {@code aria-*}
* attributes to default values.
*
* @param role Required aria role.
*/
default Locator getByRole(AriaRole role) {
return getByRole(role, null);
}
/**
* Allows locating elements by their <a href="https://www.w3.org/TR/wai-aria-1.2/#roles">ARIA role</a>, <a
* href="https://www.w3.org/TR/wai-aria-1.2/#aria-attributes">ARIA attributes</a> and <a
* href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>. Note that role selector **does not
* replace** accessibility audits and conformance tests, but rather gives early feedback about the ARIA guidelines.
*
* <p> Note that many html elements have an implicitly <a
* href="https://w3c.github.io/html-aam/#html-element-role-mappings">defined role</a> that is recognized by the role
* selector. You can find all the <a href="https://www.w3.org/TR/wai-aria-1.2/#role_definitions">supported roles here</a>.
* ARIA guidelines **do not recommend** duplicating implicit roles and attributes by setting {@code role} and/or {@code aria-*}
* attributes to default values.
*
* @param role Required aria role.
*/
Locator getByRole(AriaRole role, GetByRoleOptions options);
/**
* Locate element by the test id. By default, the {@code data-testid} attribute is used as a test id. Use {@link
* Selectors#setTestIdAttribute Selectors.setTestIdAttribute()} to configure a different test id attribute if necessary.
*
* @param testId Id to locate the element by.
*/
Locator getByTestId(String testId);
/**
* Allows locating elements that contain given text.
*
* @param text Text to locate the element for.
*/
default Locator getByText(String text) {
return getByText(text, null);
}
/**
* Allows locating elements that contain given text.
*
* @param text Text to locate the element for.
*/
Locator getByText(String text, GetByTextOptions options);
/**
* Allows locating elements that contain given text.
*
* @param text Text to locate the element for.
*/
default Locator getByText(Pattern text) {
return getByText(text, null);
}
/**
* Allows locating elements that contain given text.
*
* @param text Text to locate the element for.
*/
Locator getByText(Pattern text, GetByTextOptions options);
/**
* Allows locating elements by their title. For example, this method will find the button by its title "Submit":
*
* @param text Text to locate the element for.
*/
default Locator getByTitle(String text) {
return getByTitle(text, null);
}
/**
* Allows locating elements by their title. For example, this method will find the button by its title "Submit":
*
* @param text Text to locate the element for.
*/
Locator getByTitle(String text, GetByTitleOptions options);
/**
* Allows locating elements by their title. For example, this method will find the button by its title "Submit":
*
* @param text Text to locate the element for.
*/
default Locator getByTitle(Pattern text) {
return getByTitle(text, null);
}
/**
* Allows locating elements by their title. For example, this method will find the button by its title "Submit":
*
* @param text Text to locate the element for.
*/
Locator getByTitle(Pattern text, GetByTitleOptions options);
/**
* Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the
* last redirect. If can not go back, returns {@code null}.
@@ -4540,14 +4961,12 @@ public interface Page extends AutoCloseable {
boolean isVisible(String selector, IsVisibleOptions options);
Keyboard keyboard();
/**
* The method returns an element locator that can be used to perform actions on the page. Locator is resolved to the
* element immediately before performing an action, so a series of actions on the same locator can in fact be performed on
* different DOM elements. That would happen if the DOM structure between those actions has changed.
* The method returns an element locator that can be used to perform actions on this page / frame. Locator is resolved to
* the element immediately before performing an action, so a series of actions on the same locator can in fact be performed
* on different DOM elements. That would happen if the DOM structure between those actions has changed.
*
* <p> <a href="https://playwright.dev/java/docs/locators">Learn more about locators</a>.
*
* <p> Shortcut for main frame's {@link Frame#locator Frame.locator()}.
*
* @param selector A selector to use when resolving DOM element. See <a href="https://playwright.dev/java/docs/selectors">working with
* selectors</a> for more details.
*/
@@ -4555,14 +4974,12 @@ public interface Page extends AutoCloseable {
return locator(selector, null);
}
/**
* The method returns an element locator that can be used to perform actions on the page. Locator is resolved to the
* element immediately before performing an action, so a series of actions on the same locator can in fact be performed on
* different DOM elements. That would happen if the DOM structure between those actions has changed.
* The method returns an element locator that can be used to perform actions on this page / frame. Locator is resolved to
* the element immediately before performing an action, so a series of actions on the same locator can in fact be performed
* on different DOM elements. That would happen if the DOM structure between those actions has changed.
*
* <p> <a href="https://playwright.dev/java/docs/locators">Learn more about locators</a>.
*
* <p> Shortcut for main frame's {@link Frame#locator Frame.locator()}.
*
* @param selector A selector to use when resolving DOM element. See <a href="https://playwright.dev/java/docs/selectors">working with
* selectors</a> for more details.
*/
@@ -6106,8 +6523,8 @@ public interface Page extends AutoCloseable {
*
* <p> Shortcut for main frame's {@link Frame#waitForFunction Frame.waitForFunction()}.
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
default JSHandle waitForFunction(String expression, Object arg) {
@@ -6142,8 +6559,8 @@ public interface Page extends AutoCloseable {
*
* <p> Shortcut for main frame's {@link Frame#waitForFunction Frame.waitForFunction()}.
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
*/
default JSHandle waitForFunction(String expression) {
return waitForFunction(expression, null);
@@ -6177,8 +6594,8 @@ public interface Page extends AutoCloseable {
*
* <p> Shortcut for main frame's {@link Frame#waitForFunction Frame.waitForFunction()}.
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
JSHandle waitForFunction(String expression, Object arg, WaitForFunctionOptions options);
@@ -6188,12 +6605,12 @@ public interface Page extends AutoCloseable {
* <p> This resolves when the page reaches a required load state, {@code load} by default. The navigation must have been committed
* when this method is called. If current document has already reached the required state, resolves immediately.
* <pre>{@code
* page.click("button"); // Click triggers navigation.
* page.getByRole("button").click(); // Click triggers navigation.
* page.waitForLoadState(); // The promise resolves after "load" event.
* }</pre>
* <pre>{@code
* Page popup = page.waitForPopup(() -> {
* page.click("button"); // Click triggers a popup.
* page.getByRole("button").click(); // Click triggers a popup.
* });
* popup.waitForLoadState(LoadState.DOMCONTENTLOADED);
* System.out.println(popup.title()); // Popup is ready to use.
@@ -6218,12 +6635,12 @@ public interface Page extends AutoCloseable {
* <p> This resolves when the page reaches a required load state, {@code load} by default. The navigation must have been committed
* when this method is called. If current document has already reached the required state, resolves immediately.
* <pre>{@code
* page.click("button"); // Click triggers navigation.
* page.getByRole("button").click(); // Click triggers navigation.
* page.waitForLoadState(); // The promise resolves after "load" event.
* }</pre>
* <pre>{@code
* Page popup = page.waitForPopup(() -> {
* page.click("button"); // Click triggers a popup.
* page.getByRole("button").click(); // Click triggers a popup.
* });
* popup.waitForLoadState(LoadState.DOMCONTENTLOADED);
* System.out.println(popup.title()); // Popup is ready to use.
@@ -6240,12 +6657,12 @@ public interface Page extends AutoCloseable {
* <p> This resolves when the page reaches a required load state, {@code load} by default. The navigation must have been committed
* when this method is called. If current document has already reached the required state, resolves immediately.
* <pre>{@code
* page.click("button"); // Click triggers navigation.
* page.getByRole("button").click(); // Click triggers navigation.
* page.waitForLoadState(); // The promise resolves after "load" event.
* }</pre>
* <pre>{@code
* Page popup = page.waitForPopup(() -> {
* page.click("button"); // Click triggers a popup.
* page.getByRole("button").click(); // Click triggers a popup.
* });
* popup.waitForLoadState(LoadState.DOMCONTENTLOADED);
* System.out.println(popup.title()); // Popup is ready to use.
@@ -177,5 +177,12 @@ public interface Selectors {
* @param script Script that evaluates to a selector engine instance. The script is evaluated in the page context.
*/
void register(String name, Path script, RegisterOptions options);
/**
* Defines custom attribute name to be used in {@link Page#getByTestId Page.getByTestId()}. {@code data-testid} is used by
* default.
*
* @param attributeName Test id attribute name.
*/
void setTestIdAttribute(String attributeName);
}
@@ -192,7 +192,7 @@ public interface Tracing {
* page.navigate("https://playwright.dev");
*
* context.tracing().startChunk();
* page.locator("text=Get Started").click();
* page.getByText("Get Started").click();
* // Everything between startChunk and stopChunk will be recorded in the trace.
* context.tracing().stopChunk(new Tracing.StopChunkOptions()
* .setPath(Paths.get("trace1.zip")));
@@ -219,7 +219,7 @@ public interface Tracing {
* page.navigate("https://playwright.dev");
*
* context.tracing().startChunk();
* page.locator("text=Get Started").click();
* page.getByText("Get Started").click();
* // Everything between startChunk and stopChunk will be recorded in the trace.
* context.tracing().stopChunk(new Tracing.StopChunkOptions()
* .setPath(Paths.get("trace1.zip")));
@@ -71,8 +71,8 @@ public interface Worker {
* Worker#evaluate Worker.evaluate()} returns {@code undefined}. Playwright also supports transferring some additional values
* that are not serializable by {@code JSON}: {@code -0}, {@code NaN}, {@code Infinity}, {@code -Infinity}.
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
*/
default Object evaluate(String expression) {
return evaluate(expression, null);
@@ -88,8 +88,8 @@ public interface Worker {
* Worker#evaluate Worker.evaluate()} returns {@code undefined}. Playwright also supports transferring some additional values
* that are not serializable by {@code JSON}: {@code -0}, {@code NaN}, {@code Infinity}, {@code -Infinity}.
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
Object evaluate(String expression, Object arg);
@@ -103,8 +103,8 @@ public interface Worker {
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then {@link
* Worker#evaluateHandle Worker.evaluateHandle()} would wait for the promise to resolve and return its value.
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
*/
default JSHandle evaluateHandle(String expression) {
return evaluateHandle(expression, null);
@@ -119,8 +119,8 @@ public interface Worker {
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then {@link
* Worker#evaluateHandle Worker.evaluateHandle()} would wait for the promise to resolve and return its value.
*
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
* as a function. Otherwise, evaluated as an expression.
* @param expression JavaScript expression to be evaluated in the browser context. If the expresion evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
*/
JSHandle evaluateHandle(String expression, Object arg);
@@ -31,7 +31,7 @@ import java.util.regex.Pattern;
* @Test
* void statusBecomesSubmitted() {
* ...
* page.locator("#submit-button").click();
* page.getByRole("button").click();
* assertThat(page.locator(".status")).hasText("Submitted");
* }
* }
@@ -369,7 +369,7 @@ public interface LocatorAssertions {
/**
* Ensures the {@code Locator} points to a checked input.
* <pre>{@code
* assertThat(page.locator(".subscribe")).isChecked();
* assertThat(page.getByLabel("Subscribe to newsletter")).isChecked();
* }</pre>
*/
default void isChecked() {
@@ -378,7 +378,7 @@ public interface LocatorAssertions {
/**
* Ensures the {@code Locator} points to a checked input.
* <pre>{@code
* assertThat(page.locator(".subscribe")).isChecked();
* assertThat(page.getByLabel("Subscribe to newsletter")).isChecked();
* }</pre>
*/
void isChecked(IsCheckedOptions options);
@@ -409,7 +409,7 @@ public interface LocatorAssertions {
/**
* Ensures the {@code Locator} points to an editable element.
* <pre>{@code
* assertThat(page.locator("input")).isEditable();
* assertThat(page.getByRole("textbox")).isEditable();
* }</pre>
*/
default void isEditable() {
@@ -418,7 +418,7 @@ public interface LocatorAssertions {
/**
* Ensures the {@code Locator} points to an editable element.
* <pre>{@code
* assertThat(page.locator("input")).isEditable();
* assertThat(page.getByRole("textbox")).isEditable();
* }</pre>
*/
void isEditable(IsEditableOptions options);
@@ -457,7 +457,7 @@ public interface LocatorAssertions {
/**
* Ensures the {@code Locator} points to a focused DOM node.
* <pre>{@code
* assertThat(page.locator("input")).isFocused();
* assertThat(page.getByRole("textbox")).isFocused();
* }</pre>
*/
default void isFocused() {
@@ -466,7 +466,7 @@ public interface LocatorAssertions {
/**
* Ensures the {@code Locator} points to a focused DOM node.
* <pre>{@code
* assertThat(page.locator("input")).isFocused();
* assertThat(page.getByRole("textbox")).isFocused();
* }</pre>
*/
void isFocused(IsFocusedOptions options);
@@ -489,7 +489,7 @@ public interface LocatorAssertions {
*/
void isHidden(IsHiddenOptions options);
/**
* Ensures that {@code Locator} points to an <a href="https://playwright.dev/java/docs/api/actionability#visible">attached</a>
* Ensures that {@code Locator} points to an <a href="https://playwright.dev/java/docs/api/actionability#attached">attached</a>
* and <a href="https://playwright.dev/java/docs/api/actionability#visible">visible</a> DOM node.
* <pre>{@code
* assertThat(page.locator(".my-element")).isVisible();
@@ -499,7 +499,7 @@ public interface LocatorAssertions {
isVisible(null);
}
/**
* Ensures that {@code Locator} points to an <a href="https://playwright.dev/java/docs/api/actionability#visible">attached</a>
* Ensures that {@code Locator} points to an <a href="https://playwright.dev/java/docs/api/actionability#attached">attached</a>
* and <a href="https://playwright.dev/java/docs/api/actionability#visible">visible</a> DOM node.
* <pre>{@code
* assertThat(page.locator(".my-element")).isVisible();
@@ -997,7 +997,7 @@ public interface LocatorAssertions {
/**
* Ensures the {@code Locator} resolves to an element with the given computed CSS style.
* <pre>{@code
* assertThat(page.locator("button")).hasCSS("display", "flex");
* assertThat(page.getByRole("button")).hasCSS("display", "flex");
* }</pre>
*
* @param name CSS property name.
@@ -1009,7 +1009,7 @@ public interface LocatorAssertions {
/**
* Ensures the {@code Locator} resolves to an element with the given computed CSS style.
* <pre>{@code
* assertThat(page.locator("button")).hasCSS("display", "flex");
* assertThat(page.getByRole("button")).hasCSS("display", "flex");
* }</pre>
*
* @param name CSS property name.
@@ -1019,7 +1019,7 @@ public interface LocatorAssertions {
/**
* Ensures the {@code Locator} resolves to an element with the given computed CSS style.
* <pre>{@code
* assertThat(page.locator("button")).hasCSS("display", "flex");
* assertThat(page.getByRole("button")).hasCSS("display", "flex");
* }</pre>
*
* @param name CSS property name.
@@ -1031,7 +1031,7 @@ public interface LocatorAssertions {
/**
* Ensures the {@code Locator} resolves to an element with the given computed CSS style.
* <pre>{@code
* assertThat(page.locator("button")).hasCSS("display", "flex");
* assertThat(page.getByRole("button")).hasCSS("display", "flex");
* }</pre>
*
* @param name CSS property name.
@@ -1041,7 +1041,7 @@ public interface LocatorAssertions {
/**
* Ensures the {@code Locator} points to an element with the given DOM Node ID.
* <pre>{@code
* assertThat(page.locator("input")).hasId("lastname");
* assertThat(page.getByRole("textbox")).hasId("lastname");
* }</pre>
*
* @param id Element id.
@@ -1052,7 +1052,7 @@ public interface LocatorAssertions {
/**
* Ensures the {@code Locator} points to an element with the given DOM Node ID.
* <pre>{@code
* assertThat(page.locator("input")).hasId("lastname");
* assertThat(page.getByRole("textbox")).hasId("lastname");
* }</pre>
*
* @param id Element id.
@@ -1061,7 +1061,7 @@ public interface LocatorAssertions {
/**
* Ensures the {@code Locator} points to an element with the given DOM Node ID.
* <pre>{@code
* assertThat(page.locator("input")).hasId("lastname");
* assertThat(page.getByRole("textbox")).hasId("lastname");
* }</pre>
*
* @param id Element id.
@@ -1072,7 +1072,7 @@ public interface LocatorAssertions {
/**
* Ensures the {@code Locator} points to an element with the given DOM Node ID.
* <pre>{@code
* assertThat(page.locator("input")).hasId("lastname");
* assertThat(page.getByRole("textbox")).hasId("lastname");
* }</pre>
*
* @param id Element id.
@@ -31,7 +31,7 @@ import java.util.regex.Pattern;
* @Test
* void navigatesToLoginPage() {
* ...
* page.locator("#login").click();
* page.getByText("Sign in").click();
* assertThat(page).hasURL(Pattern.compile(".*\/login"));
* }
* }
@@ -83,9 +83,9 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
headers.addProperty("x-playwright-browser", name());
}
JsonObject json = sendMessage("connect", params).getAsJsonObject();
JsonObject json = connection.localUtils().sendMessage("connect", params).getAsJsonObject();
JsonPipe pipe = connection.getExistingObject(json.getAsJsonObject("pipe").get("guid").getAsString());
Connection connection = new Connection(pipe, this.connection.env);
Connection connection = new Connection(pipe, this.connection.env, this.connection.localUtils);
PlaywrightImpl playwright = connection.initializePlaywright();
if (!playwright.initializer.has("preLaunchedBrowser")) {
try {
@@ -80,6 +80,11 @@ public class Connection {
}
}
Connection(Transport pipe, Map<String, String> env, LocalUtils localUtils) {
this(pipe, env);
this.localUtils = localUtils;
}
Connection(Transport transport, Map<String, String> env) {
this.env = env;
if (isLogging) {
@@ -283,8 +288,10 @@ public class Connection {
result = new JsonPipe(parent, type, guid, initializer);
break;
case "LocalUtils":
localUtils = new LocalUtils(parent, type, guid, initializer);
result = localUtils;
result = new LocalUtils(parent, type, guid, initializer);
if (localUtils == null) {
localUtils = (LocalUtils) result;
}
break;
case "Page":
result = new PageImpl(parent, type, guid, initializer);
@@ -31,6 +31,7 @@ import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import static com.microsoft.playwright.impl.LocatorUtils.*;
import static com.microsoft.playwright.impl.Utils.*;
import static com.microsoft.playwright.options.WaitUntilState.*;
import static com.microsoft.playwright.impl.Serialization.*;
@@ -373,6 +374,66 @@ public class FrameImpl extends ChannelOwner implements Frame {
return withLogging("Frame.getAttribute", () -> getAttributeImpl(selector, name, options));
}
@Override
public Locator getByAltText(String text, GetByAltTextOptions options) {
return locator(getByAltTextSelector(text, convertType(options, Locator.GetByAltTextOptions.class)));
}
@Override
public Locator getByAltText(Pattern text, GetByAltTextOptions options) {
return locator(getByAltTextSelector(text, convertType(options, Locator.GetByAltTextOptions.class)));
}
@Override
public Locator getByLabel(String text, GetByLabelOptions options) {
return locator(getByLabelSelector(text, convertType(options, Locator.GetByLabelOptions.class)));
}
@Override
public Locator getByLabel(Pattern text, GetByLabelOptions options) {
return locator(getByLabelSelector(text, convertType(options, Locator.GetByLabelOptions.class)));
}
@Override
public Locator getByPlaceholder(String text, GetByPlaceholderOptions options) {
return locator(getByPlaceholderSelector(text, convertType(options, Locator.GetByPlaceholderOptions.class)));
}
@Override
public Locator getByPlaceholder(Pattern text, GetByPlaceholderOptions options) {
return locator(getByPlaceholderSelector(text, convertType(options, Locator.GetByPlaceholderOptions.class)));
}
@Override
public Locator getByRole(AriaRole role, GetByRoleOptions options) {
return locator(getByRoleSelector(role, convertType(options, Locator.GetByRoleOptions.class)));
}
@Override
public Locator getByTestId(String testId) {
return locator(getByTestIdSelector(testId));
}
@Override
public Locator getByText(String text, GetByTextOptions options) {
return locator(getByTextSelector(text, convertType(options, Locator.GetByTextOptions.class)));
}
@Override
public Locator getByText(Pattern text, GetByTextOptions options) {
return locator(getByTextSelector(text, convertType(options, Locator.GetByTextOptions.class)));
}
@Override
public Locator getByTitle(String text, GetByTitleOptions options) {
return locator(getByTitleSelector(text, convertType(options, Locator.GetByTitleOptions.class)));
}
@Override
public Locator getByTitle(Pattern text, GetByTitleOptions options) {
return locator(getByTitleSelector(text, convertType(options, Locator.GetByTitleOptions.class)));
}
String getAttributeImpl(String selector, String name, GetAttributeOptions options) {
if (options == null) {
options = new GetAttributeOptions();
@@ -18,7 +18,11 @@ package com.microsoft.playwright.impl;
import com.microsoft.playwright.FrameLocator;
import com.microsoft.playwright.Locator;
import com.microsoft.playwright.options.AriaRole;
import java.util.regex.Pattern;
import static com.microsoft.playwright.impl.LocatorUtils.*;
import static com.microsoft.playwright.impl.Utils.convertType;
class FrameLocatorImpl implements FrameLocator {
@@ -37,7 +41,67 @@ class FrameLocatorImpl implements FrameLocator {
@Override
public FrameLocatorImpl frameLocator(String selector) {
return new FrameLocatorImpl(frame, frameSelector + " >> control=enter-frame >> " + selector);
return new FrameLocatorImpl(frame, frameSelector + " >> internal:control=enter-frame >> " + selector);
}
@Override
public Locator getByAltText(String text, GetByAltTextOptions options) {
return locator(getByAltTextSelector(text, convertType(options, Locator.GetByAltTextOptions.class)));
}
@Override
public Locator getByAltText(Pattern text, GetByAltTextOptions options) {
return locator(getByAltTextSelector(text, convertType(options, Locator.GetByAltTextOptions.class)));
}
@Override
public Locator getByLabel(String text, GetByLabelOptions options) {
return locator(getByLabelSelector(text, convertType(options, Locator.GetByLabelOptions.class)));
}
@Override
public Locator getByLabel(Pattern text, GetByLabelOptions options) {
return locator(getByLabelSelector(text, convertType(options, Locator.GetByLabelOptions.class)));
}
@Override
public Locator getByPlaceholder(String text, GetByPlaceholderOptions options) {
return locator(getByPlaceholderSelector(text, convertType(options, Locator.GetByPlaceholderOptions.class)));
}
@Override
public Locator getByPlaceholder(Pattern text, GetByPlaceholderOptions options) {
return locator(getByPlaceholderSelector(text, convertType(options, Locator.GetByPlaceholderOptions.class)));
}
@Override
public Locator getByRole(AriaRole role, GetByRoleOptions options) {
return locator(getByRoleSelector(role, convertType(options, Locator.GetByRoleOptions.class)));
}
@Override
public Locator getByTestId(String testId) {
return locator(getByTestIdSelector(testId));
}
@Override
public Locator getByText(String text, GetByTextOptions options) {
return locator(getByTextSelector(text, convertType(options, Locator.GetByTextOptions.class)));
}
@Override
public Locator getByText(Pattern text, GetByTextOptions options) {
return locator(getByTextSelector(text, convertType(options, Locator.GetByTextOptions.class)));
}
@Override
public Locator getByTitle(String text, GetByTitleOptions options) {
return locator(getByTitleSelector(text, convertType(options, Locator.GetByTitleOptions.class)));
}
@Override
public Locator getByTitle(Pattern text, GetByTitleOptions options) {
return locator(getByTitleSelector(text, convertType(options, Locator.GetByTitleOptions.class)));
}
@Override
@@ -47,7 +111,7 @@ class FrameLocatorImpl implements FrameLocator {
@Override
public Locator locator(String selector, LocatorOptions options) {
return new LocatorImpl(frame, frameSelector + " >> control=enter-frame >> " + selector, convertType(options, Locator.LocatorOptions.class));
return new LocatorImpl(frame, frameSelector + " >> internal:control=enter-frame >> " + selector, convertType(options, Locator.LocatorOptions.class));
}
@Override
@@ -3,10 +3,7 @@ package com.microsoft.playwright.impl;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.microsoft.playwright.*;
import com.microsoft.playwright.options.BoundingBox;
import com.microsoft.playwright.options.FilePayload;
import com.microsoft.playwright.options.SelectOption;
import com.microsoft.playwright.options.WaitForSelectorState;
import com.microsoft.playwright.options.*;
import java.lang.reflect.Field;
import java.nio.file.Path;
@@ -16,6 +13,7 @@ import java.util.Map;
import java.util.function.BiFunction;
import java.util.regex.Pattern;
import static com.microsoft.playwright.impl.LocatorUtils.*;
import static com.microsoft.playwright.impl.Serialization.gson;
import static com.microsoft.playwright.impl.Utils.convertType;
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
@@ -24,57 +22,19 @@ class LocatorImpl implements Locator {
private final FrameImpl frame;
private final String selector;
private static class Filters {
private final Map<Field, String> filterFieldToEngine = new LinkedHashMap<>();
private void addFilter(String name, String engine) throws NoSuchFieldException {
filterFieldToEngine.put(LocatorOptions.class.getField(name), engine);
}
{
try {
addFilter("has", "has");
// addFilter("leftOf", "left-of");
// addFilter("rightOf", "right-of");
// addFilter("above", "above");
// addFilter("below", "below");
// addFilter("near", "near");
} catch (NoSuchFieldException e) {
throw new InternalError(e);
}
}
String addFiltersToSelector(String selector, LocatorOptions options, Frame frame) {
try {
for (Map.Entry<Field, String> p : filterFieldToEngine.entrySet()) {
LocatorImpl filter = (LocatorImpl) p.getKey().get(options);
if (filter == null) {
continue;
}
if (filter.frame != frame) {
throw new PlaywrightException("Inner '" + p.getKey().getName() + "' locator must belong to the same frame.");
}
selector += " >> " + p.getValue() + "=" + gson().toJson(filter.selector);
}
} catch (IllegalAccessException e) {
throw new PlaywrightException("Unexpected options", e);
}
return selector;
}
}
private static final Filters filters = new Filters();
public LocatorImpl(FrameImpl frame, String selector, LocatorOptions options) {
this.frame = frame;
if (options != null) {
if (options.hasText != null) {
if (options.hasText instanceof Pattern) {
Pattern pattern = (Pattern) options.hasText;
String jsRegex = "/" + pattern.pattern() + "/" + toJsRegexFlags(pattern);
selector += " >> has=" + gson().toJson("text=" + jsRegex);
} else if (options.hasText instanceof String) {
String text = (String) options.hasText;
selector += " >> :scope:has-text(" + escapeWithQuotes(text) + ")";
}
String textSelector = "text=" + escapeForTextSelector(options.hasText, false);
selector += " >> internal:has=" + gson().toJson(textSelector);
}
if (options.has != null) {
LocatorImpl locator = (LocatorImpl) options.has;
if (locator.frame != frame)
throw new Error("Inner 'has' locator must belong to the same frame.");
selector += " >> internal:has=" + gson().toJson(locator.selector);
}
selector = filters.addFiltersToSelector(selector, options, frame);
}
this.selector = selector;
}
@@ -234,6 +194,66 @@ class LocatorImpl implements Locator {
return frame.getAttribute(selector, name, convertType(options, Frame.GetAttributeOptions.class).setStrict(true));
}
@Override
public Locator getByAltText(String text, GetByAltTextOptions options) {
return locator(getByAltTextSelector(text, options));
}
@Override
public Locator getByAltText(Pattern text, GetByAltTextOptions options) {
return locator(getByAltTextSelector(text, options));
}
@Override
public Locator getByLabel(String text, GetByLabelOptions options) {
return locator(getByLabelSelector(text, options));
}
@Override
public Locator getByLabel(Pattern text, GetByLabelOptions options) {
return locator(getByLabelSelector(text, options));
}
@Override
public Locator getByPlaceholder(String text, GetByPlaceholderOptions options) {
return locator(getByPlaceholderSelector(text, options));
}
@Override
public Locator getByPlaceholder(Pattern text, GetByPlaceholderOptions options) {
return locator(getByPlaceholderSelector(text, options));
}
@Override
public Locator getByRole(AriaRole role, GetByRoleOptions options) {
return null;
}
@Override
public Locator getByTestId(String testId) {
return locator(getByTestIdSelector(testId));
}
@Override
public Locator getByText(String text, GetByTextOptions options) {
return locator(getByTextSelector(text, options));
}
@Override
public Locator getByText(Pattern text, GetByTextOptions options) {
return locator(getByTextSelector(text, options));
}
@Override
public Locator getByTitle(String text, GetByTitleOptions options) {
return locator(getByTitleSelector(text, options));
}
@Override
public Locator getByTitle(Pattern text, GetByTitleOptions options) {
return locator(getByTitleSelector(text, options));
}
@Override
public void highlight() {
frame.highlightImpl(selector);
@@ -0,0 +1,132 @@
package com.microsoft.playwright.impl;
import com.microsoft.playwright.Locator;
import com.microsoft.playwright.options.AriaRole;
import java.util.regex.Pattern;
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
public class LocatorUtils {
private static volatile String testIdAttributeName = "data-testid";;
static void setTestIdAttributeName(String name) {
testIdAttributeName = name;
}
static String getByTextSelector(String text, Locator.GetByTextOptions options) {
boolean exact = options != null && options.exact != null && options.exact;
return "text=" + escapeForTextSelector(text, exact);
}
static String getByTextSelector(Pattern text, Locator.GetByTextOptions options) {
boolean exact = options != null && options.exact != null && options.exact;
return "text=" + escapeForTextSelector(text, exact);
}
static String getByLabelSelector(Object text, Locator.GetByLabelOptions options) {
boolean exact = options != null && options.exact != null && options.exact;
return "internal:label=" + escapeForTextSelector(text, exact);
}
private static String getByAttributeTextSelector(String attrName, Object value, boolean exact) {
if (value instanceof Pattern) {
return "internal:attr=[" + attrName + "=" + toJsRegExp((Pattern) value) + "]";
}
return "internal:attr=[" + attrName + "=" + escapeForAttributeSelector((String) value, exact) + "]";
}
static String getByTestIdSelector(String testId) {
return getByAttributeTextSelector(testIdAttributeName, testId, true);
}
static String getByAltTextSelector(Object text, Locator.GetByAltTextOptions options) {
boolean exact = options != null && options.exact != null && options.exact;
return getByAttributeTextSelector("alt", text, exact);
}
static String getByTitleSelector(Object text, Locator.GetByTitleOptions options) {
boolean exact = options != null && options.exact != null && options.exact;
return getByAttributeTextSelector("title", text, exact);
}
static String getByPlaceholderSelector(Object text, Locator.GetByPlaceholderOptions options) {
boolean exact = options != null && options.exact != null && options.exact;
return getByAttributeTextSelector("placeholder", text, exact);
}
private static void addAttr(StringBuilder result, String name, String value) {
result.append("[").append(name).append("=").append(value).append("]");
}
static String getByRoleSelector(AriaRole role, Locator.GetByRoleOptions options) {
StringBuilder result = new StringBuilder();
result.append("role=").append(role.name().toLowerCase());
if (options != null) {
if (options.checked != null)
addAttr(result, "checked", options.checked.toString());
if (options.disabled != null)
addAttr(result, "disabled", options.disabled.toString());
if (options.selected != null)
addAttr(result, "selected", options.selected.toString());
if (options.expanded != null)
addAttr(result, "expanded", options.expanded.toString());
if (options.includeHidden != null)
addAttr(result, "include-hidden", options.includeHidden.toString());
if (options.level != null)
addAttr(result, "level", options.level.toString());
if (options.name != null) {
String name;
if (options.name instanceof String) {
name = escapeForAttributeSelector((String) options.name, false);
} else if (options.name instanceof Pattern) {
name = toJsRegExp((Pattern) options.name);
} else {
throw new IllegalArgumentException("options.name can be String or Pattern, found: " + options.name);
}
addAttr(result, "name", name);
}
if (options.pressed != null)
addAttr(result, "pressed", options.pressed.toString());
}
return result.toString();
}
static String escapeForTextSelector(Object text, boolean exact) {
return escapeForTextSelector(text, exact, false);
}
private static String escapeForTextSelector(Object param, boolean exact, boolean caseSensitive) {
if (param instanceof Pattern) {
return toJsRegExp((Pattern) param);
}
if (!(param instanceof String)) {
throw new IllegalArgumentException("text parameter must be Pattern or String: " + param);
}
String text = (String) param;
if (exact) {
return '"' + text.replace("\"", "\\\"") + '"';
}
if (text.contains("\"") || text.contains(">>") || text.startsWith("/")) {
return "/" + escapeForRegex(text).replaceAll("\\s+", "\\\\s+") + "/" + (caseSensitive ? "" : "i");
}
return text;
}
private static String escapeForRegex(String text) {
return text.replaceAll("[.*+?^>${}()|\\[\\]\\\\]", "\\\\\\\\$0");
}
private static String escapeForAttributeSelector(String value, boolean exact) {
// TODO: this should actually be
// 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");
}
private static String toJsRegExp(Pattern pattern) {
return "/" + pattern.pattern() + "/" + toJsRegexFlags(pattern);
}
}
@@ -761,6 +761,77 @@ public class PageImpl extends ChannelOwner implements Page {
() -> mainFrame.getAttributeImpl(selector, name, convertType(options, Frame.GetAttributeOptions.class)));
}
@Override
public Locator getByAltText(String text, GetByAltTextOptions options) {
return withLogging("Page.getAttribute",
() -> mainFrame.getByAltText(text, convertType(options, Frame.GetByAltTextOptions.class)));
}
@Override
public Locator getByAltText(Pattern text, GetByAltTextOptions options) {
return withLogging("Page.getByAltText",
() -> mainFrame.getByAltText(text, convertType(options, Frame.GetByAltTextOptions.class)));
}
@Override
public Locator getByLabel(String text, GetByLabelOptions options) {
return withLogging("Page.getByLabel",
() -> mainFrame.getByLabel(text, convertType(options, Frame.GetByLabelOptions.class)));
}
@Override
public Locator getByLabel(Pattern text, GetByLabelOptions options) {
return withLogging("Page.getByLabel",
() -> mainFrame.getByLabel(text, convertType(options, Frame.GetByLabelOptions.class)));
}
@Override
public Locator getByPlaceholder(String text, GetByPlaceholderOptions options) {
return withLogging("Page.getByPlaceholder",
() -> mainFrame.getByPlaceholder(text, convertType(options, Frame.GetByPlaceholderOptions.class)));
}
@Override
public Locator getByPlaceholder(Pattern text, GetByPlaceholderOptions options) {
return withLogging("Page.getByPlaceholder",
() -> mainFrame.getByPlaceholder(text, convertType(options, Frame.GetByPlaceholderOptions.class)));
}
@Override
public Locator getByRole(AriaRole role, GetByRoleOptions options) {
return withLogging("Page.getByRole",
() -> mainFrame.getByRole(role, convertType(options, Frame.GetByRoleOptions.class)));
}
@Override
public Locator getByTestId(String testId) {
return withLogging("Page.getByTestId", () -> mainFrame.getByTestId(testId));
}
@Override
public Locator getByText(String text, GetByTextOptions options) {
return withLogging("Page.getByText",
() -> mainFrame.getByText(text, convertType(options, Frame.GetByTextOptions.class)));
}
@Override
public Locator getByText(Pattern text, GetByTextOptions options) {
return withLogging("Page.getByText",
() -> mainFrame.getByText(text, convertType(options, Frame.GetByTextOptions.class)));
}
@Override
public Locator getByTitle(String text, GetByTitleOptions options) {
return withLogging("Page.getByTitle",
() -> mainFrame.getByTitle(text, convertType(options, Frame.GetByTitleOptions.class)));
}
@Override
public Locator getByTitle(Pattern text, GetByTitleOptions options) {
return withLogging("Page.getByTitle",
() -> mainFrame.getByTitle(text, convertType(options, Frame.GetByTitleOptions.class)));
}
@Override
public Response goBack(GoBackOptions options) {
return withLogging("Page.goBack", () -> goBackImpl(options));
@@ -25,6 +25,7 @@ import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import static com.microsoft.playwright.impl.LocatorUtils.setTestIdAttributeName;
import static java.nio.charset.StandardCharsets.UTF_8;
public class SharedSelectors extends LoggingSupport implements Selectors {
@@ -61,6 +62,12 @@ public class SharedSelectors extends LoggingSupport implements Selectors {
});
}
@Override
public void setTestIdAttribute(String attributeName) {
// TODO: set it per playwright insttance
setTestIdAttributeName(attributeName);
}
void addChannel(SelectorsImpl channel) {
registrations.forEach(r -> channel.registerImpl(r.name, r.script, r.options));
channels.add(channel);
@@ -0,0 +1,102 @@
/*
* 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 enum AriaRole {
ALERT,
ALERTDIALOG,
APPLICATION,
ARTICLE,
BANNER,
BLOCKQUOTE,
BUTTON,
CAPTION,
CELL,
CHECKBOX,
CODE,
COLUMNHEADER,
COMBOBOX,
COMPLEMENTARY,
CONTENTINFO,
DEFINITION,
DELETION,
DIALOG,
DIRECTORY,
DOCUMENT,
EMPHASIS,
FEED,
FIGURE,
FORM,
GENERIC,
GRID,
GRIDCELL,
GROUP,
HEADING,
IMG,
INSERTION,
LINK,
LIST,
LISTBOX,
LISTITEM,
LOG,
MAIN,
MARQUEE,
MATH,
METER,
MENU,
MENUBAR,
MENUITEM,
MENUITEMCHECKBOX,
MENUITEMRADIO,
NAVIGATION,
NONE,
NOTE,
OPTION,
PARAGRAPH,
PRESENTATION,
PROGRESSBAR,
RADIO,
RADIOGROUP,
REGION,
ROW,
ROWGROUP,
ROWHEADER,
SCROLLBAR,
SEARCH,
SEARCHBOX,
SEPARATOR,
SLIDER,
SPINBUTTON,
STATUS,
STRONG,
SUBSCRIPT,
SUPERSCRIPT,
SWITCH,
TAB,
TABLE,
TABLIST,
TABPANEL,
TERM,
TEXTBOX,
TIME,
TIMER,
TOOLBAR,
TOOLTIP,
TREE,
TREEGRID,
TREEITEM
}
@@ -287,6 +287,27 @@ public class TestBrowserContextFetch extends TestBase {
assertEquals("/simple.json", request.get().url);
}
@Test
void getShouldSupportPostData() throws ExecutionException, InterruptedException {
Future<Server.Request> request = server.futureRequest("/simple.json");
APIResponse response = context.request().get(server.PREFIX + "/simple.json",
RequestOptions.create().setData("My request"));
assertEquals("GET", request.get().method);
assertEquals("My request", new String(request.get().postBody));
assertEquals(200, response.status());
assertEquals("/simple.json", request.get().url);
}
@Test
void headShouldSupportPostData() throws ExecutionException, InterruptedException {
Future<Server.Request> request = server.futureRequest("/simple.json");
APIResponse response = context.request().head(server.PREFIX + "/simple.json",
RequestOptions.create().setData("My request"));
assertEquals("HEAD", request.get().method);
assertEquals("My request", new String(request.get().postBody));
assertEquals(200, response.status());
assertEquals("/simple.json", request.get().url);
}
@Test
void shouldAddDefaultHeaders() throws ExecutionException, InterruptedException {
@@ -16,6 +16,7 @@
package com.microsoft.playwright;
import com.microsoft.playwright.options.AriaRole;
import org.junit.jupiter.api.Test;
import java.net.MalformedURLException;
@@ -30,13 +31,14 @@ public class TestLocatorFrame extends TestBase {
.setBody("<iframe src='iframe.html'></iframe>").setContentType("text/html")));
page.route("**/iframe.html", route -> {
route.fulfill(new Route.FulfillOptions().setBody("<html>\n" +
" <div>\n" +
" <button>Hello iframe</button>\n" +
" <iframe src='iframe-2.html'></iframe>\n" +
" </div>\n" +
" <span>1</span>\n" +
" <span>2</span>\n" +
" </html>").setContentType("text/html"));
" <div>\n" +
" <button data-testid=\"buttonId\">Hello iframe</button>\n" +
" <iframe src=\"iframe-2.html\"></iframe>\n" +
" </div>\n" +
" <span>1</span>\n" +
" <span>2</span>\n" +
" <label for=target>Name</label><input id=target type=text placeholder=Placeholder title=Title alt=Alternative>\n" +
"</html>").setContentType("text/html"));
});
page.route("**/iframe-2.html", route -> {
route.fulfill(new Route.FulfillOptions().setBody("<html><button>Hello nested iframe</button></html>").setContentType("text/html"));
@@ -241,4 +243,24 @@ public class TestLocatorFrame extends TestBase {
assertThat(button3).hasText("Hello from iframe-3.html");
}
@Test
void getByCoverage() {
routeIframe(page);
page.navigate(server.EMPTY_PAGE);
Locator button1 = page.frameLocator("iframe").getByRole(AriaRole.BUTTON);
Locator button2 = page.frameLocator("iframe").getByText("Hello");
Locator button3 = page.frameLocator("iframe").getByTestId("buttonId");
assertThat(button1).hasText("Hello iframe");
assertThat(button2).hasText("Hello iframe");
assertThat(button3).hasText("Hello iframe");
Locator input1 = page.frameLocator("iframe").getByLabel("Name");
assertThat(input1).hasValue("");
Locator input2 = page.frameLocator("iframe").getByPlaceholder("Placeholder");
assertThat(input2).hasValue("");
Locator input3 = page.frameLocator("iframe").getByAltText("Alternative");
assertThat(input3).hasValue("");
Locator input4 = page.frameLocator("iframe").getByTitle("Title");
assertThat(input4).hasValue("");
}
}
@@ -0,0 +1,142 @@
package com.microsoft.playwright;
import org.junit.jupiter.api.Test;
import java.util.Collections;
import java.util.regex.Pattern;
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class TestSelectorsGetBy extends TestBase {
@Test
void getByTestIdShouldWork() {
page.setContent("<div><div data-testid='Hello'>Hello world</div></div>");
assertThat(page.getByTestId("Hello")).hasText("Hello world");
assertThat(page.mainFrame().getByTestId("Hello")).hasText("Hello world");
assertThat(page.locator("div").getByTestId("Hello")).hasText("Hello world");
}
@Test
void getByTestIdShouldEscapeId() {
page.setContent("<div><div data-testid='He\"llo'>Hello world</div></div>");
assertThat(page.getByTestId("He\"llo")).hasText("Hello world");
}
@Test
void getByTextShouldWork() {
page.setContent("<div>yo</div><div>ya</div><div>\nye </div>");
assertTrue(((String) page.getByText("ye").evaluate("e => e.outerHTML")).contains(">\nye </div>"));
assertTrue(((String) page.getByText(Pattern.compile("ye")).evaluate("e => e.outerHTML")).contains(">\nye </div>"));
assertTrue(((String) page.getByText(Pattern.compile("e")).evaluate("e => e.outerHTML")).contains(">\nye </div>"));
page.setContent("<div> ye </div><div>ye</div>");
assertTrue(((String) page.getByText("ye", new Page.GetByTextOptions().setExact(true)).first().evaluate("e => e.outerHTML")).contains("> ye </div>"));
page.setContent("<div>Hello world</div><div>Hello</div>");
assertEquals("<div>Hello</div>", page.getByText("Hello", new Page.GetByTextOptions().setExact(true)).evaluate("e => e.outerHTML"));
}
@Test
void getByLabelShouldWork() {
page.setContent("<div><label for=target>Name</label><input id=target type=text></div>");
assertEquals("LABEL", page.getByText("Name").evaluate("e => e.nodeName"));
assertEquals("INPUT", page.getByLabel("Name").evaluate("e => e.nodeName"));
assertEquals("INPUT", page.mainFrame().getByLabel("Name").evaluate("e => e.nodeName"));
assertEquals("INPUT", page.locator("div").getByLabel("Name").evaluate("e => e.nodeName"));
}
@Test
void getByLabelShouldWorkWithNestedElements() {
page.setContent("<label for=target>Last <span>Name</span></label><input id=target type=text>");
assertThat(page.getByLabel("last name")).hasAttribute("id", "target");
assertThat(page.getByLabel("st na")).hasAttribute("id", "target");
assertThat(page.getByLabel("Name")).hasAttribute("id", "target");
assertThat(page.getByLabel("Last Name", new Page.GetByLabelOptions().setExact(true))).hasAttribute("id", "target");
assertThat(page.getByLabel(Pattern.compile("Last\\s+name", Pattern.CASE_INSENSITIVE))).hasAttribute("id", "target");
assertEquals(Collections.emptyList(), page.getByLabel("Last", new Page.GetByLabelOptions().setExact(true)).elementHandles());
assertEquals(Collections.emptyList(), page.getByLabel("last name", new Page.GetByLabelOptions().setExact(true)).elementHandles());
assertEquals(Collections.emptyList(), page.getByLabel("Name", new Page.GetByLabelOptions().setExact(true)).elementHandles());
assertEquals(Collections.emptyList(), page.getByLabel("what?").elementHandles());
assertEquals(Collections.emptyList(), page.getByLabel(Pattern.compile("last name")).elementHandles());
}
@Test
void getByPlaceholderShouldWork() {
page.setContent("<div>\n" +
" <input placeholder='Hello'>\n" +
" <input placeholder='Hello World'>\n" +
" </div>");
assertThat(page.getByPlaceholder("hello")).hasCount(2);
assertThat(page.getByPlaceholder("Hello", new Page.GetByPlaceholderOptions().setExact(true))).hasCount(1);
assertThat(page.getByPlaceholder(Pattern.compile("wor", Pattern.CASE_INSENSITIVE))).hasCount(1);
// Coverage
assertThat(page.mainFrame().getByPlaceholder("hello")).hasCount(2);
assertThat(page.locator("div").getByPlaceholder("hello")).hasCount(2);
}
@Test
void getByAltTextShouldWork() {
page.setContent("<div>\n" +
" <input alt='Hello'>\n" +
" <input alt='Hello World'>\n" +
" </div>");
assertThat(page.getByAltText("hello")).hasCount(2);
assertThat(page.getByAltText("Hello", new Page.GetByAltTextOptions().setExact(true))).hasCount(1);
assertThat(page.getByAltText(Pattern.compile("wor", Pattern.CASE_INSENSITIVE))).hasCount(1);
// Coverage
assertThat(page.mainFrame().getByAltText("hello")).hasCount(2);
assertThat(page.locator("div").getByAltText("hello")).hasCount(2);
}
@Test
void getByTitleShouldWork() {
page.setContent("<div>\n" +
" <input title='Hello'>\n" +
" <input title='Hello World'>\n" +
" </div>");
assertThat(page.getByTitle("hello")).hasCount(2);
assertThat(page.getByTitle("Hello", new Page.GetByTitleOptions().setExact(true))).hasCount(1);
assertThat(page.getByTitle(Pattern.compile("wor", Pattern.CASE_INSENSITIVE))).hasCount(1);
// Coverage
assertThat(page.mainFrame().getByTitle("hello")).hasCount(2);
assertThat(page.locator("div").getByTitle("hello")).hasCount(2);
}
@Test
void getByEscaping() {
page.setContent("<label id=label for=control>Hello my\n" +
"wo\"rld</label><input id=control />");
page.evalOnSelector("input", "input => {\n" +
" input.setAttribute('placeholder', 'hello my\\nwo\"rld');\n" +
" input.setAttribute('title', 'hello my\\nwo\"rld');\n" +
" input.setAttribute('alt', 'hello my\\nwo\"rld');\n" +
" }");
assertThat(page.getByText("hello my\nwo\"rld")).hasAttribute("id", "label");
assertThat(page.getByText("hello my wo\"rld")).hasAttribute("id", "label");
assertThat(page.getByLabel("hello my\nwo\"rld")).hasAttribute("id", "control");
assertThat(page.getByPlaceholder("hello my\nwo\"rld")).hasAttribute("id", "control");
assertThat(page.getByAltText("hello my\nwo\"rld")).hasAttribute("id", "control");
assertThat(page.getByTitle("hello my\nwo\"rld")).hasAttribute("id", "control");
page.setContent("<label id=label for=control>Hello my\n" +
"world</label><input id=control />");
page.evalOnSelector("input", "input => {\n" +
" input.setAttribute('placeholder', 'hello my\\nworld');\n" +
" input.setAttribute('title', 'hello my\\nworld');\n" +
" input.setAttribute('alt', 'hello my\\nworld');\n" +
" }");
assertThat(page.getByText("hello my\nworld")).hasAttribute("id", "label");
assertThat(page.getByText("hello my world")).hasAttribute("id", "label");
assertThat(page.getByLabel("hello my\nworld")).hasAttribute("id", "control");
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");
}
}
@@ -0,0 +1,385 @@
package com.microsoft.playwright;
import com.microsoft.playwright.options.AriaRole;
import org.junit.jupiter.api.Test;
import java.util.regex.Pattern;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static org.junit.jupiter.api.Assertions.*;
public class TestSelectorsRole extends TestBase {
@Test
void shouldDetectRoles() {
page.setContent("<button>Hello</button>\n" +
" <select multiple=\"\" size=\"2\"></select>\n" +
" <select></select>\n" +
" <h3>Heading</h3>\n" +
" <details><summary>Hello</summary></details>\n" +
" <div role='dialog'>I am a dialog</div>");
assertEquals(asList("<button>Hello</button>"), page.locator("role=button").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList("<select multiple=\"\" size=\"2\"></select>"), page.locator("role=listbox").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList("<select></select>"), page.locator("role=combobox").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList("<h3>Heading</h3>"), page.locator("role=heading").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList("<details><summary>Hello</summary></details>"), page.locator("role=group").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList("<div role=\"dialog\">I am a dialog</div>"), page.locator("role=dialog").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(emptyList(), page.locator("role=menuitem").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(emptyList(), page.getByRole(AriaRole.MENUITEM).evaluateAll("els => els.map(e => e.outerHTML)"));
}
@Test
void shouldSupportSelected() {
page.setContent("<select>\n" +
" <option>Hi</option>\n" +
" <option selected>Hello</option>\n" +
" </select>\n" +
" <div>\n" +
" <div role=\"option\" aria-selected=\"true\">Hi</div>\n" +
" <div role=\"option\" aria-selected=\"false\">Hello</div>\n" +
" </div>");
assertEquals(asList(
"<option selected=\"\">Hello</option>",
"<div role=\"option\" aria-selected=\"true\">Hi</div>"
), page.locator("role=option[selected]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<option selected=\"\">Hello</option>",
"<div role=\"option\" aria-selected=\"true\">Hi</div>"
), page.locator("role=option[selected=true]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<option selected=\"\">Hello</option>",
"<div role=\"option\" aria-selected=\"true\">Hi</div>"
), page.getByRole(AriaRole.OPTION, new Page.GetByRoleOptions().setSelected(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<option>Hi</option>",
"<div role=\"option\" aria-selected=\"false\">Hello</div>"
), page.locator("role=option[selected=false]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<option>Hi</option>",
"<div role=\"option\" aria-selected=\"false\">Hello</div>"
), page.getByRole(AriaRole.OPTION, new Page.GetByRoleOptions().setSelected(false)).evaluateAll("els => els.map(e => e.outerHTML)"));
}
@Test
void shouldSupportChecked() {
page.setContent("<input type=checkbox>\n" +
" <input type=checkbox checked>\n" +
" <input type=checkbox indeterminate>\n" +
" <div role=checkbox aria-checked=\"true\">Hi</div>\n" +
" <div role=checkbox aria-checked=\"false\">Hello</div>\n" +
" <div role=checkbox>Unknown</div>");
page.evalOnSelector("[indeterminate]", "input => input.indeterminate = true");
assertEquals(asList(
"<input type=\"checkbox\" checked=\"\">",
"<div role=\"checkbox\" aria-checked=\"true\">Hi</div>"
), page.locator("role=checkbox[checked]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<input type=\"checkbox\" checked=\"\">",
"<div role=\"checkbox\" aria-checked=\"true\">Hi</div>"
), page.locator("role=checkbox[checked=true]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<input type=\"checkbox\" checked=\"\">",
"<div role=\"checkbox\" aria-checked=\"true\">Hi</div>"
), page.getByRole(AriaRole.CHECKBOX, new Page.GetByRoleOptions().setChecked(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<input type=\"checkbox\">",
"<div role=\"checkbox\" aria-checked=\"false\">Hello</div>",
"<div role=\"checkbox\">Unknown</div>"
), page.locator("role=checkbox[checked=false]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<input type=\"checkbox\">",
"<div role=\"checkbox\" aria-checked=\"false\">Hello</div>",
"<div role=\"checkbox\">Unknown</div>"
), page.getByRole(AriaRole.CHECKBOX, new Page.GetByRoleOptions().setChecked(false)).evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<input type=\"checkbox\" indeterminate=\"\">"
), page.locator("role=checkbox[checked='mixed']").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<input type=\"checkbox\">",
"<input type=\"checkbox\" checked=\"\">",
"<input type=\"checkbox\" indeterminate=\"\">",
"<div role=\"checkbox\" aria-checked=\"true\">Hi</div>",
"<div role=\"checkbox\" aria-checked=\"false\">Hello</div>",
"<div role=\"checkbox\">Unknown</div>"
), page.locator("role=checkbox").evaluateAll("els => els.map(e => e.outerHTML)"));
}
@Test
void shouldSupportPressed() {
page.setContent("<button>Hi</button>\n" +
" <button aria-pressed=\"true\">Hello</button>\n" +
" <button aria-pressed=\"false\">Bye</button>\n" +
" <button aria-pressed=\"mixed\">Mixed</button>");
assertEquals(asList(
"<button aria-pressed=\"true\">Hello</button>"
), page.locator("role=button[pressed]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<button aria-pressed=\"true\">Hello</button>"
), page.locator("role=button[pressed=true]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<button aria-pressed=\"true\">Hello</button>"
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setPressed(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<button>Hi</button>",
"<button aria-pressed=\"false\">Bye</button>"
), page.locator("role=button[pressed=false]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<button>Hi</button>",
"<button aria-pressed=\"false\">Bye</button>"
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setPressed(false)).evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<button aria-pressed=\"mixed\">Mixed</button>"
), page.locator("role=button[pressed='mixed']").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<button>Hi</button>",
"<button aria-pressed=\"true\">Hello</button>",
"<button aria-pressed=\"false\">Bye</button>",
"<button aria-pressed=\"mixed\">Mixed</button>"
), page.locator("role=button").evaluateAll("els => els.map(e => e.outerHTML)"));
}
@Test
void shouldSupportExpanded() {
page.setContent("<button>Hi</button>\n" +
" <button aria-expanded=\"true\">Hello</button>\n" +
" <button aria-expanded=\"false\">Bye</button>");
assertEquals(asList(
"<button aria-expanded=\"true\">Hello</button>"
), page.locator("role=button[expanded]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<button aria-expanded=\"true\">Hello</button>"
), page.locator("role=button[expanded=true]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<button aria-expanded=\"true\">Hello</button>"
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setExpanded(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<button>Hi</button>",
"<button aria-expanded=\"false\">Bye</button>"
), page.locator("role=button[expanded=false]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<button>Hi</button>",
"<button aria-expanded=\"false\">Bye</button>"
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setExpanded(false)).evaluateAll("els => els.map(e => e.outerHTML)"));
}
@Test
void shouldSupportDisabled() {
page.setContent("<button>Hi</button>\n" +
" <button disabled>Bye</button>\n" +
" <button aria-disabled=\"true\">Hello</button>\n" +
" <button aria-disabled=\"false\">Oh</button>\n" +
" <fieldset disabled>\n" +
" <button>Yay</button>\n" +
" </fieldset>");
assertEquals(asList(
"<button disabled=\"\">Bye</button>",
"<button aria-disabled=\"true\">Hello</button>",
"<button>Yay</button>"
), page.locator("role=button[disabled]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<button disabled=\"\">Bye</button>",
"<button aria-disabled=\"true\">Hello</button>",
"<button>Yay</button>"
), page.locator("role=button[disabled=true]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<button disabled=\"\">Bye</button>",
"<button aria-disabled=\"true\">Hello</button>",
"<button>Yay</button>"
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setDisabled(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<button>Hi</button>",
"<button aria-disabled=\"false\">Oh</button>"
), page.locator("role=button[disabled=false]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<button>Hi</button>",
"<button aria-disabled=\"false\">Oh</button>"
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setDisabled(false)).evaluateAll("els => els.map(e => e.outerHTML)"));
}
@Test
void shouldSupportLevel() {
page.setContent("<h1>Hello</h1>\n" +
" <h3>Hi</h3>\n" +
" <div role=\"heading\" aria-level=\"5\">Bye</div>");
assertEquals(asList(
"<h1>Hello</h1>"
), page.locator("role=heading[level=1]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<h1>Hello</h1>"
), page.getByRole(AriaRole.HEADING, new Page.GetByRoleOptions().setLevel(1)).evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<h3>Hi</h3>"
), page.locator("role=heading[level=3]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<h3>Hi</h3>"
), page.getByRole(AriaRole.HEADING, new Page.GetByRoleOptions().setLevel(3)).evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<div role=\"heading\" aria-level=\"5\">Bye</div>"
), page.locator("role=heading[level=5]").evaluateAll("els => els.map(e => e.outerHTML)"));
}
@Test
void shouldFilterHiddenUnlessExplicitlyAskedFor() {
page.setContent("<button>Hi</button>\n" +
" <button hidden>Hello</button>\n" +
" <button aria-hidden=\"true\">Yay</button>\n" +
" <button aria-hidden=\"false\">Nay</button>\n" +
" <button style=\"visibility:hidden\">Bye</button>\n" +
" <div style=\"visibility:hidden\">\n" +
" <button>Oh</button>\n" +
" </div>\n" +
" <div style=\"visibility:hidden\">\n" +
" <button style=\"visibility:visible\">Still here</button>\n" +
" </div>\n" +
" <button style=\"display:none\">Never</button>\n" +
" <div id=host1></div>\n" +
" <div id=host2 style=\"display:none\"></div>\n" +
" <script>\n" +
" function addButton(host, text) {\n" +
" const root = host.attachShadow({ mode: 'open' });\n" +
" const button = document.createElement('button');\n" +
" button.textContent = text;\n" +
" root.appendChild(button);\n" +
" }\n" +
" addButton(document.getElementById('host1'), 'Shadow1');\n" +
" addButton(document.getElementById('host2'), 'Shadow2');\n" +
" </script>");
assertEquals(asList(
"<button>Hi</button>",
"<button aria-hidden=\"false\">Nay</button>",
"<button style=\"visibility:visible\">Still here</button>",
"<button>Shadow1</button>"
), page.locator("role=button").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<button>Hi</button>",
"<button hidden=\"\">Hello</button>",
"<button aria-hidden=\"true\">Yay</button>",
"<button aria-hidden=\"false\">Nay</button>",
"<button style=\"visibility:hidden\">Bye</button>",
"<button>Oh</button>",
"<button style=\"visibility:visible\">Still here</button>",
"<button style=\"display:none\">Never</button>",
"<button>Shadow1</button>",
"<button>Shadow2</button>"
), page.locator("role=button[include-hidden]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<button>Hi</button>",
"<button hidden=\"\">Hello</button>",
"<button aria-hidden=\"true\">Yay</button>",
"<button aria-hidden=\"false\">Nay</button>",
"<button style=\"visibility:hidden\">Bye</button>",
"<button>Oh</button>",
"<button style=\"visibility:visible\">Still here</button>",
"<button style=\"display:none\">Never</button>",
"<button>Shadow1</button>",
"<button>Shadow2</button>"
), page.locator("role=button[include-hidden=true]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<button>Hi</button>",
"<button aria-hidden=\"false\">Nay</button>",
"<button style=\"visibility:visible\">Still here</button>",
"<button>Shadow1</button>"
), page.locator("role=button[include-hidden=false]").evaluateAll("els => els.map(e => e.outerHTML)"));
}
@Test
void shouldSupportName() {
page.setContent("<div role=\"button\" aria-label=\"Hello\"></div>\n" +
" <div role=\"button\" aria-label=\"Hallo\"></div>\n" +
" <div role=\"button\" aria-label=\"Hello\" aria-hidden=\"true\"></div>\n" +
" <div role=\"button\" aria-label=\"123\" aria-hidden=\"true\"></div>\n" +
" <div role=\"button\" aria-label='foo\"bar' aria-hidden=\"true\"></div>");
assertEquals(asList(
"<div role=\"button\" aria-label=\"Hello\"></div>"
), page.locator("role=button[name='Hello']").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<div role=\"button\" aria-label=\"Hello\"></div>"
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Hello")).evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<div role=\"button\" aria-label=\"Hallo\"></div>"
), page.locator("role=button[name*='all']").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<div role=\"button\" aria-label=\"Hello\"></div>",
"<div role=\"button\" aria-label=\"Hallo\"></div>"
), page.locator("role=button[name=/^H[ae]llo$/]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<div role=\"button\" aria-label=\"Hello\"></div>",
"<div role=\"button\" aria-label=\"Hallo\"></div>"
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName(Pattern.compile("^H[ae]llo$"))).evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<div role=\"button\" aria-label=\"Hello\"></div>",
"<div role=\"button\" aria-label=\"Hallo\"></div>"
), page.locator("role=button[name=/h.*o/i]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<div role=\"button\" aria-label=\"Hello\"></div>",
"<div role=\"button\" aria-label=\"Hallo\"></div>"
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName(Pattern.compile("h.*o", Pattern.CASE_INSENSITIVE))).evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<div role=\"button\" aria-label=\"Hello\"></div>",
"<div role=\"button\" aria-label=\"Hello\" aria-hidden=\"true\"></div>"
), page.locator("role=button[name='Hello'][include-hidden]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<div role=\"button\" aria-label=\"Hello\"></div>",
"<div role=\"button\" aria-label=\"Hello\" aria-hidden=\"true\"></div>"
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Hello").setIncludeHidden(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<div role=\"button\" aria-label=\"Hello\"></div>",
"<div role=\"button\" aria-label=\"Hello\" aria-hidden=\"true\"></div>"
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("hello").setIncludeHidden(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<div role=\"button\" aria-label=\"Hello\"></div>"
), page.locator("role=button[name=Hello]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<div role=\"button\" aria-label=\"123\" aria-hidden=\"true\"></div>"
), page.locator("role=button[name=123][include-hidden]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<div role=\"button\" aria-label=\"123\" aria-hidden=\"true\"></div>"
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("123").setIncludeHidden(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
}
@Test
void errors() {
PlaywrightException e0 = assertThrows(PlaywrightException.class, () -> page.querySelector("role=[bar]"));
assertTrue(e0.getMessage().contains("Role must not be empty"), e0.getMessage());
PlaywrightException e1 = assertThrows(PlaywrightException.class, () -> page.querySelector("role=foo[sElected]"));
assertTrue(e1.getMessage().contains("Unknown attribute \"sElected\", must be one of \"checked\", \"disabled\", \"expanded\", \"include-hidden\", \"level\", \"name\", \"pressed\", \"selected\""), e1.getMessage());
PlaywrightException e2 = assertThrows(PlaywrightException.class, () -> page.querySelector("role=foo[bar . qux=true]"));
assertTrue(e2.getMessage().contains("Unknown attribute \"bar.qux\""), e2.getMessage());
PlaywrightException e3 = assertThrows(PlaywrightException.class, () -> page.querySelector("role=heading[level='bar']"));
assertTrue(e3.getMessage().contains("\"level\" attribute must be compared to a number"), e3.getMessage());
PlaywrightException e4 = assertThrows(PlaywrightException.class, () -> page.querySelector("role=checkbox[checked='bar']"));
assertTrue(e4.getMessage().contains("\"checked\" must be one of true, false, \"mixed\""), e4.getMessage());
PlaywrightException e5 = assertThrows(PlaywrightException.class, () -> page.querySelector("role=checkbox[checked~=true]"));
assertTrue(e5.getMessage().contains("cannot use ~= in attribute with non-string matching value"), e5.getMessage());
PlaywrightException e6 = assertThrows(PlaywrightException.class, () -> page.querySelector("role=button[level=3]"));
assertTrue(e6.getMessage().contains("\"level\" attribute is only supported for roles: \"heading\", \"listitem\", \"row\", \"treeitem\""), e6.getMessage());
PlaywrightException e7 = assertThrows(PlaywrightException.class, () -> page.querySelector("role=button[name]"));
assertTrue(e7.getMessage().contains("\"name\" attribute must have a value"), e7.getMessage());
}
}
@@ -114,6 +114,9 @@ class Utils {
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipPath.toFile()))) {
for (ZipEntry zipEntry = zis.getNextEntry(); zipEntry != null; zipEntry = zis.getNextEntry()) {
Path toPath = toDir.resolve(zipEntry.getName());
if (!toPath.normalize().startsWith(toDir.normalize())) {
throw new IOException("Bad zip entry");
}
if (zipEntry.isDirectory()) {
Files.createDirectories(toPath);
} else {
+1 -1
View File
@@ -6,7 +6,7 @@
<groupId>com.microsoft.playwright</groupId>
<artifactId>parent-pom</artifactId>
<version>1.26.0-SNAPSHOT</version>
<version>1.27.1</version>
<packaging>pom</packaging>
<name>Playwright Parent Project</name>
<description>Java library to automate Chromium, Firefox and WebKit with a single API.
+1 -1
View File
@@ -1 +1 @@
1.26.0
1.27.1
+1 -1
View File
@@ -6,7 +6,7 @@
<groupId>com.microsoft.playwright</groupId>
<artifactId>api-generator</artifactId>
<version>1.26.0-SNAPSHOT</version>
<version>1.27.1</version>
<name>Playwright - API Generator</name>
<description>
This is an internal module used to generate Java API from the upstream Playwright
@@ -939,7 +939,7 @@ class Interface extends TypeDefinition {
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", "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").contains(jsonName)) {
output.add("import com.microsoft.playwright.options.*;");
}
if ("Download".equals(jsonName)) {
+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.26.0-SNAPSHOT</version>
<version>1.27.1</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.26.0-SNAPSHOT</version>
<version>1.27.1</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.26.0-SNAPSHOT</version>
<version>1.27.1</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.26.0-SNAPSHOT</version>
<version>1.27.1</version>
<name>Playwright - Update Version in Documentation</name>
<description>
This is an internal module used to update versions in the documentation based on