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

Compare commits

...

32 Commits

Author SHA1 Message Date
Yury Semikhatsky 80fa0c6e98 chore: roll driver to 1.31.1 (#1219) 2023-02-27 19:58:18 -08:00
Yury Semikhatsky 3d9dc8429c chore: set release version to 1.31.0 (#1211) 2023-02-22 08:57:24 -08:00
Karl Heinz Marbaise 4762ad9768 devops: Improve plugin configuration inheritance usage (#1201) (#1202)
devops: Improve plugin configuration inheritance usage. (#1201)
 - removing duplication of plugin definition in modules
 - using single location to define all (parent)
 - defined all used plugins via pluginManagement with
   most recent versions.
 - removed life cycle binding from pluginManagement
 - moved life cycle binding to default location
 - using jar-no-fork of maven-source-plugin.
2023-02-17 15:38:52 -08:00
Karl Heinz Marbaise 0fb77bbc81 fix: Improve maven plugin configuration (#1200) 2023-02-17 09:48:45 -08:00
Yury Semikhatsky c4b27febd4 feat: roll driver 1.31.0-beta-1676591072000 (#1207) 2023-02-16 19:09:22 -08:00
Yury Semikhatsky a478acf6b2 test: response.finished() respects page.close (#1206) 2023-02-16 15:18:54 -08:00
Yury Semikhatsky da36841809 fix: properly escape slash inside attributes (#1205)
https://github.com/microsoft/playwright/issues/20471
2023-02-16 13:02:22 -08:00
Yury Semikhatsky 8dfb745da9 fix: page.pause should not throw (#1204) 2023-02-16 11:21:24 -08:00
Yury Semikhatsky e81b874bbb chore: set dev version 1.31.0-SNAPSHOT (#1186) 2023-01-23 11:55:55 -08:00
Yury Semikhatsky 96b432d528 chode: roll driver to 1.30.0-beta-1674276599000 (#1183) 2023-01-23 11:18:37 -08:00
Yury Semikhatsky 551c168884 chore: roll 1.30 driver (#1182) 2023-01-22 21:17:31 -08:00
Yury Semikhatsky 9010fa95a0 chore: bump dev version to 1.30 (#1180) 2023-01-18 12:21:03 -08:00
Yury Semikhatsky b2e17853d7 chore: roll driver to 1.29.2 (#1176) 2023-01-18 11:45:35 -08:00
Yury Semikhatsky d792d460b1 devops: delete unuzed pipeline (#1177) 2023-01-18 11:31:15 -08:00
Yury Semikhatsky 1b1343649e devops: check branch bash (#1174) 2023-01-18 11:22:21 -08:00
Yury Semikhatsky 65624d6658 devops: delete old publish.yml (#1173) 2023-01-18 09:36:02 -08:00
Yury Semikhatsky 93a62868a1 devops: remove sonatype plugins from pom (#1171) 2023-01-18 09:31:53 -08:00
Yury Semikhatsky 28e547fe2b devops: add azure pipeline for release publishing (#1170) 2023-01-18 09:23:16 -08:00
Vladislav 22b2932d2d Uprade readme.md 1.27 -> 1.28.1 (#1167) 2023-01-13 17:36:54 -08:00
Aria Moradi 8c0231b0f7 fix: handle when FileSystem already exists (#1140) 2023-01-06 13:20:42 -08:00
Yury Semikhatsky c1891cb9f7 fix(docker): adduser error (#1160) 2023-01-06 11:31:16 -08:00
Yury Semikhatsky 81d31d24f8 chore(tests): suppress surefire plugin "Corrupted STDOUT..." warning (#1151) 2022-12-28 15:14:10 -08:00
Yury Semikhatsky 17d8a9ac7a devops: use latest v1 for playwright gha (#1154) 2022-12-28 14:29:11 -08:00
Yury Semikhatsky 4246c375ac fix: Date and LocalDateTime serialization in post data (#1150) 2022-12-22 17:35:09 -08:00
Max Schmitt ec5f9604cd devops: set up CI with Azure Pipelines (#1146)
Co-authored-by: Yury Semikhatsky <yurys@chromium.org>
2022-12-22 13:46:49 +01:00
Yury Semikhatsky d9fea34baa feat: generate @since tags for methods (#1145) 2022-12-21 10:15:51 -08:00
Yury Semikhatsky 45f81c0659 chore: roll driver to 1.29.0 (#1144) 2022-12-20 00:11:27 -08:00
Yury Semikhatsky 74fafc4d7e docs: improve line wrapping (#1143) 2022-12-19 14:52:28 -08:00
Yury Semikhatsky 4efa174368 feat: roll driver, implement new APIs (#1142) 2022-12-19 12:31:32 -08:00
Yury Semikhatsky 048bca9d59 fix: asynchronous route handling (#1137) 2022-11-30 14:59:41 -08:00
Yury Semikhatsky afa20b91ae fix: implement LocatorImpl.getByRole (#1131) 2022-11-28 14:48:32 -08:00
Yury Semikhatsky 8904de9bb8 chore: set dev version to 1.29.0-SNAPSHOT (#1126) 2022-11-16 12:43:07 -08:00
87 changed files with 9580 additions and 5635 deletions
+57
View File
@@ -0,0 +1,57 @@
trigger:
none
pool:
vmImage: ubuntu-22.04
steps:
- bash: |
if [[ ! "$CURRENT_BRANCH" =~ ^release-.* ]]; then
echo "Can only publish from a release branch."
echo "Unexpected branch name: $CURRENT_BRANCH"
exit 1
fi
env:
CURRENT_BRANCH: ${{ variables['Build.SourceBranchName'] }}
displayName: "Check the branch is a release branch"
- bash: |
echo "importing GPG key:"
# Pipeline variables do not preserve line ends so we use base64 instead of --armored as a workaround.
echo $GPG_PRIVATE_KEY_BASE64 | base64 -d | gpg --batch --import
echo "list keys after import:"
gpg --list-keys
env:
GPG_PRIVATE_KEY_BASE64: $(GPG_PRIVATE_KEY_BASE64) # secret variable has to be mapped to an env variable
displayName: "Import gpg key"
- bash: ./scripts/download_driver_for_all_platforms.sh
displayName: 'Download driver'
- bash: mvn -B deploy -D skipTests --no-transfer-progress --activate-profiles release -D gpg.passphrase=$GPG_PASSPHRASE -DaltDeploymentRepository=snapshot-repo::default::file:$(pwd)/local-build
displayName: 'Build and deploy to a local directory'
env:
GPG_PASSPHRASE: $(GPG_PASSPHRASE) # secret variable has to be mapped to an env variable
- bash: |
for file in $(find snapshots -type f); do
echo "processing: $file"
if [[ $file =~ \.(md5|sha1|sha256)$ ]]; then
continue
fi
sha256sum "$file" | cut -f1 -d \ > "$file.sha256"
done
displayName: 'Create .sha256 files'
- task: EsrpRelease@2
inputs:
ConnectedServiceName: 'Playwright-Java-ESRP'
Intent: 'PackageDistribution'
ContentType: 'Maven'
PackageLocation: './local-build'
Owners: 'yurys@microsoft.com'
Approvers: 'maxschmitt@microsoft.com'
ServiceEndpointUrl: 'https://api.esrp.microsoft.com'
MainPublisher: 'PlaywrightJava'
DomainTenantId: '72f988bf-86f1-41af-91ab-2d7cd011db47'
displayName: 'ESRP Release to Maven'
-32
View File
@@ -1,32 +0,0 @@
name: Publish
on:
release:
types: [published]
push:
branches:
- main
jobs:
build:
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: microsoft/playwright-github-action@v1.5.0
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml
server-username: MAVEN_USERNAME # env variable for username in deploy
server-password: MAVEN_PASSWORD # env variable for token in deploy
gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import
gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase
- name: Download drivers
shell: bash
run: scripts/download_driver_for_all_platforms.sh
- name: Publish to Maven Central
run: mvn deploy --batch-mode -D skipTests --activate-profiles release --no-transfer-progress
env:
MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
+3
View File
@@ -29,3 +29,6 @@ jobs:
- name: Test CLI version
shell: bash
run: tools/test-cli-version/test.sh
- name: Test CLI Fatjar
shell: bash
run: tools/test-cli-fatjar/test.sh
+4 -4
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 -->108.0.5359.29<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Chromium <!-- GEN:chromium-version -->111.0.5563.19<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| WebKit <!-- GEN:webkit-version -->16.4<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->106.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Firefox <!-- GEN:firefox-version -->109.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
Headless execution is supported for all the browsers on all platforms. Check out [system requirements](https://playwright.dev/java/docs/next/intro/#system-requirements) for details.
@@ -43,7 +43,7 @@ To run Playwright simply add following dependency to your Maven project:
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>1.27.0</version>
<version>1.28.1</version>
</dependency>
```
@@ -51,7 +51,7 @@ To run Playwright using Gradle add following dependency to your build.gradle fil
```gradle
dependencies {
implementation group: 'com.microsoft.playwright', name: 'playwright', version: '1.27.0'
implementation group: 'com.microsoft.playwright', name: 'playwright', version: '1.28.1'
}
```
+1 -20
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>com.microsoft.playwright</groupId>
<artifactId>parent-pom</artifactId>
<version>1.28.0-SNAPSHOT</version>
<version>1.31.0</version>
</parent>
<artifactId>driver-bundle</artifactId>
@@ -16,25 +16,6 @@
It is intended to be used on the systems where Playwright driver is not preinstalled.
</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<configuration>
<excludeResources>true</excludeResources>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.microsoft.playwright</groupId>
@@ -106,14 +106,25 @@ public class DriverJar extends Driver {
return name.endsWith(".sh") || name.endsWith(".exe") || !name.contains(".");
}
void extractDriverToTempDir() throws URISyntaxException, IOException {
private FileSystem initFileSystem(URI uri) throws IOException {
try {
return FileSystems.newFileSystem(uri, Collections.emptyMap());
} catch (FileSystemAlreadyExistsException e) {
return null;
}
}
public static URI getDriverResourceURI() throws URISyntaxException {
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
URI originalUri = classloader.getResource(
"driver/" + platformDir()).toURI();
return classloader.getResource("driver/" + platformDir()).toURI();
}
void extractDriverToTempDir() throws URISyntaxException, IOException {
URI originalUri = getDriverResourceURI();
URI uri = maybeExtractNestedJar(originalUri);
// Create zip filesystem if loading from jar.
try (FileSystem fileSystem = "jar".equals(uri.getScheme()) ? FileSystems.newFileSystem(uri, Collections.emptyMap()) : null) {
try (FileSystem fileSystem = "jar".equals(uri.getScheme()) ? initFileSystem(uri) : null) {
Path srcRoot = Paths.get(uri);
// jar file system's .relativize gives wrong results when used with
// spring-boot-maven-plugin, convert to the default filesystem to
+1 -17
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>com.microsoft.playwright</groupId>
<artifactId>parent-pom</artifactId>
<version>1.28.0-SNAPSHOT</version>
<version>1.31.0</version>
</parent>
<artifactId>driver</artifactId>
@@ -15,22 +15,6 @@
This module provides API for discovery and launching of Playwright driver.
</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
+2 -2
View File
@@ -6,7 +6,7 @@
<groupId>org.example</groupId>
<artifactId>examples</artifactId>
<version>1.28.0-SNAPSHOT</version>
<version>1.31.0</version>
<name>Playwright Client Examples</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -15,7 +15,7 @@
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>1.22.0</version>
<version>1.30.0</version>
</dependency>
</dependencies>
<build>
+2 -14
View File
@@ -7,7 +7,7 @@
<parent>
<groupId>com.microsoft.playwright</groupId>
<artifactId>parent-pom</artifactId>
<version>1.28.0-SNAPSHOT</version>
<version>1.31.0</version>
</parent>
<artifactId>playwright</artifactId>
@@ -21,26 +21,14 @@
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<configuration combine.self="append">
<subpackages>com.microsoft.playwright</subpackages>
<excludePackageNames>com.microsoft.playwright.impl</excludePackageNames>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
@@ -21,20 +21,21 @@ import java.nio.file.Path;
import java.util.*;
/**
* Exposes API that can be used for the Web API testing. This class is used for creating {@code APIRequestContext} instance which
* in turn can be used for sending web requests. An instance of this class can be obtained via {@link Playwright#request
* Playwright.request()}. For more information see {@code APIRequestContext}.
* Exposes API that can be used for the Web API testing. This class is used for creating {@code APIRequestContext} instance
* which in turn can be used for sending web requests. An instance of this class can be obtained via {@link
* Playwright#request Playwright.request()}. For more information see {@code APIRequestContext}.
*/
public interface APIRequest {
class NewContextOptions {
/**
* Methods like {@link APIRequestContext#get APIRequestContext.get()} take the base URL into consideration by using the <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code URL()}</a> constructor for building the corresponding
* URL. Examples:
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code URL()}</a> constructor for building the
* corresponding URL. Examples:
* <ul>
* <li> baseURL: {@code http://localhost:3000} and sending request to {@code /bar.html} results in {@code http://localhost:3000/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo/} and sending request to {@code ./bar.html} results in
* {@code http://localhost:3000/foo/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000} and sending request to {@code /bar.html} results in {@code
* http://localhost:3000/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo/} and sending request to {@code ./bar.html} results in {@code
* http://localhost:3000/foo/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo} (without trailing slash) and navigating to {@code ./bar.html} results in
* {@code http://localhost:3000/bar.html}</li>
* </ul>
@@ -71,7 +72,8 @@ public interface APIRequest {
*/
public Path storageStatePath;
/**
* Maximum time in milliseconds to wait for the response. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout.
* Maximum time in milliseconds to wait for the response. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable
* timeout.
*/
public Double timeout;
/**
@@ -81,12 +83,13 @@ public interface APIRequest {
/**
* Methods like {@link APIRequestContext#get APIRequestContext.get()} take the base URL into consideration by using the <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code URL()}</a> constructor for building the corresponding
* URL. Examples:
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code URL()}</a> constructor for building the
* corresponding URL. Examples:
* <ul>
* <li> baseURL: {@code http://localhost:3000} and sending request to {@code /bar.html} results in {@code http://localhost:3000/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo/} and sending request to {@code ./bar.html} results in
* {@code http://localhost:3000/foo/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000} and sending request to {@code /bar.html} results in {@code
* http://localhost:3000/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo/} and sending request to {@code ./bar.html} results in {@code
* http://localhost:3000/foo/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo} (without trailing slash) and navigating to {@code ./bar.html} results in
* {@code http://localhost:3000/bar.html}</li>
* </ul>
@@ -156,7 +159,8 @@ public interface APIRequest {
return this;
}
/**
* Maximum time in milliseconds to wait for the response. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout.
* Maximum time in milliseconds to wait for the response. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable
* timeout.
*/
public NewContextOptions setTimeout(double timeout) {
this.timeout = timeout;
@@ -172,12 +176,16 @@ public interface APIRequest {
}
/**
* Creates new instances of {@code APIRequestContext}.
*
* @since v1.16
*/
default APIRequestContext newContext() {
return newContext(null);
}
/**
* Creates new instances of {@code APIRequestContext}.
*
* @since v1.16
*/
APIRequestContext newContext(NewContextOptions options);
}
@@ -23,18 +23,18 @@ import java.nio.file.Path;
* This API is used for the Web API testing. You can use it to trigger API endpoints, configure micro-services, prepare
* environment or the service to your e2e test.
*
* <p> Each Playwright browser context has associated with it {@code APIRequestContext} instance which shares cookie storage with the
* browser context and can be accessed via {@link BrowserContext#request BrowserContext.request()} or {@link Page#request
* Page.request()}. It is also possible to create a new APIRequestContext instance manually by calling {@link
* <p> Each Playwright browser context has associated with it {@code APIRequestContext} instance which shares cookie storage
* with the browser context and can be accessed via {@link BrowserContext#request BrowserContext.request()} or {@link
* Page#request Page.request()}. It is also possible to create a new APIRequestContext instance manually by calling {@link
* APIRequest#newContext APIRequest.newContext()}.
*
* <p> **Cookie management**
*
* <p> {@code APIRequestContext} returned by {@link BrowserContext#request BrowserContext.request()} and {@link Page#request
* Page.request()} shares cookie storage with the corresponding {@code BrowserContext}. Each API request will have {@code Cookie}
* header populated with the values from the browser context. If the API response contains {@code Set-Cookie} header it will
* automatically update {@code BrowserContext} cookies and requests made from the page will pick them up. This means that if you
* log in using this API, your e2e test will be logged in and vice versa.
* Page.request()} shares cookie storage with the corresponding {@code BrowserContext}. Each API request will have {@code
* Cookie} header populated with the values from the browser context. If the API response contains {@code Set-Cookie}
* header it will automatically update {@code BrowserContext} cookies and requests made from the page will pick them up.
* This means that if you log in using this API, your e2e test will be logged in and vice versa.
*
* <p> If you want API requests to not interfere with the browser cookies you should create a new {@code APIRequestContext} by
* calling {@link APIRequest#newContext APIRequest.newContext()}. Such {@code APIRequestContext} object will have its own
@@ -63,6 +63,7 @@ public interface APIRequestContext {
* The method will automatically follow redirects.
*
* @param url Target URL.
* @since v1.16
*/
default APIResponse delete(String url) {
return delete(url, null);
@@ -74,19 +75,23 @@ public interface APIRequestContext {
*
* @param url Target URL.
* @param params Optional request parameters.
* @since v1.16
*/
APIResponse delete(String url, RequestOptions params);
/**
* All responses returned by {@link APIRequestContext#get APIRequestContext.get()} and similar methods are stored in the
* memory, so that you can later call {@link APIResponse#body APIResponse.body()}. This method discards all stored
* responses, and makes {@link APIResponse#body APIResponse.body()} throw "Response disposed" error.
*
* @since v1.16
*/
void dispose();
/**
* 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.
* context cookies from the response. The method will automatically follow redirects. JSON objects can be passed directly
* to the request.
*
* <p> JSON objects can be passed directly to the request:
* <p> **Usage**
* <pre>{@code
* Map<String, Object> data = new HashMap();
* data.put("title", "Book Title");
@@ -112,15 +117,17 @@ public interface APIRequestContext {
* }</pre>
*
* @param urlOrRequest Target URL or Request to get all parameters from.
* @since v1.16
*/
default APIResponse fetch(String urlOrRequest) {
return fetch(urlOrRequest, null);
}
/**
* 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.
* context cookies from the response. The method will automatically follow redirects. JSON objects can be passed directly
* to the request.
*
* <p> JSON objects can be passed directly to the request:
* <p> **Usage**
* <pre>{@code
* Map<String, Object> data = new HashMap();
* data.put("title", "Book Title");
@@ -147,13 +154,15 @@ public interface APIRequestContext {
*
* @param urlOrRequest Target URL or Request to get all parameters from.
* @param params Optional request parameters.
* @since v1.16
*/
APIResponse fetch(String urlOrRequest, RequestOptions params);
/**
* 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.
* context cookies from the response. The method will automatically follow redirects. JSON objects can be passed directly
* to the request.
*
* <p> JSON objects can be passed directly to the request:
* <p> **Usage**
* <pre>{@code
* Map<String, Object> data = new HashMap();
* data.put("title", "Book Title");
@@ -179,15 +188,17 @@ public interface APIRequestContext {
* }</pre>
*
* @param urlOrRequest Target URL or Request to get all parameters from.
* @since v1.16
*/
default APIResponse fetch(Request urlOrRequest) {
return fetch(urlOrRequest, null);
}
/**
* 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.
* context cookies from the response. The method will automatically follow redirects. JSON objects can be passed directly
* to the request.
*
* <p> JSON objects can be passed directly to the request:
* <p> **Usage**
* <pre>{@code
* Map<String, Object> data = new HashMap();
* data.put("title", "Book Title");
@@ -214,6 +225,7 @@ public interface APIRequestContext {
*
* @param urlOrRequest Target URL or Request to get all parameters from.
* @param params Optional request parameters.
* @since v1.16
*/
APIResponse fetch(Request urlOrRequest, RequestOptions params);
/**
@@ -221,6 +233,8 @@ 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> **Usage**
*
* <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()
@@ -229,6 +243,7 @@ public interface APIRequestContext {
* }</pre>
*
* @param url Target URL.
* @since v1.16
*/
default APIResponse get(String url) {
return get(url, null);
@@ -238,6 +253,8 @@ 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> **Usage**
*
* <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()
@@ -247,6 +264,7 @@ public interface APIRequestContext {
*
* @param url Target URL.
* @param params Optional request parameters.
* @since v1.16
*/
APIResponse get(String url, RequestOptions params);
/**
@@ -255,6 +273,7 @@ public interface APIRequestContext {
* method will automatically follow redirects.
*
* @param url Target URL.
* @since v1.16
*/
default APIResponse head(String url) {
return head(url, null);
@@ -266,6 +285,7 @@ public interface APIRequestContext {
*
* @param url Target URL.
* @param params Optional request parameters.
* @since v1.16
*/
APIResponse head(String url, RequestOptions params);
/**
@@ -274,6 +294,7 @@ public interface APIRequestContext {
* The method will automatically follow redirects.
*
* @param url Target URL.
* @since v1.16
*/
default APIResponse patch(String url) {
return patch(url, null);
@@ -285,6 +306,7 @@ public interface APIRequestContext {
*
* @param url Target URL.
* @param params Optional request parameters.
* @since v1.16
*/
APIResponse patch(String url, RequestOptions params);
/**
@@ -292,6 +314,8 @@ 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> **Usage**
*
* <p> JSON objects can be passed directly to the request:
* <pre>{@code
* Map<String, Object> data = new HashMap();
@@ -300,16 +324,17 @@ public interface APIRequestContext {
* 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):
* <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:
* <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");
@@ -326,6 +351,7 @@ public interface APIRequestContext {
* }</pre>
*
* @param url Target URL.
* @since v1.16
*/
default APIResponse post(String url) {
return post(url, null);
@@ -335,6 +361,8 @@ 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> **Usage**
*
* <p> JSON objects can be passed directly to the request:
* <pre>{@code
* Map<String, Object> data = new HashMap();
@@ -343,16 +371,17 @@ public interface APIRequestContext {
* 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):
* <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:
* <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");
@@ -370,6 +399,7 @@ public interface APIRequestContext {
*
* @param url Target URL.
* @param params Optional request parameters.
* @since v1.16
*/
APIResponse post(String url, RequestOptions params);
/**
@@ -378,6 +408,7 @@ public interface APIRequestContext {
* method will automatically follow redirects.
*
* @param url Target URL.
* @since v1.16
*/
default APIResponse put(String url) {
return put(url, null);
@@ -389,11 +420,14 @@ public interface APIRequestContext {
*
* @param url Target URL.
* @param params Optional request parameters.
* @since v1.16
*/
APIResponse put(String url, RequestOptions params);
/**
* Returns storage state for this request context, contains current cookies and local storage snapshot if it was passed to
* the constructor.
*
* @since v1.16
*/
default String storageState() {
return storageState(null);
@@ -401,6 +435,8 @@ public interface APIRequestContext {
/**
* Returns storage state for this request context, contains current cookies and local storage snapshot if it was passed to
* the constructor.
*
* @since v1.16
*/
String storageState(StorageStateOptions options);
}
@@ -20,45 +20,63 @@ import com.microsoft.playwright.options.*;
import java.util.*;
/**
* {@code APIResponse} class represents responses returned by {@link APIRequestContext#get APIRequestContext.get()} and similar
* methods.
* {@code APIResponse} class represents responses returned by {@link APIRequestContext#get APIRequestContext.get()} and
* similar methods.
*/
public interface APIResponse {
/**
* Returns the buffer with response body.
*
* @since v1.16
*/
byte[] body();
/**
* Disposes the body of this response. If not called then the body will stay in memory until the context closes.
*
* @since v1.16
*/
void dispose();
/**
* An object with all the response HTTP headers associated with this response.
*
* @since v1.16
*/
Map<String, String> headers();
/**
* An array with all the request HTTP headers associated with this response. Header names are not lower-cased. Headers with
* multiple entries, such as {@code Set-Cookie}, appear in the array multiple times.
*
* @since v1.16
*/
List<HttpHeader> headersArray();
/**
* Contains a boolean stating whether the response was successful (status in the range 200-299) or not.
*
* @since v1.16
*/
boolean ok();
/**
* Contains the status code of the response (e.g., 200 for a success).
*
* @since v1.16
*/
int status();
/**
* Contains the status text of the response (e.g. usually an "OK" for a success).
*
* @since v1.16
*/
String statusText();
/**
* Returns the text representation of response body.
*
* @since v1.16
*/
String text();
/**
* Contains the URL of the response.
*
* @since v1.16
*/
String url();
}
@@ -23,8 +23,8 @@ import java.util.function.Consumer;
import java.util.regex.Pattern;
/**
* A Browser is created via {@link BrowserType#launch BrowserType.launch()}. An example of using a {@code Browser} to create a
* {@code Page}:
* A Browser is created via {@link BrowserType#launch BrowserType.launch()}. An example of using a {@code Browser} to
* create a {@code Page}:
* <pre>{@code
* import com.microsoft.playwright.*;
*
@@ -65,11 +65,13 @@ public interface Browser extends AutoCloseable {
* When using {@link Page#navigate Page.navigate()}, {@link Page#route Page.route()}, {@link Page#waitForURL
* Page.waitForURL()}, {@link Page#waitForRequest Page.waitForRequest()}, or {@link Page#waitForResponse
* Page.waitForResponse()} it takes the base URL in consideration by using the <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code URL()}</a> constructor for building the corresponding
* URL. Examples:
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code URL()}</a> constructor for building the
* corresponding URL. Examples:
* <ul>
* <li> baseURL: {@code http://localhost:3000} and navigating to {@code /bar.html} results in {@code http://localhost:3000/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo/} and navigating to {@code ./bar.html} results in {@code http://localhost:3000/foo/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000} and navigating to {@code /bar.html} results in {@code
* http://localhost:3000/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo/} and navigating to {@code ./bar.html} results in {@code
* http://localhost:3000/foo/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo} (without trailing slash) and navigating to {@code ./bar.html} results in
* {@code http://localhost:3000/bar.html}</li>
* </ul>
@@ -80,9 +82,9 @@ public interface Browser extends AutoCloseable {
*/
public Boolean bypassCSP;
/**
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code "no-preference"}. See
* {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults.
* Defaults to {@code "light"}.
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code
* "no-preference"}. See {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets
* emulation to system defaults. Defaults to {@code "light"}.
*/
public Optional<ColorScheme> colorScheme;
/**
@@ -94,8 +96,9 @@ public interface Browser extends AutoCloseable {
*/
public Map<String, String> extraHTTPHeaders;
/**
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"}, {@code "none"}. See {@link Page#emulateMedia
* Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to {@code "none"}.
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"}, {@code "none"}. See {@link
* Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults.
* Defaults to {@code "none"}.
*/
public Optional<ForcedColors> forcedColors;
public Geolocation geolocation;
@@ -112,8 +115,8 @@ public interface Browser extends AutoCloseable {
*/
public Boolean ignoreHTTPSErrors;
/**
* Whether the {@code meta viewport} tag is taken into account and touch events are enabled. Defaults to {@code false}. Not supported
* in Firefox.
* Whether the {@code meta viewport} tag is taken into account and touch events are enabled. Defaults to {@code false}. Not
* supported in Firefox.
*/
public Boolean isMobile;
/**
@@ -121,8 +124,8 @@ public interface Browser extends AutoCloseable {
*/
public Boolean javaScriptEnabled;
/**
* Specify user locale, for example {@code en-GB}, {@code de-DE}, etc. Locale will affect {@code navigator.language} value, {@code Accept-Language}
* request header value as well as number and date formatting rules.
* Specify user locale, for example {@code en-GB}, {@code de-DE}, etc. Locale will affect {@code navigator.language} value,
* {@code Accept-Language} request header value as well as number and date formatting rules.
*/
public String locale;
/**
@@ -143,14 +146,15 @@ 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 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.
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If
* {@code attach} 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;
/**
* When set to {@code minimal}, only record information necessary for routing from HAR. This omits sizes, timing, page, cookies,
* security and other types of HAR information that are not used when replaying from HAR. Defaults to {@code full}.
* When set to {@code minimal}, only record information necessary for routing from HAR. This omits sizes, timing, page,
* cookies, security and other types of HAR information that are not used when replaying from HAR. Defaults to {@code
* full}.
*/
public HarMode recordHarMode;
/**
@@ -171,26 +175,26 @@ public interface Browser extends AutoCloseable {
public Path recordVideoDir;
/**
* Dimensions of the recorded videos. If not specified the size will be equal to {@code viewport} scaled down to fit into
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each page will
* be scaled down if necessary to fit the specified size.
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each
* page will be scaled down if necessary to fit the specified size.
*/
public RecordVideoSize recordVideoSize;
/**
* Emulates {@code "prefers-reduced-motion"} media feature, supported values are {@code "reduce"}, {@code "no-preference"}. See {@link
* Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to
* {@code "no-preference"}.
* Emulates {@code "prefers-reduced-motion"} media feature, supported values are {@code "reduce"}, {@code "no-preference"}.
* See {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system
* defaults. Defaults to {@code "no-preference"}.
*/
public Optional<ReducedMotion> reducedMotion;
/**
* Emulates consistent window screen size available inside web page via {@code window.screen}. Is only used when the {@code viewport}
* is set.
* Emulates consistent window screen size available inside web page via {@code window.screen}. Is only used when the {@code
* viewport} is set.
*/
public ScreenSize screenSize;
/**
* Whether to allow sites to register Service workers. Defaults to {@code "allow"}.
* <ul>
* <li> {@code "allow"}: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API">Service Workers</a> can be
* registered.</li>
* <li> {@code "allow"}: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API">Service Workers</a> can
* be registered.</li>
* <li> {@code "block"}: Playwright will block all registration of Service Workers.</li>
* </ul>
*/
@@ -207,9 +211,9 @@ public interface Browser extends AutoCloseable {
*/
public Path storageStatePath;
/**
* If specified, enables strict selectors mode for this context. In the strict selectors mode all operations on selectors
* that imply single target DOM element will throw when more than one element matches the selector. See {@code Locator} to learn
* more about the strict mode.
* If set to true, enables strict selectors mode for this context. In the strict selectors mode all operations on selectors
* that imply single target DOM element will throw when more than one element matches the selector. This option does not
* affect any Locator APIs (Locators are always strict). See {@code Locator} to learn more about the strict mode.
*/
public Boolean strictSelectors;
/**
@@ -223,7 +227,11 @@ public interface Browser extends AutoCloseable {
*/
public String userAgent;
/**
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default viewport.
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. Use {@code null} to disable the consistent
* viewport emulation.
*
* <p> <strong>NOTE:</strong> The {@code null} value opts out from the default presets, makes viewport depend on the host window size defined by the
* operating system. It makes the execution of the tests non-deterministic.
*/
public Optional<ViewportSize> viewportSize;
@@ -238,11 +246,13 @@ public interface Browser extends AutoCloseable {
* When using {@link Page#navigate Page.navigate()}, {@link Page#route Page.route()}, {@link Page#waitForURL
* Page.waitForURL()}, {@link Page#waitForRequest Page.waitForRequest()}, or {@link Page#waitForResponse
* Page.waitForResponse()} it takes the base URL in consideration by using the <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code URL()}</a> constructor for building the corresponding
* URL. Examples:
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code URL()}</a> constructor for building the
* corresponding URL. Examples:
* <ul>
* <li> baseURL: {@code http://localhost:3000} and navigating to {@code /bar.html} results in {@code http://localhost:3000/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo/} and navigating to {@code ./bar.html} results in {@code http://localhost:3000/foo/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000} and navigating to {@code /bar.html} results in {@code
* http://localhost:3000/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo/} and navigating to {@code ./bar.html} results in {@code
* http://localhost:3000/foo/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo} (without trailing slash) and navigating to {@code ./bar.html} results in
* {@code http://localhost:3000/bar.html}</li>
* </ul>
@@ -259,9 +269,9 @@ public interface Browser extends AutoCloseable {
return this;
}
/**
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code "no-preference"}. See
* {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults.
* Defaults to {@code "light"}.
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code
* "no-preference"}. See {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets
* emulation to system defaults. Defaults to {@code "light"}.
*/
public NewContextOptions setColorScheme(ColorScheme colorScheme) {
this.colorScheme = Optional.ofNullable(colorScheme);
@@ -282,8 +292,9 @@ public interface Browser extends AutoCloseable {
return this;
}
/**
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"}, {@code "none"}. See {@link Page#emulateMedia
* Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to {@code "none"}.
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"}, {@code "none"}. See {@link
* Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults.
* Defaults to {@code "none"}.
*/
public NewContextOptions setForcedColors(ForcedColors forcedColors) {
this.forcedColors = Optional.ofNullable(forcedColors);
@@ -324,8 +335,8 @@ public interface Browser extends AutoCloseable {
return this;
}
/**
* Whether the {@code meta viewport} tag is taken into account and touch events are enabled. Defaults to {@code false}. Not supported
* in Firefox.
* Whether the {@code meta viewport} tag is taken into account and touch events are enabled. Defaults to {@code false}. Not
* supported in Firefox.
*/
public NewContextOptions setIsMobile(boolean isMobile) {
this.isMobile = isMobile;
@@ -339,8 +350,8 @@ public interface Browser extends AutoCloseable {
return this;
}
/**
* Specify user locale, for example {@code en-GB}, {@code de-DE}, etc. Locale will affect {@code navigator.language} value, {@code Accept-Language}
* request header value as well as number and date formatting rules.
* Specify user locale, for example {@code en-GB}, {@code de-DE}, etc. Locale will affect {@code navigator.language} value,
* {@code Accept-Language} request header value as well as number and date formatting rules.
*/
public NewContextOptions setLocale(String locale) {
this.locale = locale;
@@ -383,17 +394,18 @@ public interface Browser extends AutoCloseable {
return this;
}
/**
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If {@code attach}
* 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.
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If
* {@code attach} 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) {
this.recordHarContent = recordHarContent;
return this;
}
/**
* When set to {@code minimal}, only record information necessary for routing from HAR. This omits sizes, timing, page, cookies,
* security and other types of HAR information that are not used when replaying from HAR. Defaults to {@code full}.
* When set to {@code minimal}, only record information necessary for routing from HAR. This omits sizes, timing, page,
* cookies, security and other types of HAR information that are not used when replaying from HAR. Defaults to {@code
* full}.
*/
public NewContextOptions setRecordHarMode(HarMode recordHarMode) {
this.recordHarMode = recordHarMode;
@@ -433,40 +445,40 @@ public interface Browser extends AutoCloseable {
}
/**
* Dimensions of the recorded videos. If not specified the size will be equal to {@code viewport} scaled down to fit into
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each page will
* be scaled down if necessary to fit the specified size.
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each
* page will be scaled down if necessary to fit the specified size.
*/
public NewContextOptions setRecordVideoSize(int width, int height) {
return setRecordVideoSize(new RecordVideoSize(width, height));
}
/**
* Dimensions of the recorded videos. If not specified the size will be equal to {@code viewport} scaled down to fit into
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each page will
* be scaled down if necessary to fit the specified size.
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each
* page will be scaled down if necessary to fit the specified size.
*/
public NewContextOptions setRecordVideoSize(RecordVideoSize recordVideoSize) {
this.recordVideoSize = recordVideoSize;
return this;
}
/**
* Emulates {@code "prefers-reduced-motion"} media feature, supported values are {@code "reduce"}, {@code "no-preference"}. See {@link
* Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to
* {@code "no-preference"}.
* Emulates {@code "prefers-reduced-motion"} media feature, supported values are {@code "reduce"}, {@code "no-preference"}.
* See {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system
* defaults. Defaults to {@code "no-preference"}.
*/
public NewContextOptions setReducedMotion(ReducedMotion reducedMotion) {
this.reducedMotion = Optional.ofNullable(reducedMotion);
return this;
}
/**
* Emulates consistent window screen size available inside web page via {@code window.screen}. Is only used when the {@code viewport}
* is set.
* Emulates consistent window screen size available inside web page via {@code window.screen}. Is only used when the {@code
* viewport} is set.
*/
public NewContextOptions setScreenSize(int width, int height) {
return setScreenSize(new ScreenSize(width, height));
}
/**
* Emulates consistent window screen size available inside web page via {@code window.screen}. Is only used when the {@code viewport}
* is set.
* Emulates consistent window screen size available inside web page via {@code window.screen}. Is only used when the {@code
* viewport} is set.
*/
public NewContextOptions setScreenSize(ScreenSize screenSize) {
this.screenSize = screenSize;
@@ -475,8 +487,8 @@ public interface Browser extends AutoCloseable {
/**
* Whether to allow sites to register Service workers. Defaults to {@code "allow"}.
* <ul>
* <li> {@code "allow"}: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API">Service Workers</a> can be
* registered.</li>
* <li> {@code "allow"}: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API">Service Workers</a> can
* be registered.</li>
* <li> {@code "block"}: Playwright will block all registration of Service Workers.</li>
* </ul>
*/
@@ -502,9 +514,9 @@ public interface Browser extends AutoCloseable {
return this;
}
/**
* If specified, enables strict selectors mode for this context. In the strict selectors mode all operations on selectors
* that imply single target DOM element will throw when more than one element matches the selector. See {@code Locator} to learn
* more about the strict mode.
* If set to true, enables strict selectors mode for this context. In the strict selectors mode all operations on selectors
* that imply single target DOM element will throw when more than one element matches the selector. This option does not
* affect any Locator APIs (Locators are always strict). See {@code Locator} to learn more about the strict mode.
*/
public NewContextOptions setStrictSelectors(boolean strictSelectors) {
this.strictSelectors = strictSelectors;
@@ -527,13 +539,21 @@ public interface Browser extends AutoCloseable {
return this;
}
/**
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default viewport.
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. Use {@code null} to disable the consistent
* viewport emulation.
*
* <p> <strong>NOTE:</strong> The {@code null} value opts out from the default presets, makes viewport depend on the host window size defined by the
* operating system. It makes the execution of the tests non-deterministic.
*/
public NewContextOptions setViewportSize(int width, int height) {
return setViewportSize(new ViewportSize(width, height));
}
/**
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default viewport.
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. Use {@code null} to disable the consistent
* viewport emulation.
*
* <p> <strong>NOTE:</strong> The {@code null} value opts out from the default presets, makes viewport depend on the host window size defined by the
* operating system. It makes the execution of the tests non-deterministic.
*/
public NewContextOptions setViewportSize(ViewportSize viewportSize) {
this.viewportSize = Optional.ofNullable(viewportSize);
@@ -549,11 +569,13 @@ public interface Browser extends AutoCloseable {
* When using {@link Page#navigate Page.navigate()}, {@link Page#route Page.route()}, {@link Page#waitForURL
* Page.waitForURL()}, {@link Page#waitForRequest Page.waitForRequest()}, or {@link Page#waitForResponse
* Page.waitForResponse()} it takes the base URL in consideration by using the <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code URL()}</a> constructor for building the corresponding
* URL. Examples:
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code URL()}</a> constructor for building the
* corresponding URL. Examples:
* <ul>
* <li> baseURL: {@code http://localhost:3000} and navigating to {@code /bar.html} results in {@code http://localhost:3000/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo/} and navigating to {@code ./bar.html} results in {@code http://localhost:3000/foo/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000} and navigating to {@code /bar.html} results in {@code
* http://localhost:3000/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo/} and navigating to {@code ./bar.html} results in {@code
* http://localhost:3000/foo/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo} (without trailing slash) and navigating to {@code ./bar.html} results in
* {@code http://localhost:3000/bar.html}</li>
* </ul>
@@ -564,9 +586,9 @@ public interface Browser extends AutoCloseable {
*/
public Boolean bypassCSP;
/**
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code "no-preference"}. See
* {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults.
* Defaults to {@code "light"}.
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code
* "no-preference"}. See {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets
* emulation to system defaults. Defaults to {@code "light"}.
*/
public Optional<ColorScheme> colorScheme;
/**
@@ -578,8 +600,9 @@ public interface Browser extends AutoCloseable {
*/
public Map<String, String> extraHTTPHeaders;
/**
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"}, {@code "none"}. See {@link Page#emulateMedia
* Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to {@code "none"}.
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"}, {@code "none"}. See {@link
* Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults.
* Defaults to {@code "none"}.
*/
public Optional<ForcedColors> forcedColors;
public Geolocation geolocation;
@@ -596,8 +619,8 @@ public interface Browser extends AutoCloseable {
*/
public Boolean ignoreHTTPSErrors;
/**
* Whether the {@code meta viewport} tag is taken into account and touch events are enabled. Defaults to {@code false}. Not supported
* in Firefox.
* Whether the {@code meta viewport} tag is taken into account and touch events are enabled. Defaults to {@code false}. Not
* supported in Firefox.
*/
public Boolean isMobile;
/**
@@ -605,8 +628,8 @@ public interface Browser extends AutoCloseable {
*/
public Boolean javaScriptEnabled;
/**
* Specify user locale, for example {@code en-GB}, {@code de-DE}, etc. Locale will affect {@code navigator.language} value, {@code Accept-Language}
* request header value as well as number and date formatting rules.
* Specify user locale, for example {@code en-GB}, {@code de-DE}, etc. Locale will affect {@code navigator.language} value,
* {@code Accept-Language} request header value as well as number and date formatting rules.
*/
public String locale;
/**
@@ -627,14 +650,15 @@ 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 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.
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If
* {@code attach} 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;
/**
* When set to {@code minimal}, only record information necessary for routing from HAR. This omits sizes, timing, page, cookies,
* security and other types of HAR information that are not used when replaying from HAR. Defaults to {@code full}.
* When set to {@code minimal}, only record information necessary for routing from HAR. This omits sizes, timing, page,
* cookies, security and other types of HAR information that are not used when replaying from HAR. Defaults to {@code
* full}.
*/
public HarMode recordHarMode;
/**
@@ -655,26 +679,26 @@ public interface Browser extends AutoCloseable {
public Path recordVideoDir;
/**
* Dimensions of the recorded videos. If not specified the size will be equal to {@code viewport} scaled down to fit into
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each page will
* be scaled down if necessary to fit the specified size.
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each
* page will be scaled down if necessary to fit the specified size.
*/
public RecordVideoSize recordVideoSize;
/**
* Emulates {@code "prefers-reduced-motion"} media feature, supported values are {@code "reduce"}, {@code "no-preference"}. See {@link
* Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to
* {@code "no-preference"}.
* Emulates {@code "prefers-reduced-motion"} media feature, supported values are {@code "reduce"}, {@code "no-preference"}.
* See {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system
* defaults. Defaults to {@code "no-preference"}.
*/
public Optional<ReducedMotion> reducedMotion;
/**
* Emulates consistent window screen size available inside web page via {@code window.screen}. Is only used when the {@code viewport}
* is set.
* Emulates consistent window screen size available inside web page via {@code window.screen}. Is only used when the {@code
* viewport} is set.
*/
public ScreenSize screenSize;
/**
* Whether to allow sites to register Service workers. Defaults to {@code "allow"}.
* <ul>
* <li> {@code "allow"}: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API">Service Workers</a> can be
* registered.</li>
* <li> {@code "allow"}: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API">Service Workers</a> can
* be registered.</li>
* <li> {@code "block"}: Playwright will block all registration of Service Workers.</li>
* </ul>
*/
@@ -691,9 +715,9 @@ public interface Browser extends AutoCloseable {
*/
public Path storageStatePath;
/**
* If specified, enables strict selectors mode for this context. In the strict selectors mode all operations on selectors
* that imply single target DOM element will throw when more than one element matches the selector. See {@code Locator} to learn
* more about the strict mode.
* If set to true, enables strict selectors mode for this context. In the strict selectors mode all operations on selectors
* that imply single target DOM element will throw when more than one element matches the selector. This option does not
* affect any Locator APIs (Locators are always strict). See {@code Locator} to learn more about the strict mode.
*/
public Boolean strictSelectors;
/**
@@ -707,7 +731,11 @@ public interface Browser extends AutoCloseable {
*/
public String userAgent;
/**
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default viewport.
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. Use {@code null} to disable the consistent
* viewport emulation.
*
* <p> <strong>NOTE:</strong> The {@code null} value opts out from the default presets, makes viewport depend on the host window size defined by the
* operating system. It makes the execution of the tests non-deterministic.
*/
public Optional<ViewportSize> viewportSize;
@@ -722,11 +750,13 @@ public interface Browser extends AutoCloseable {
* When using {@link Page#navigate Page.navigate()}, {@link Page#route Page.route()}, {@link Page#waitForURL
* Page.waitForURL()}, {@link Page#waitForRequest Page.waitForRequest()}, or {@link Page#waitForResponse
* Page.waitForResponse()} it takes the base URL in consideration by using the <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code URL()}</a> constructor for building the corresponding
* URL. Examples:
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code URL()}</a> constructor for building the
* corresponding URL. Examples:
* <ul>
* <li> baseURL: {@code http://localhost:3000} and navigating to {@code /bar.html} results in {@code http://localhost:3000/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo/} and navigating to {@code ./bar.html} results in {@code http://localhost:3000/foo/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000} and navigating to {@code /bar.html} results in {@code
* http://localhost:3000/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo/} and navigating to {@code ./bar.html} results in {@code
* http://localhost:3000/foo/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo} (without trailing slash) and navigating to {@code ./bar.html} results in
* {@code http://localhost:3000/bar.html}</li>
* </ul>
@@ -743,9 +773,9 @@ public interface Browser extends AutoCloseable {
return this;
}
/**
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code "no-preference"}. See
* {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults.
* Defaults to {@code "light"}.
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code
* "no-preference"}. See {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets
* emulation to system defaults. Defaults to {@code "light"}.
*/
public NewPageOptions setColorScheme(ColorScheme colorScheme) {
this.colorScheme = Optional.ofNullable(colorScheme);
@@ -766,8 +796,9 @@ public interface Browser extends AutoCloseable {
return this;
}
/**
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"}, {@code "none"}. See {@link Page#emulateMedia
* Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to {@code "none"}.
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"}, {@code "none"}. See {@link
* Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults.
* Defaults to {@code "none"}.
*/
public NewPageOptions setForcedColors(ForcedColors forcedColors) {
this.forcedColors = Optional.ofNullable(forcedColors);
@@ -808,8 +839,8 @@ public interface Browser extends AutoCloseable {
return this;
}
/**
* Whether the {@code meta viewport} tag is taken into account and touch events are enabled. Defaults to {@code false}. Not supported
* in Firefox.
* Whether the {@code meta viewport} tag is taken into account and touch events are enabled. Defaults to {@code false}. Not
* supported in Firefox.
*/
public NewPageOptions setIsMobile(boolean isMobile) {
this.isMobile = isMobile;
@@ -823,8 +854,8 @@ public interface Browser extends AutoCloseable {
return this;
}
/**
* Specify user locale, for example {@code en-GB}, {@code de-DE}, etc. Locale will affect {@code navigator.language} value, {@code Accept-Language}
* request header value as well as number and date formatting rules.
* Specify user locale, for example {@code en-GB}, {@code de-DE}, etc. Locale will affect {@code navigator.language} value,
* {@code Accept-Language} request header value as well as number and date formatting rules.
*/
public NewPageOptions setLocale(String locale) {
this.locale = locale;
@@ -867,17 +898,18 @@ public interface Browser extends AutoCloseable {
return this;
}
/**
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If {@code attach}
* 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.
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If
* {@code attach} 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) {
this.recordHarContent = recordHarContent;
return this;
}
/**
* When set to {@code minimal}, only record information necessary for routing from HAR. This omits sizes, timing, page, cookies,
* security and other types of HAR information that are not used when replaying from HAR. Defaults to {@code full}.
* When set to {@code minimal}, only record information necessary for routing from HAR. This omits sizes, timing, page,
* cookies, security and other types of HAR information that are not used when replaying from HAR. Defaults to {@code
* full}.
*/
public NewPageOptions setRecordHarMode(HarMode recordHarMode) {
this.recordHarMode = recordHarMode;
@@ -917,40 +949,40 @@ public interface Browser extends AutoCloseable {
}
/**
* Dimensions of the recorded videos. If not specified the size will be equal to {@code viewport} scaled down to fit into
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each page will
* be scaled down if necessary to fit the specified size.
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each
* page will be scaled down if necessary to fit the specified size.
*/
public NewPageOptions setRecordVideoSize(int width, int height) {
return setRecordVideoSize(new RecordVideoSize(width, height));
}
/**
* Dimensions of the recorded videos. If not specified the size will be equal to {@code viewport} scaled down to fit into
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each page will
* be scaled down if necessary to fit the specified size.
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each
* page will be scaled down if necessary to fit the specified size.
*/
public NewPageOptions setRecordVideoSize(RecordVideoSize recordVideoSize) {
this.recordVideoSize = recordVideoSize;
return this;
}
/**
* Emulates {@code "prefers-reduced-motion"} media feature, supported values are {@code "reduce"}, {@code "no-preference"}. See {@link
* Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to
* {@code "no-preference"}.
* Emulates {@code "prefers-reduced-motion"} media feature, supported values are {@code "reduce"}, {@code "no-preference"}.
* See {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system
* defaults. Defaults to {@code "no-preference"}.
*/
public NewPageOptions setReducedMotion(ReducedMotion reducedMotion) {
this.reducedMotion = Optional.ofNullable(reducedMotion);
return this;
}
/**
* Emulates consistent window screen size available inside web page via {@code window.screen}. Is only used when the {@code viewport}
* is set.
* Emulates consistent window screen size available inside web page via {@code window.screen}. Is only used when the {@code
* viewport} is set.
*/
public NewPageOptions setScreenSize(int width, int height) {
return setScreenSize(new ScreenSize(width, height));
}
/**
* Emulates consistent window screen size available inside web page via {@code window.screen}. Is only used when the {@code viewport}
* is set.
* Emulates consistent window screen size available inside web page via {@code window.screen}. Is only used when the {@code
* viewport} is set.
*/
public NewPageOptions setScreenSize(ScreenSize screenSize) {
this.screenSize = screenSize;
@@ -959,8 +991,8 @@ public interface Browser extends AutoCloseable {
/**
* Whether to allow sites to register Service workers. Defaults to {@code "allow"}.
* <ul>
* <li> {@code "allow"}: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API">Service Workers</a> can be
* registered.</li>
* <li> {@code "allow"}: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API">Service Workers</a> can
* be registered.</li>
* <li> {@code "block"}: Playwright will block all registration of Service Workers.</li>
* </ul>
*/
@@ -986,9 +1018,9 @@ public interface Browser extends AutoCloseable {
return this;
}
/**
* If specified, enables strict selectors mode for this context. In the strict selectors mode all operations on selectors
* that imply single target DOM element will throw when more than one element matches the selector. See {@code Locator} to learn
* more about the strict mode.
* If set to true, enables strict selectors mode for this context. In the strict selectors mode all operations on selectors
* that imply single target DOM element will throw when more than one element matches the selector. This option does not
* affect any Locator APIs (Locators are always strict). See {@code Locator} to learn more about the strict mode.
*/
public NewPageOptions setStrictSelectors(boolean strictSelectors) {
this.strictSelectors = strictSelectors;
@@ -1011,13 +1043,21 @@ public interface Browser extends AutoCloseable {
return this;
}
/**
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default viewport.
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. Use {@code null} to disable the consistent
* viewport emulation.
*
* <p> <strong>NOTE:</strong> The {@code null} value opts out from the default presets, makes viewport depend on the host window size defined by the
* operating system. It makes the execution of the tests non-deterministic.
*/
public NewPageOptions setViewportSize(int width, int height) {
return setViewportSize(new ViewportSize(width, height));
}
/**
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default viewport.
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. Use {@code null} to disable the consistent
* viewport emulation.
*
* <p> <strong>NOTE:</strong> The {@code null} value opts out from the default presets, makes viewport depend on the host window size defined by the
* operating system. It makes the execution of the tests non-deterministic.
*/
public NewPageOptions setViewportSize(ViewportSize viewportSize) {
this.viewportSize = Optional.ofNullable(viewportSize);
@@ -1062,6 +1102,8 @@ public interface Browser extends AutoCloseable {
}
/**
* Get the browser type (chromium, firefox or webkit) that the browser belongs to.
*
* @since v1.23
*/
BrowserType browserType();
/**
@@ -1076,29 +1118,39 @@ public interface Browser extends AutoCloseable {
* Browser.newContext()} **before** calling {@link Browser#close Browser.close()}.
*
* <p> The {@code Browser} object itself is considered to be disposed and cannot be used anymore.
*
* @since v1.8
*/
void close();
/**
* Returns an array of all open browser contexts. In a newly created browser, this will return zero browser contexts.
*
* <p> **Usage**
* <pre>{@code
* Browser browser = pw.webkit().launch();
* System.out.println(browser.contexts().size()); // prints "0"
* BrowserContext context = browser.newContext();
* System.out.println(browser.contexts().size()); // prints "1"
* }</pre>
*
* @since v1.8
*/
List<BrowserContext> contexts();
/**
* Indicates that the browser is connected.
*
* @since v1.8
*/
boolean isConnected();
/**
* Creates a new browser context. It won't share cookies/cache with other browser contexts.
*
* <p> <strong>NOTE:</strong> If directly using this method to create {@code BrowserContext}s, it is best practice to explicitly close the returned context
* via {@link BrowserContext#close BrowserContext.close()} when your code is done with the {@code BrowserContext}, and before
* calling {@link Browser#close Browser.close()}. This will ensure the {@code context} is closed gracefully and any
* artifacts—like HARs and videos—are fully flushed and saved.
* <p> <strong>NOTE:</strong> If directly using this method to create {@code BrowserContext}s, it is best practice to explicitly close the returned
* context via {@link BrowserContext#close BrowserContext.close()} when your code is done with the {@code BrowserContext},
* and before calling {@link Browser#close Browser.close()}. This will ensure the {@code context} is closed gracefully and
* any artifacts—like HARs and videos—are fully flushed and saved.
*
* <p> **Usage**
* <pre>{@code
* Browser browser = playwright.firefox().launch(); // Or 'chromium' or 'webkit'.
* // Create a new incognito browser context.
@@ -1111,6 +1163,8 @@ public interface Browser extends AutoCloseable {
* context.close();
* browser.close();
* }</pre>
*
* @since v1.8
*/
default BrowserContext newContext() {
return newContext(null);
@@ -1118,10 +1172,12 @@ public interface Browser extends AutoCloseable {
/**
* Creates a new browser context. It won't share cookies/cache with other browser contexts.
*
* <p> <strong>NOTE:</strong> If directly using this method to create {@code BrowserContext}s, it is best practice to explicitly close the returned context
* via {@link BrowserContext#close BrowserContext.close()} when your code is done with the {@code BrowserContext}, and before
* calling {@link Browser#close Browser.close()}. This will ensure the {@code context} is closed gracefully and any
* artifacts—like HARs and videos—are fully flushed and saved.
* <p> <strong>NOTE:</strong> If directly using this method to create {@code BrowserContext}s, it is best practice to explicitly close the returned
* context via {@link BrowserContext#close BrowserContext.close()} when your code is done with the {@code BrowserContext},
* and before calling {@link Browser#close Browser.close()}. This will ensure the {@code context} is closed gracefully and
* any artifacts—like HARs and videos—are fully flushed and saved.
*
* <p> **Usage**
* <pre>{@code
* Browser browser = playwright.firefox().launch(); // Or 'chromium' or 'webkit'.
* // Create a new incognito browser context.
@@ -1134,6 +1190,8 @@ public interface Browser extends AutoCloseable {
* context.close();
* browser.close();
* }</pre>
*
* @since v1.8
*/
BrowserContext newContext(NewContextOptions options);
/**
@@ -1142,6 +1200,8 @@ public interface Browser extends AutoCloseable {
* <p> This is a convenience API that should only be used for the single-page scenarios and short snippets. Production code and
* testing frameworks should explicitly create {@link Browser#newContext Browser.newContext()} followed by the {@link
* BrowserContext#newPage BrowserContext.newPage()} to control their exact life times.
*
* @since v1.8
*/
default Page newPage() {
return newPage(null);
@@ -1152,6 +1212,8 @@ public interface Browser extends AutoCloseable {
* <p> This is a convenience API that should only be used for the single-page scenarios and short snippets. Production code and
* testing frameworks should explicitly create {@link Browser#newContext Browser.newContext()} followed by the {@link
* BrowserContext#newPage BrowserContext.newPage()} to control their exact life times.
*
* @since v1.8
*/
Page newPage(NewPageOptions options);
/**
@@ -1162,6 +1224,8 @@ public interface Browser extends AutoCloseable {
*
* <p> You can use {@link Browser#startTracing Browser.startTracing()} and {@link Browser#stopTracing Browser.stopTracing()} to
* create a trace file that can be opened in Chrome DevTools performance panel.
*
* <p> **Usage**
* <pre>{@code
* browser.startTracing(page, new Browser.StartTracingOptions()
* .setPath(Paths.get("trace.json")));
@@ -1170,6 +1234,7 @@ public interface Browser extends AutoCloseable {
* }</pre>
*
* @param page Optional, if specified, tracing includes screenshots of the given page.
* @since v1.11
*/
default void startTracing(Page page) {
startTracing(page, null);
@@ -1182,12 +1247,16 @@ public interface Browser extends AutoCloseable {
*
* <p> You can use {@link Browser#startTracing Browser.startTracing()} and {@link Browser#stopTracing Browser.stopTracing()} to
* create a trace file that can be opened in Chrome DevTools performance panel.
*
* <p> **Usage**
* <pre>{@code
* browser.startTracing(page, new Browser.StartTracingOptions()
* .setPath(Paths.get("trace.json")));
* page.goto('https://www.google.com');
* browser.stopTracing();
* }</pre>
*
* @since v1.11
*/
default void startTracing() {
startTracing(null);
@@ -1200,6 +1269,8 @@ public interface Browser extends AutoCloseable {
*
* <p> You can use {@link Browser#startTracing Browser.startTracing()} and {@link Browser#stopTracing Browser.stopTracing()} to
* create a trace file that can be opened in Chrome DevTools performance panel.
*
* <p> **Usage**
* <pre>{@code
* browser.startTracing(page, new Browser.StartTracingOptions()
* .setPath(Paths.get("trace.json")));
@@ -1208,6 +1279,7 @@ public interface Browser extends AutoCloseable {
* }</pre>
*
* @param page Optional, if specified, tracing includes screenshots of the given page.
* @since v1.11
*/
void startTracing(Page page, StartTracingOptions options);
/**
@@ -1217,10 +1289,14 @@ public interface Browser extends AutoCloseable {
* href="https://playwright.dev/java/docs/api/class-tracing">here</a>.
*
* <p> Returns the buffer with trace data.
*
* @since v1.11
*/
byte[] stopTracing();
/**
* Returns the browser version.
*
* @since v1.8
*/
String version();
}
@@ -63,11 +63,11 @@ public interface BrowserContext extends AutoCloseable {
* specific page.
*
* <p> The earliest moment that page is available is when it has navigated to the initial url. For example, when opening a
* popup with {@code window.open('http://example.com')}, this event will fire when the network request to "http://example.com" is
* done and its response has started loading in the popup.
* popup with {@code window.open('http://example.com')}, this event will fire when the network request to
* "http://example.com" is done and its response has started loading in the popup.
* <pre>{@code
* Page newPage = context.waitForPage(() -> {
* page.locator("a[target=_blank]").click();
* page.getByText("open new page").click();
* });
* System.out.println(newPage.evaluate("location.href"));
* }</pre>
@@ -110,8 +110,8 @@ public interface BrowserContext extends AutoCloseable {
/**
* Emitted when a request finishes successfully after downloading the response body. For a successful response, the
* sequence of events is {@code request}, {@code response} and {@code requestfinished}. To listen for successful requests from a particular
* page, use {@link Page#onRequestFinished Page.onRequestFinished()}.
* sequence of events is {@code request}, {@code response} and {@code requestfinished}. To listen for successful requests
* from a particular page, use {@link Page#onRequestFinished Page.onRequestFinished()}.
*/
void onRequestFinished(Consumer<Request> handler);
/**
@@ -121,8 +121,8 @@ public interface BrowserContext extends AutoCloseable {
/**
* Emitted when [response] status and headers are received for a request. For a successful response, the sequence of events
* is {@code request}, {@code response} and {@code requestfinished}. To listen for response events from a particular page, use {@link
* Page#onResponse Page.onResponse()}.
* is {@code request}, {@code response} and {@code requestfinished}. To listen for response events from a particular page,
* use {@link Page#onResponse Page.onResponse()}.
*/
void onResponse(Consumer<Response> handler);
/**
@@ -254,8 +254,8 @@ public interface BrowserContext extends AutoCloseable {
*/
public Predicate<Page> predicate;
/**
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
* value can be changed by using the {@link BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()}.
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The
* default value can be changed by using the {@link BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()}.
*/
public Double timeout;
@@ -267,8 +267,8 @@ public interface BrowserContext extends AutoCloseable {
return this;
}
/**
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
* value can be changed by using the {@link BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()}.
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The
* default value can be changed by using the {@link BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()}.
*/
public WaitForPageOptions setTimeout(double timeout) {
this.timeout = timeout;
@@ -278,9 +278,13 @@ public interface BrowserContext extends AutoCloseable {
/**
* Adds cookies into this browser context. All pages within this context will have these cookies installed. Cookies can be
* obtained via {@link BrowserContext#cookies BrowserContext.cookies()}.
*
* <p> **Usage**
* <pre>{@code
* browserContext.addCookies(Arrays.asList(cookieObject1, cookieObject2));
* }</pre>
*
* @since v1.8
*/
void addCookies(List<Cookie> cookies);
/**
@@ -294,6 +298,8 @@ public interface BrowserContext extends AutoCloseable {
* <p> The script is evaluated after the document was created but before any of its scripts were run. This is useful to amend
* the JavaScript environment, e.g. to seed {@code Math.random}.
*
* <p> **Usage**
*
* <p> An example of overriding {@code Math.random} before the page loads:
* <pre>{@code
* // In your playwright script, assuming the preload.js file is in same directory.
@@ -304,6 +310,7 @@ public interface BrowserContext extends AutoCloseable {
* BrowserContext.addInitScript()} and {@link Page#addInitScript Page.addInitScript()} is not defined.
*
* @param script Script to be evaluated in all pages in the browser context.
* @since v1.8
*/
void addInitScript(String script);
/**
@@ -317,6 +324,8 @@ public interface BrowserContext extends AutoCloseable {
* <p> The script is evaluated after the document was created but before any of its scripts were run. This is useful to amend
* the JavaScript environment, e.g. to seed {@code Math.random}.
*
* <p> **Usage**
*
* <p> An example of overriding {@code Math.random} before the page loads:
* <pre>{@code
* // In your playwright script, assuming the preload.js file is in same directory.
@@ -327,35 +336,48 @@ public interface BrowserContext extends AutoCloseable {
* BrowserContext.addInitScript()} and {@link Page#addInitScript Page.addInitScript()} is not defined.
*
* @param script Script to be evaluated in all pages in the browser context.
* @since v1.8
*/
void addInitScript(Path script);
/**
* Returns the browser instance of the context. If it was launched as a persistent context null gets returned.
*
* @since v1.8
*/
Browser browser();
/**
* Clears context cookies.
*
* @since v1.8
*/
void clearCookies();
/**
* Clears all permission overrides for the browser context.
*
* <p> **Usage**
* <pre>{@code
* BrowserContext context = browser.newContext();
* context.grantPermissions(Arrays.asList("clipboard-read"));
* // do stuff ..
* context.clearPermissions();
* }</pre>
*
* @since v1.8
*/
void clearPermissions();
/**
* Closes the browser context. All the pages that belong to the browser context will be closed.
*
* <p> <strong>NOTE:</strong> The default browser context cannot be closed.
*
* @since v1.8
*/
void close();
/**
* If no URLs are specified, this method returns all cookies. If URLs are specified, only cookies that affect those URLs
* are returned.
*
* @since v1.8
*/
default List<Cookie> cookies() {
return cookies((String) null);
@@ -365,6 +387,7 @@ public interface BrowserContext extends AutoCloseable {
* are returned.
*
* @param urls Optional list of URLs.
* @since v1.8
*/
List<Cookie> cookies(String urls);
/**
@@ -372,21 +395,24 @@ public interface BrowserContext extends AutoCloseable {
* are returned.
*
* @param urls Optional list of URLs.
* @since v1.8
*/
List<Cookie> cookies(List<String> urls);
/**
* The method adds a function called {@code name} on the {@code window} object of every frame in every page in the context. When
* called, the function executes {@code callback} and returns a <a
* The method adds a function called {@code name} on the {@code window} object of every frame in every page in the context.
* When called, the function executes {@code callback} and returns a <a
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a> which
* resolves to the return value of {@code callback}. If the {@code callback} returns a <a
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, it will be
* awaited.
*
* <p> The first argument of the {@code callback} function contains information about the caller: {@code { browserContext: BrowserContext,
* page: Page, frame: Frame }}.
* <p> The first argument of the {@code callback} function contains information about the caller: {@code { browserContext:
* BrowserContext, page: Page, frame: Frame }}.
*
* <p> See {@link Page#exposeBinding Page.exposeBinding()} for page-only version.
*
* <p> **Usage**
*
* <p> An example of exposing page URL to all frames in all pages in the context:
* <pre>{@code
* import com.microsoft.playwright.*;
@@ -406,7 +432,7 @@ public interface BrowserContext extends AutoCloseable {
* "</script>\n" +
* "<button onclick=\"onClick()\">Click me</button>\n" +
* "<div></div>");
* page.getByRole("button").click();
* page.getByRole(AriaRole.BUTTON).click();
* }
* }
* }
@@ -429,23 +455,26 @@ public interface BrowserContext extends AutoCloseable {
*
* @param name Name of the function on the window object.
* @param callback Callback function that will be called in the Playwright's context.
* @since v1.8
*/
default void exposeBinding(String name, BindingCallback callback) {
exposeBinding(name, callback, null);
}
/**
* The method adds a function called {@code name} on the {@code window} object of every frame in every page in the context. When
* called, the function executes {@code callback} and returns a <a
* The method adds a function called {@code name} on the {@code window} object of every frame in every page in the context.
* When called, the function executes {@code callback} and returns a <a
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a> which
* resolves to the return value of {@code callback}. If the {@code callback} returns a <a
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, it will be
* awaited.
*
* <p> The first argument of the {@code callback} function contains information about the caller: {@code { browserContext: BrowserContext,
* page: Page, frame: Frame }}.
* <p> The first argument of the {@code callback} function contains information about the caller: {@code { browserContext:
* BrowserContext, page: Page, frame: Frame }}.
*
* <p> See {@link Page#exposeBinding Page.exposeBinding()} for page-only version.
*
* <p> **Usage**
*
* <p> An example of exposing page URL to all frames in all pages in the context:
* <pre>{@code
* import com.microsoft.playwright.*;
@@ -465,7 +494,7 @@ public interface BrowserContext extends AutoCloseable {
* "</script>\n" +
* "<button onclick=\"onClick()\">Click me</button>\n" +
* "<div></div>");
* page.getByRole("button").click();
* page.getByRole(AriaRole.BUTTON).click();
* }
* }
* }
@@ -488,11 +517,12 @@ public interface BrowserContext extends AutoCloseable {
*
* @param name Name of the function on the window object.
* @param callback Callback function that will be called in the Playwright's context.
* @since v1.8
*/
void exposeBinding(String name, BindingCallback callback, ExposeBindingOptions options);
/**
* The method adds a function called {@code name} on the {@code window} object of every frame in every page in the context. When
* called, the function executes {@code callback} and returns a <a
* The method adds a function called {@code name} on the {@code window} object of every frame in every page in the context.
* When called, the function executes {@code callback} and returns a <a
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a> which
* resolves to the return value of {@code callback}.
*
@@ -502,6 +532,8 @@ public interface BrowserContext extends AutoCloseable {
*
* <p> See {@link Page#exposeFunction Page.exposeFunction()} for page-only version.
*
* <p> **Usage**
*
* <p> An example of adding a {@code sha256} function to all pages in the context:
* <pre>{@code
* import com.microsoft.playwright.*;
@@ -535,7 +567,7 @@ public interface BrowserContext extends AutoCloseable {
* "</script>\n" +
* "<button onclick=\"onClick()\">Click me</button>\n" +
* "<div></div>\n");
* page.getByRole("button").click();
* page.getByRole(AriaRole.BUTTON).click();
* }
* }
* }
@@ -543,6 +575,7 @@ public interface BrowserContext extends AutoCloseable {
*
* @param name Name of the function on the window object.
* @param callback Callback function that will be called in the Playwright's context.
* @since v1.8
*/
void exposeFunction(String name, FunctionCallback callback);
/**
@@ -567,6 +600,7 @@ public interface BrowserContext extends AutoCloseable {
* <li> {@code "clipboard-write"}</li>
* <li> {@code "payment-handler"}</li>
* </ul>
* @since v1.8
*/
default void grantPermissions(List<String> permissions) {
grantPermissions(permissions, null);
@@ -593,18 +627,25 @@ public interface BrowserContext extends AutoCloseable {
* <li> {@code "clipboard-write"}</li>
* <li> {@code "payment-handler"}</li>
* </ul>
* @since v1.8
*/
void grantPermissions(List<String> permissions, GrantPermissionsOptions options);
/**
* Creates a new page in the browser context.
*
* @since v1.8
*/
Page newPage();
/**
* Returns all open pages in the context.
*
* @since v1.8
*/
List<Page> pages();
/**
* API testing helper associated with this context. Requests made with this API will use context cookies.
*
* @since v1.16
*/
APIRequestContext request();
/**
@@ -615,6 +656,8 @@ public interface BrowserContext extends AutoCloseable {
* href="https://github.com/microsoft/playwright/issues/1090">this</a> issue. We recommend disabling Service Workers when
* using request interception by setting {@code Browser.newContext.serviceWorkers} to {@code "block"}.
*
* <p> **Usage**
*
* <p> An example of a naive handler that aborts all image requests:
* <pre>{@code
* BrowserContext context = browser.newContext();
@@ -651,10 +694,11 @@ public interface BrowserContext extends AutoCloseable {
*
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
*
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the context
* options was provided and the passed URL is a path, it gets merged via the <a
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
* context options was provided and the passed URL is a path, it gets merged via the <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
* @param handler handler function to route the request.
* @since v1.8
*/
default void route(String url, Consumer<Route> handler) {
route(url, handler, null);
@@ -667,6 +711,8 @@ public interface BrowserContext extends AutoCloseable {
* href="https://github.com/microsoft/playwright/issues/1090">this</a> issue. We recommend disabling Service Workers when
* using request interception by setting {@code Browser.newContext.serviceWorkers} to {@code "block"}.
*
* <p> **Usage**
*
* <p> An example of a naive handler that aborts all image requests:
* <pre>{@code
* BrowserContext context = browser.newContext();
@@ -703,10 +749,11 @@ public interface BrowserContext extends AutoCloseable {
*
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
*
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the context
* options was provided and the passed URL is a path, it gets merged via the <a
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
* context options was provided and the passed URL is a path, it gets merged via the <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
* @param handler handler function to route the request.
* @since v1.8
*/
void route(String url, Consumer<Route> handler, RouteOptions options);
/**
@@ -717,6 +764,8 @@ public interface BrowserContext extends AutoCloseable {
* href="https://github.com/microsoft/playwright/issues/1090">this</a> issue. We recommend disabling Service Workers when
* using request interception by setting {@code Browser.newContext.serviceWorkers} to {@code "block"}.
*
* <p> **Usage**
*
* <p> An example of a naive handler that aborts all image requests:
* <pre>{@code
* BrowserContext context = browser.newContext();
@@ -753,10 +802,11 @@ public interface BrowserContext extends AutoCloseable {
*
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
*
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the context
* options was provided and the passed URL is a path, it gets merged via the <a
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
* context options was provided and the passed URL is a path, it gets merged via the <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
* @param handler handler function to route the request.
* @since v1.8
*/
default void route(Pattern url, Consumer<Route> handler) {
route(url, handler, null);
@@ -769,6 +819,8 @@ public interface BrowserContext extends AutoCloseable {
* href="https://github.com/microsoft/playwright/issues/1090">this</a> issue. We recommend disabling Service Workers when
* using request interception by setting {@code Browser.newContext.serviceWorkers} to {@code "block"}.
*
* <p> **Usage**
*
* <p> An example of a naive handler that aborts all image requests:
* <pre>{@code
* BrowserContext context = browser.newContext();
@@ -805,10 +857,11 @@ public interface BrowserContext extends AutoCloseable {
*
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
*
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the context
* options was provided and the passed URL is a path, it gets merged via the <a
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
* context options was provided and the passed URL is a path, it gets merged via the <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
* @param handler handler function to route the request.
* @since v1.8
*/
void route(Pattern url, Consumer<Route> handler, RouteOptions options);
/**
@@ -819,6 +872,8 @@ public interface BrowserContext extends AutoCloseable {
* href="https://github.com/microsoft/playwright/issues/1090">this</a> issue. We recommend disabling Service Workers when
* using request interception by setting {@code Browser.newContext.serviceWorkers} to {@code "block"}.
*
* <p> **Usage**
*
* <p> An example of a naive handler that aborts all image requests:
* <pre>{@code
* BrowserContext context = browser.newContext();
@@ -855,10 +910,11 @@ public interface BrowserContext extends AutoCloseable {
*
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
*
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the context
* options was provided and the passed URL is a path, it gets merged via the <a
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
* context options was provided and the passed URL is a path, it gets merged via the <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
* @param handler handler function to route the request.
* @since v1.8
*/
default void route(Predicate<String> url, Consumer<Route> handler) {
route(url, handler, null);
@@ -871,6 +927,8 @@ public interface BrowserContext extends AutoCloseable {
* href="https://github.com/microsoft/playwright/issues/1090">this</a> issue. We recommend disabling Service Workers when
* using request interception by setting {@code Browser.newContext.serviceWorkers} to {@code "block"}.
*
* <p> **Usage**
*
* <p> An example of a naive handler that aborts all image requests:
* <pre>{@code
* BrowserContext context = browser.newContext();
@@ -907,10 +965,11 @@ public interface BrowserContext extends AutoCloseable {
*
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
*
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the context
* options was provided and the passed URL is a path, it gets merged via the <a
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing. When a {@code baseURL} via the
* context options was provided and the passed URL is a path, it gets merged via the <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code new URL()}</a> constructor.
* @param handler handler function to route the request.
* @since v1.8
*/
void route(Predicate<String> url, Consumer<Route> handler, RouteOptions options);
/**
@@ -921,8 +980,9 @@ public interface BrowserContext extends AutoCloseable {
* href="https://github.com/microsoft/playwright/issues/1090">this</a> issue. We recommend disabling Service Workers when
* using request interception by setting {@code Browser.newContext.serviceWorkers} to {@code "block"}.
*
* @param har Path to a <a href="http://www.softwareishard.com/blog/har-12-spec">HAR</a> file with prerecorded network data. If {@code path}
* is a relative path, then it is resolved relative to the current working directory.
* @param har Path to a <a href="http://www.softwareishard.com/blog/har-12-spec">HAR</a> file with prerecorded network data. If {@code
* path} is a relative path, then it is resolved relative to the current working directory.
* @since v1.23
*/
default void routeFromHAR(Path har) {
routeFromHAR(har, null);
@@ -935,8 +995,9 @@ public interface BrowserContext extends AutoCloseable {
* href="https://github.com/microsoft/playwright/issues/1090">this</a> issue. We recommend disabling Service Workers when
* using request interception by setting {@code Browser.newContext.serviceWorkers} to {@code "block"}.
*
* @param har Path to a <a href="http://www.softwareishard.com/blog/har-12-spec">HAR</a> file with prerecorded network data. If {@code path}
* is a relative path, then it is resolved relative to the current working directory.
* @param har Path to a <a href="http://www.softwareishard.com/blog/har-12-spec">HAR</a> file with prerecorded network data. If {@code
* path} is a relative path, then it is resolved relative to the current working directory.
* @since v1.23
*/
void routeFromHAR(Path har, RouteFromHAROptions options);
/**
@@ -955,6 +1016,7 @@ public interface BrowserContext extends AutoCloseable {
* BrowserContext.setDefaultNavigationTimeout()}.
*
* @param timeout Maximum navigation time in milliseconds
* @since v1.8
*/
void setDefaultNavigationTimeout(double timeout);
/**
@@ -966,6 +1028,7 @@ public interface BrowserContext extends AutoCloseable {
* BrowserContext.setDefaultTimeout()}.
*
* @param timeout Maximum time in milliseconds
* @since v1.8
*/
void setDefaultTimeout(double timeout);
/**
@@ -977,34 +1040,49 @@ public interface BrowserContext extends AutoCloseable {
* in the outgoing requests.
*
* @param headers An object containing additional HTTP headers to be sent with every request. All header values must be strings.
* @since v1.8
*/
void setExtraHTTPHeaders(Map<String, String> headers);
/**
* Sets the context's geolocation. Passing {@code null} or {@code undefined} emulates position unavailable.
*
* <p> **Usage**
* <pre>{@code
* browserContext.setGeolocation(new Geolocation(59.95, 30.31667));
* }</pre>
*
* <p> <strong>NOTE:</strong> Consider using {@link BrowserContext#grantPermissions BrowserContext.grantPermissions()} to grant permissions for the
* browser context pages to read its geolocation.
*
* @since v1.8
*/
void setGeolocation(Geolocation geolocation);
/**
*
*
* @param offline Whether to emulate network being offline for the browser context.
* @since v1.8
*/
void setOffline(boolean offline);
/**
* Returns storage state for this browser context, contains current cookies and local storage snapshot.
*
* @since v1.8
*/
default String storageState() {
return storageState(null);
}
/**
* Returns storage state for this browser context, contains current cookies and local storage snapshot.
*
* @since v1.8
*/
String storageState(StorageStateOptions options);
/**
*
*
* @since v1.12
*/
Tracing tracing();
/**
* Removes a route created with {@link BrowserContext#route BrowserContext.route()}. When {@code handler} is not specified,
@@ -1012,6 +1090,7 @@ public interface BrowserContext extends AutoCloseable {
*
* @param url A glob pattern, regex pattern or predicate receiving [URL] used to register a routing with {@link BrowserContext#route
* BrowserContext.route()}.
* @since v1.8
*/
default void unroute(String url) {
unroute(url, null);
@@ -1023,6 +1102,7 @@ public interface BrowserContext extends AutoCloseable {
* @param url A glob pattern, regex pattern or predicate receiving [URL] used to register a routing with {@link BrowserContext#route
* BrowserContext.route()}.
* @param handler Optional handler function used to register a routing with {@link BrowserContext#route BrowserContext.route()}.
* @since v1.8
*/
void unroute(String url, Consumer<Route> handler);
/**
@@ -1031,6 +1111,7 @@ public interface BrowserContext extends AutoCloseable {
*
* @param url A glob pattern, regex pattern or predicate receiving [URL] used to register a routing with {@link BrowserContext#route
* BrowserContext.route()}.
* @since v1.8
*/
default void unroute(Pattern url) {
unroute(url, null);
@@ -1042,6 +1123,7 @@ public interface BrowserContext extends AutoCloseable {
* @param url A glob pattern, regex pattern or predicate receiving [URL] used to register a routing with {@link BrowserContext#route
* BrowserContext.route()}.
* @param handler Optional handler function used to register a routing with {@link BrowserContext#route BrowserContext.route()}.
* @since v1.8
*/
void unroute(Pattern url, Consumer<Route> handler);
/**
@@ -1050,6 +1132,7 @@ public interface BrowserContext extends AutoCloseable {
*
* @param url A glob pattern, regex pattern or predicate receiving [URL] used to register a routing with {@link BrowserContext#route
* BrowserContext.route()}.
* @since v1.8
*/
default void unroute(Predicate<String> url) {
unroute(url, null);
@@ -1061,24 +1144,27 @@ public interface BrowserContext extends AutoCloseable {
* @param url A glob pattern, regex pattern or predicate receiving [URL] used to register a routing with {@link BrowserContext#route
* BrowserContext.route()}.
* @param handler Optional handler function used to register a routing with {@link BrowserContext#route BrowserContext.route()}.
* @since v1.8
*/
void unroute(Predicate<String> url, Consumer<Route> handler);
/**
* Performs action and waits for a new {@code Page} to be created in the context. If predicate is provided, it passes {@code Page}
* value into the {@code predicate} function and waits for {@code predicate(event)} to return a truthy value. Will throw an error if
* the context closes before new {@code Page} is created.
* Performs action and waits for a new {@code Page} to be created in the context. If predicate is provided, it passes
* {@code Page} value into the {@code predicate} function and waits for {@code predicate(event)} to return a truthy value.
* Will throw an error if the context closes before new {@code Page} is created.
*
* @param callback Callback that performs the action triggering the event.
* @since v1.9
*/
default Page waitForPage(Runnable callback) {
return waitForPage(null, callback);
}
/**
* Performs action and waits for a new {@code Page} to be created in the context. If predicate is provided, it passes {@code Page}
* value into the {@code predicate} function and waits for {@code predicate(event)} to return a truthy value. Will throw an error if
* the context closes before new {@code Page} is created.
* Performs action and waits for a new {@code Page} to be created in the context. If predicate is provided, it passes
* {@code Page} value into the {@code predicate} function and waits for {@code predicate(event)} to return a truthy value.
* Will throw an error if the context closes before new {@code Page} is created.
*
* @param callback Callback that performs the action triggering the event.
* @since v1.9
*/
Page waitForPage(WaitForPageOptions options, Runnable callback);
}
@@ -91,8 +91,8 @@ public interface BrowserType {
*/
public Double slowMo;
/**
* Maximum time in milliseconds to wait for the connection to be established. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to
* disable timeout.
* Maximum time in milliseconds to wait for the connection to be established. Defaults to {@code 30000} (30 seconds). Pass
* {@code 0} to disable timeout.
*/
public Double timeout;
@@ -112,8 +112,8 @@ public interface BrowserType {
return this;
}
/**
* Maximum time in milliseconds to wait for the connection to be established. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to
* disable timeout.
* Maximum time in milliseconds to wait for the connection to be established. Defaults to {@code 30000} (30 seconds). Pass
* {@code 0} to disable timeout.
*/
public ConnectOverCDPOptions setTimeout(double timeout) {
this.timeout = timeout;
@@ -137,8 +137,8 @@ public interface BrowserType {
*/
public Boolean chromiumSandbox;
/**
* **Chromium-only** Whether to auto-open a Developer Tools panel for each tab. If this option is {@code true}, the {@code headless}
* option will be set {@code false}.
* **Chromium-only** Whether to auto-open a Developer Tools panel for each tab. If this option is {@code true}, the {@code
* headless} option will be set {@code false}.
*/
public Boolean devtools;
/**
@@ -177,18 +177,18 @@ public interface BrowserType {
/**
* Whether to run browser in headless mode. More details for <a
* href="https://developers.google.com/web/updates/2017/04/headless-chrome">Chromium</a> and <a
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode">Firefox</a>. Defaults to {@code true} unless the
* {@code devtools} option is {@code true}.
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode">Firefox</a>. Defaults to {@code true}
* unless the {@code devtools} option is {@code true}.
*/
public Boolean headless;
/**
* If {@code true}, Playwright does not pass its own configurations args and only uses the ones from {@code args}. Dangerous option;
* use with care. Defaults to {@code false}.
* If {@code true}, Playwright does not pass its own configurations args and only uses the ones from {@code args}.
* Dangerous option; use with care. Defaults to {@code false}.
*/
public Boolean ignoreAllDefaultArgs;
/**
* If {@code true}, Playwright does not pass its own configurations args and only uses the ones from {@code args}. Dangerous option;
* use with care.
* If {@code true}, Playwright does not pass its own configurations args and only uses the ones from {@code args}.
* Dangerous option; use with care.
*/
public List<String> ignoreDefaultArgs;
/**
@@ -200,8 +200,8 @@ public interface BrowserType {
*/
public Double slowMo;
/**
* Maximum time in milliseconds to wait for the browser instance to start. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to
* disable timeout.
* Maximum time in milliseconds to wait for the browser instance to start. Defaults to {@code 30000} (30 seconds). Pass
* {@code 0} to disable timeout.
*/
public Double timeout;
/**
@@ -244,8 +244,8 @@ public interface BrowserType {
return this;
}
/**
* **Chromium-only** Whether to auto-open a Developer Tools panel for each tab. If this option is {@code true}, the {@code headless}
* option will be set {@code false}.
* **Chromium-only** Whether to auto-open a Developer Tools panel for each tab. If this option is {@code true}, the {@code
* headless} option will be set {@code false}.
*/
public LaunchOptions setDevtools(boolean devtools) {
this.devtools = devtools;
@@ -308,24 +308,24 @@ public interface BrowserType {
/**
* Whether to run browser in headless mode. More details for <a
* href="https://developers.google.com/web/updates/2017/04/headless-chrome">Chromium</a> and <a
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode">Firefox</a>. Defaults to {@code true} unless the
* {@code devtools} option is {@code true}.
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode">Firefox</a>. Defaults to {@code true}
* unless the {@code devtools} option is {@code true}.
*/
public LaunchOptions setHeadless(boolean headless) {
this.headless = headless;
return this;
}
/**
* If {@code true}, Playwright does not pass its own configurations args and only uses the ones from {@code args}. Dangerous option;
* use with care. Defaults to {@code false}.
* If {@code true}, Playwright does not pass its own configurations args and only uses the ones from {@code args}.
* Dangerous option; use with care. Defaults to {@code false}.
*/
public LaunchOptions setIgnoreAllDefaultArgs(boolean ignoreAllDefaultArgs) {
this.ignoreAllDefaultArgs = ignoreAllDefaultArgs;
return this;
}
/**
* If {@code true}, Playwright does not pass its own configurations args and only uses the ones from {@code args}. Dangerous option;
* use with care.
* If {@code true}, Playwright does not pass its own configurations args and only uses the ones from {@code args}.
* Dangerous option; use with care.
*/
public LaunchOptions setIgnoreDefaultArgs(List<String> ignoreDefaultArgs) {
this.ignoreDefaultArgs = ignoreDefaultArgs;
@@ -352,8 +352,8 @@ public interface BrowserType {
return this;
}
/**
* Maximum time in milliseconds to wait for the browser instance to start. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to
* disable timeout.
* Maximum time in milliseconds to wait for the browser instance to start. Defaults to {@code 30000} (30 seconds). Pass
* {@code 0} to disable timeout.
*/
public LaunchOptions setTimeout(double timeout) {
this.timeout = timeout;
@@ -381,11 +381,13 @@ public interface BrowserType {
* When using {@link Page#navigate Page.navigate()}, {@link Page#route Page.route()}, {@link Page#waitForURL
* Page.waitForURL()}, {@link Page#waitForRequest Page.waitForRequest()}, or {@link Page#waitForResponse
* Page.waitForResponse()} it takes the base URL in consideration by using the <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code URL()}</a> constructor for building the corresponding
* URL. Examples:
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code URL()}</a> constructor for building the
* corresponding URL. Examples:
* <ul>
* <li> baseURL: {@code http://localhost:3000} and navigating to {@code /bar.html} results in {@code http://localhost:3000/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo/} and navigating to {@code ./bar.html} results in {@code http://localhost:3000/foo/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000} and navigating to {@code /bar.html} results in {@code
* http://localhost:3000/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo/} and navigating to {@code ./bar.html} results in {@code
* http://localhost:3000/foo/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo} (without trailing slash) and navigating to {@code ./bar.html} results in
* {@code http://localhost:3000/bar.html}</li>
* </ul>
@@ -406,9 +408,9 @@ public interface BrowserType {
*/
public Boolean chromiumSandbox;
/**
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code "no-preference"}. See
* {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults.
* Defaults to {@code "light"}.
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code
* "no-preference"}. See {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets
* emulation to system defaults. Defaults to {@code "light"}.
*/
public Optional<ColorScheme> colorScheme;
/**
@@ -416,8 +418,8 @@ public interface BrowserType {
*/
public Double deviceScaleFactor;
/**
* **Chromium-only** Whether to auto-open a Developer Tools panel for each tab. If this option is {@code true}, the {@code headless}
* option will be set {@code false}.
* **Chromium-only** Whether to auto-open a Developer Tools panel for each tab. If this option is {@code true}, the {@code
* headless} option will be set {@code false}.
*/
public Boolean devtools;
/**
@@ -441,8 +443,9 @@ public interface BrowserType {
*/
public Map<String, String> extraHTTPHeaders;
/**
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"}, {@code "none"}. See {@link Page#emulateMedia
* Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to {@code "none"}.
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"}, {@code "none"}. See {@link
* Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults.
* Defaults to {@code "none"}.
*/
public Optional<ForcedColors> forcedColors;
public Geolocation geolocation;
@@ -465,8 +468,8 @@ public interface BrowserType {
/**
* Whether to run browser in headless mode. More details for <a
* href="https://developers.google.com/web/updates/2017/04/headless-chrome">Chromium</a> and <a
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode">Firefox</a>. Defaults to {@code true} unless the
* {@code devtools} option is {@code true}.
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode">Firefox</a>. Defaults to {@code true}
* unless the {@code devtools} option is {@code true}.
*/
public Boolean headless;
/**
@@ -474,13 +477,13 @@ public interface BrowserType {
*/
public HttpCredentials httpCredentials;
/**
* If {@code true}, Playwright does not pass its own configurations args and only uses the ones from {@code args}. Dangerous option;
* use with care. Defaults to {@code false}.
* If {@code true}, Playwright does not pass its own configurations args and only uses the ones from {@code args}.
* Dangerous option; use with care. Defaults to {@code false}.
*/
public Boolean ignoreAllDefaultArgs;
/**
* If {@code true}, Playwright does not pass its own configurations args and only uses the ones from {@code args}. Dangerous option;
* use with care.
* If {@code true}, Playwright does not pass its own configurations args and only uses the ones from {@code args}.
* Dangerous option; use with care.
*/
public List<String> ignoreDefaultArgs;
/**
@@ -488,8 +491,8 @@ public interface BrowserType {
*/
public Boolean ignoreHTTPSErrors;
/**
* Whether the {@code meta viewport} tag is taken into account and touch events are enabled. Defaults to {@code false}. Not supported
* in Firefox.
* Whether the {@code meta viewport} tag is taken into account and touch events are enabled. Defaults to {@code false}. Not
* supported in Firefox.
*/
public Boolean isMobile;
/**
@@ -497,8 +500,8 @@ public interface BrowserType {
*/
public Boolean javaScriptEnabled;
/**
* Specify user locale, for example {@code en-GB}, {@code de-DE}, etc. Locale will affect {@code navigator.language} value, {@code Accept-Language}
* request header value as well as number and date formatting rules.
* Specify user locale, for example {@code en-GB}, {@code de-DE}, etc. Locale will affect {@code navigator.language} value,
* {@code Accept-Language} request header value as well as number and date formatting rules.
*/
public String locale;
/**
@@ -515,14 +518,15 @@ 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 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.
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If
* {@code attach} 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;
/**
* When set to {@code minimal}, only record information necessary for routing from HAR. This omits sizes, timing, page, cookies,
* security and other types of HAR information that are not used when replaying from HAR. Defaults to {@code full}.
* When set to {@code minimal}, only record information necessary for routing from HAR. This omits sizes, timing, page,
* cookies, security and other types of HAR information that are not used when replaying from HAR. Defaults to {@code
* full}.
*/
public HarMode recordHarMode;
/**
@@ -543,26 +547,26 @@ public interface BrowserType {
public Path recordVideoDir;
/**
* Dimensions of the recorded videos. If not specified the size will be equal to {@code viewport} scaled down to fit into
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each page will
* be scaled down if necessary to fit the specified size.
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each
* page will be scaled down if necessary to fit the specified size.
*/
public RecordVideoSize recordVideoSize;
/**
* Emulates {@code "prefers-reduced-motion"} media feature, supported values are {@code "reduce"}, {@code "no-preference"}. See {@link
* Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to
* {@code "no-preference"}.
* Emulates {@code "prefers-reduced-motion"} media feature, supported values are {@code "reduce"}, {@code "no-preference"}.
* See {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system
* defaults. Defaults to {@code "no-preference"}.
*/
public Optional<ReducedMotion> reducedMotion;
/**
* Emulates consistent window screen size available inside web page via {@code window.screen}. Is only used when the {@code viewport}
* is set.
* Emulates consistent window screen size available inside web page via {@code window.screen}. Is only used when the {@code
* viewport} is set.
*/
public ScreenSize screenSize;
/**
* Whether to allow sites to register Service workers. Defaults to {@code "allow"}.
* <ul>
* <li> {@code "allow"}: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API">Service Workers</a> can be
* registered.</li>
* <li> {@code "allow"}: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API">Service Workers</a> can
* be registered.</li>
* <li> {@code "block"}: Playwright will block all registration of Service Workers.</li>
* </ul>
*/
@@ -572,14 +576,14 @@ public interface BrowserType {
*/
public Double slowMo;
/**
* If specified, enables strict selectors mode for this context. In the strict selectors mode all operations on selectors
* that imply single target DOM element will throw when more than one element matches the selector. See {@code Locator} to learn
* more about the strict mode.
* If set to true, enables strict selectors mode for this context. In the strict selectors mode all operations on selectors
* that imply single target DOM element will throw when more than one element matches the selector. This option does not
* affect any Locator APIs (Locators are always strict). See {@code Locator} to learn more about the strict mode.
*/
public Boolean strictSelectors;
/**
* Maximum time in milliseconds to wait for the browser instance to start. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to
* disable timeout.
* Maximum time in milliseconds to wait for the browser instance to start. Defaults to {@code 30000} (30 seconds). Pass
* {@code 0} to disable timeout.
*/
public Double timeout;
/**
@@ -597,7 +601,11 @@ public interface BrowserType {
*/
public String userAgent;
/**
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default viewport.
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. Use {@code null} to disable the consistent
* viewport emulation.
*
* <p> <strong>NOTE:</strong> The {@code null} value opts out from the default presets, makes viewport depend on the host window size defined by the
* operating system. It makes the execution of the tests non-deterministic.
*/
public Optional<ViewportSize> viewportSize;
@@ -620,11 +628,13 @@ public interface BrowserType {
* When using {@link Page#navigate Page.navigate()}, {@link Page#route Page.route()}, {@link Page#waitForURL
* Page.waitForURL()}, {@link Page#waitForRequest Page.waitForRequest()}, or {@link Page#waitForResponse
* Page.waitForResponse()} it takes the base URL in consideration by using the <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code URL()}</a> constructor for building the corresponding
* URL. Examples:
* href="https://developer.mozilla.org/en-US/docs/Web/API/URL/URL">{@code URL()}</a> constructor for building the
* corresponding URL. Examples:
* <ul>
* <li> baseURL: {@code http://localhost:3000} and navigating to {@code /bar.html} results in {@code http://localhost:3000/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo/} and navigating to {@code ./bar.html} results in {@code http://localhost:3000/foo/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000} and navigating to {@code /bar.html} results in {@code
* http://localhost:3000/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo/} and navigating to {@code ./bar.html} results in {@code
* http://localhost:3000/foo/bar.html}</li>
* <li> baseURL: {@code http://localhost:3000/foo} (without trailing slash) and navigating to {@code ./bar.html} results in
* {@code http://localhost:3000/bar.html}</li>
* </ul>
@@ -667,9 +677,9 @@ public interface BrowserType {
return this;
}
/**
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code "no-preference"}. See
* {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults.
* Defaults to {@code "light"}.
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code
* "no-preference"}. See {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets
* emulation to system defaults. Defaults to {@code "light"}.
*/
public LaunchPersistentContextOptions setColorScheme(ColorScheme colorScheme) {
this.colorScheme = Optional.ofNullable(colorScheme);
@@ -683,8 +693,8 @@ public interface BrowserType {
return this;
}
/**
* **Chromium-only** Whether to auto-open a Developer Tools panel for each tab. If this option is {@code true}, the {@code headless}
* option will be set {@code false}.
* **Chromium-only** Whether to auto-open a Developer Tools panel for each tab. If this option is {@code true}, the {@code
* headless} option will be set {@code false}.
*/
public LaunchPersistentContextOptions setDevtools(boolean devtools) {
this.devtools = devtools;
@@ -723,8 +733,9 @@ public interface BrowserType {
return this;
}
/**
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"}, {@code "none"}. See {@link Page#emulateMedia
* Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to {@code "none"}.
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"}, {@code "none"}. See {@link
* Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults.
* Defaults to {@code "none"}.
*/
public LaunchPersistentContextOptions setForcedColors(ForcedColors forcedColors) {
this.forcedColors = Optional.ofNullable(forcedColors);
@@ -768,8 +779,8 @@ public interface BrowserType {
/**
* Whether to run browser in headless mode. More details for <a
* href="https://developers.google.com/web/updates/2017/04/headless-chrome">Chromium</a> and <a
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode">Firefox</a>. Defaults to {@code true} unless the
* {@code devtools} option is {@code true}.
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Headless_mode">Firefox</a>. Defaults to {@code true}
* unless the {@code devtools} option is {@code true}.
*/
public LaunchPersistentContextOptions setHeadless(boolean headless) {
this.headless = headless;
@@ -789,16 +800,16 @@ public interface BrowserType {
return this;
}
/**
* If {@code true}, Playwright does not pass its own configurations args and only uses the ones from {@code args}. Dangerous option;
* use with care. Defaults to {@code false}.
* If {@code true}, Playwright does not pass its own configurations args and only uses the ones from {@code args}.
* Dangerous option; use with care. Defaults to {@code false}.
*/
public LaunchPersistentContextOptions setIgnoreAllDefaultArgs(boolean ignoreAllDefaultArgs) {
this.ignoreAllDefaultArgs = ignoreAllDefaultArgs;
return this;
}
/**
* If {@code true}, Playwright does not pass its own configurations args and only uses the ones from {@code args}. Dangerous option;
* use with care.
* If {@code true}, Playwright does not pass its own configurations args and only uses the ones from {@code args}.
* Dangerous option; use with care.
*/
public LaunchPersistentContextOptions setIgnoreDefaultArgs(List<String> ignoreDefaultArgs) {
this.ignoreDefaultArgs = ignoreDefaultArgs;
@@ -812,8 +823,8 @@ public interface BrowserType {
return this;
}
/**
* Whether the {@code meta viewport} tag is taken into account and touch events are enabled. Defaults to {@code false}. Not supported
* in Firefox.
* Whether the {@code meta viewport} tag is taken into account and touch events are enabled. Defaults to {@code false}. Not
* supported in Firefox.
*/
public LaunchPersistentContextOptions setIsMobile(boolean isMobile) {
this.isMobile = isMobile;
@@ -827,8 +838,8 @@ public interface BrowserType {
return this;
}
/**
* Specify user locale, for example {@code en-GB}, {@code de-DE}, etc. Locale will affect {@code navigator.language} value, {@code Accept-Language}
* request header value as well as number and date formatting rules.
* Specify user locale, for example {@code en-GB}, {@code de-DE}, etc. Locale will affect {@code navigator.language} value,
* {@code Accept-Language} request header value as well as number and date formatting rules.
*/
public LaunchPersistentContextOptions setLocale(String locale) {
this.locale = locale;
@@ -863,17 +874,18 @@ public interface BrowserType {
return this;
}
/**
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If {@code attach}
* 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.
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If
* {@code attach} 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) {
this.recordHarContent = recordHarContent;
return this;
}
/**
* When set to {@code minimal}, only record information necessary for routing from HAR. This omits sizes, timing, page, cookies,
* security and other types of HAR information that are not used when replaying from HAR. Defaults to {@code full}.
* When set to {@code minimal}, only record information necessary for routing from HAR. This omits sizes, timing, page,
* cookies, security and other types of HAR information that are not used when replaying from HAR. Defaults to {@code
* full}.
*/
public LaunchPersistentContextOptions setRecordHarMode(HarMode recordHarMode) {
this.recordHarMode = recordHarMode;
@@ -913,40 +925,40 @@ public interface BrowserType {
}
/**
* Dimensions of the recorded videos. If not specified the size will be equal to {@code viewport} scaled down to fit into
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each page will
* be scaled down if necessary to fit the specified size.
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each
* page will be scaled down if necessary to fit the specified size.
*/
public LaunchPersistentContextOptions setRecordVideoSize(int width, int height) {
return setRecordVideoSize(new RecordVideoSize(width, height));
}
/**
* Dimensions of the recorded videos. If not specified the size will be equal to {@code viewport} scaled down to fit into
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each page will
* be scaled down if necessary to fit the specified size.
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each
* page will be scaled down if necessary to fit the specified size.
*/
public LaunchPersistentContextOptions setRecordVideoSize(RecordVideoSize recordVideoSize) {
this.recordVideoSize = recordVideoSize;
return this;
}
/**
* Emulates {@code "prefers-reduced-motion"} media feature, supported values are {@code "reduce"}, {@code "no-preference"}. See {@link
* Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults. Defaults to
* {@code "no-preference"}.
* Emulates {@code "prefers-reduced-motion"} media feature, supported values are {@code "reduce"}, {@code "no-preference"}.
* See {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system
* defaults. Defaults to {@code "no-preference"}.
*/
public LaunchPersistentContextOptions setReducedMotion(ReducedMotion reducedMotion) {
this.reducedMotion = Optional.ofNullable(reducedMotion);
return this;
}
/**
* Emulates consistent window screen size available inside web page via {@code window.screen}. Is only used when the {@code viewport}
* is set.
* Emulates consistent window screen size available inside web page via {@code window.screen}. Is only used when the {@code
* viewport} is set.
*/
public LaunchPersistentContextOptions setScreenSize(int width, int height) {
return setScreenSize(new ScreenSize(width, height));
}
/**
* Emulates consistent window screen size available inside web page via {@code window.screen}. Is only used when the {@code viewport}
* is set.
* Emulates consistent window screen size available inside web page via {@code window.screen}. Is only used when the {@code
* viewport} is set.
*/
public LaunchPersistentContextOptions setScreenSize(ScreenSize screenSize) {
this.screenSize = screenSize;
@@ -955,8 +967,8 @@ public interface BrowserType {
/**
* Whether to allow sites to register Service workers. Defaults to {@code "allow"}.
* <ul>
* <li> {@code "allow"}: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API">Service Workers</a> can be
* registered.</li>
* <li> {@code "allow"}: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API">Service Workers</a> can
* be registered.</li>
* <li> {@code "block"}: Playwright will block all registration of Service Workers.</li>
* </ul>
*/
@@ -972,17 +984,17 @@ public interface BrowserType {
return this;
}
/**
* If specified, enables strict selectors mode for this context. In the strict selectors mode all operations on selectors
* that imply single target DOM element will throw when more than one element matches the selector. See {@code Locator} to learn
* more about the strict mode.
* If set to true, enables strict selectors mode for this context. In the strict selectors mode all operations on selectors
* that imply single target DOM element will throw when more than one element matches the selector. This option does not
* affect any Locator APIs (Locators are always strict). See {@code Locator} to learn more about the strict mode.
*/
public LaunchPersistentContextOptions setStrictSelectors(boolean strictSelectors) {
this.strictSelectors = strictSelectors;
return this;
}
/**
* Maximum time in milliseconds to wait for the browser instance to start. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to
* disable timeout.
* Maximum time in milliseconds to wait for the browser instance to start. Defaults to {@code 30000} (30 seconds). Pass
* {@code 0} to disable timeout.
*/
public LaunchPersistentContextOptions setTimeout(double timeout) {
this.timeout = timeout;
@@ -1012,13 +1024,21 @@ public interface BrowserType {
return this;
}
/**
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default viewport.
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. Use {@code null} to disable the consistent
* viewport emulation.
*
* <p> <strong>NOTE:</strong> The {@code null} value opts out from the default presets, makes viewport depend on the host window size defined by the
* operating system. It makes the execution of the tests non-deterministic.
*/
public LaunchPersistentContextOptions setViewportSize(int width, int height) {
return setViewportSize(new ViewportSize(width, height));
}
/**
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default viewport.
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. Use {@code null} to disable the consistent
* viewport emulation.
*
* <p> <strong>NOTE:</strong> The {@code null} value opts out from the default presets, makes viewport depend on the host window size defined by the
* operating system. It makes the execution of the tests non-deterministic.
*/
public LaunchPersistentContextOptions setViewportSize(ViewportSize viewportSize) {
this.viewportSize = Optional.ofNullable(viewportSize);
@@ -1026,21 +1046,23 @@ public interface BrowserType {
}
}
/**
* This method attaches Playwright to an existing browser instance. When connecting to another browser launched via
* {@code BrowserType.launchServer} in Node.js, the major and minor version needs to match the client version (1.2.3 → is
* This method attaches Playwright to an existing browser instance. When connecting to another browser launched via {@code
* BrowserType.launchServer} in Node.js, the major and minor version needs to match the client version (1.2.3 → is
* compatible with 1.2.x).
*
* @param wsEndpoint A browser websocket endpoint to connect to.
* @since v1.8
*/
default Browser connect(String wsEndpoint) {
return connect(wsEndpoint, null);
}
/**
* This method attaches Playwright to an existing browser instance. When connecting to another browser launched via
* {@code BrowserType.launchServer} in Node.js, the major and minor version needs to match the client version (1.2.3 → is
* This method attaches Playwright to an existing browser instance. When connecting to another browser launched via {@code
* BrowserType.launchServer} in Node.js, the major and minor version needs to match the client version (1.2.3 → is
* compatible with 1.2.x).
*
* @param wsEndpoint A browser websocket endpoint to connect to.
* @since v1.8
*/
Browser connect(String wsEndpoint, ConnectOptions options);
/**
@@ -1049,14 +1071,17 @@ public interface BrowserType {
* <p> The default browser context is accessible via {@link Browser#contexts Browser.contexts()}.
*
* <p> <strong>NOTE:</strong> Connecting over the Chrome DevTools Protocol is only supported for Chromium-based browsers.
*
* <p> **Usage**
* <pre>{@code
* Browser browser = playwright.chromium().connectOverCDP("http://localhost:9222");
* BrowserContext defaultContext = browser.contexts().get(0);
* Page page = defaultContext.pages().get(0);
* }</pre>
*
* @param endpointURL A CDP websocket endpoint or http url to connect to. For example {@code http://localhost:9222/} or
* {@code ws://127.0.0.1:9222/devtools/browser/387adf4c-243f-4051-a181-46798f4a46f4}.
* @param endpointURL A CDP websocket endpoint or http url to connect to. For example {@code http://localhost:9222/} or {@code
* ws://127.0.0.1:9222/devtools/browser/387adf4c-243f-4051-a181-46798f4a46f4}.
* @since v1.9
*/
default Browser connectOverCDP(String endpointURL) {
return connectOverCDP(endpointURL, null);
@@ -1067,23 +1092,30 @@ public interface BrowserType {
* <p> The default browser context is accessible via {@link Browser#contexts Browser.contexts()}.
*
* <p> <strong>NOTE:</strong> Connecting over the Chrome DevTools Protocol is only supported for Chromium-based browsers.
*
* <p> **Usage**
* <pre>{@code
* Browser browser = playwright.chromium().connectOverCDP("http://localhost:9222");
* BrowserContext defaultContext = browser.contexts().get(0);
* Page page = defaultContext.pages().get(0);
* }</pre>
*
* @param endpointURL A CDP websocket endpoint or http url to connect to. For example {@code http://localhost:9222/} or
* {@code ws://127.0.0.1:9222/devtools/browser/387adf4c-243f-4051-a181-46798f4a46f4}.
* @param endpointURL A CDP websocket endpoint or http url to connect to. For example {@code http://localhost:9222/} or {@code
* ws://127.0.0.1:9222/devtools/browser/387adf4c-243f-4051-a181-46798f4a46f4}.
* @since v1.9
*/
Browser connectOverCDP(String endpointURL, ConnectOverCDPOptions options);
/**
* A path where Playwright expects to find a bundled browser executable.
*
* @since v1.8
*/
String executablePath();
/**
* Returns the browser instance.
*
* <p> **Usage**
*
* <p> You can use {@code ignoreDefaultArgs} to filter out {@code --mute-audio} from default arguments:
* <pre>{@code
* // Or "firefox" or "webkit".
@@ -1109,6 +1141,8 @@ public interface BrowserType {
* other differences between Chromium and Chrome. <a
* href="https://chromium.googlesource.com/chromium/src/+/lkgr/docs/chromium_browser_vs_google_chrome.md">This article</a>
* describes some differences for Linux users.
*
* @since v1.8
*/
default Browser launch() {
return launch(null);
@@ -1116,6 +1150,8 @@ public interface BrowserType {
/**
* Returns the browser instance.
*
* <p> **Usage**
*
* <p> You can use {@code ignoreDefaultArgs} to filter out {@code --mute-audio} from default arguments:
* <pre>{@code
* // Or "firefox" or "webkit".
@@ -1141,6 +1177,8 @@ public interface BrowserType {
* other differences between Chromium and Chrome. <a
* href="https://chromium.googlesource.com/chromium/src/+/lkgr/docs/chromium_browser_vs_google_chrome.md">This article</a>
* describes some differences for Linux users.
*
* @since v1.8
*/
Browser launch(LaunchOptions options);
/**
@@ -1152,8 +1190,9 @@ public interface BrowserType {
* @param userDataDir Path to a User Data Directory, which stores browser session data like cookies and local storage. More details for <a
* href="https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md#introduction">Chromium</a> and <a
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Command_Line_Options#User_Profile">Firefox</a>. Note that
* Chromium's user data directory is the **parent** directory of the "Profile Path" seen at {@code chrome://version}. Pass an
* empty string to use a temporary directory instead.
* Chromium's user data directory is the **parent** directory of the "Profile Path" seen at {@code chrome://version}. Pass
* an empty string to use a temporary directory instead.
* @since v1.8
*/
default BrowserContext launchPersistentContext(Path userDataDir) {
return launchPersistentContext(userDataDir, null);
@@ -1167,12 +1206,15 @@ public interface BrowserType {
* @param userDataDir Path to a User Data Directory, which stores browser session data like cookies and local storage. More details for <a
* href="https://chromium.googlesource.com/chromium/src/+/master/docs/user_data_dir.md#introduction">Chromium</a> and <a
* href="https://developer.mozilla.org/en-US/docs/Mozilla/Command_Line_Options#User_Profile">Firefox</a>. Note that
* Chromium's user data directory is the **parent** directory of the "Profile Path" seen at {@code chrome://version}. Pass an
* empty string to use a temporary directory instead.
* Chromium's user data directory is the **parent** directory of the "Profile Path" seen at {@code chrome://version}. Pass
* an empty string to use a temporary directory instead.
* @since v1.8
*/
BrowserContext launchPersistentContext(Path userDataDir, LaunchPersistentContextOptions options);
/**
* Returns browser name. For example: {@code "chromium"}, {@code "webkit"} or {@code "firefox"}.
*
* @since v1.8
*/
String name();
}
@@ -19,19 +19,19 @@ package com.microsoft.playwright;
import java.util.*;
/**
* {@code ConsoleMessage} objects are dispatched by page via the {@link Page#onConsoleMessage Page.onConsoleMessage()} event. For
* each console messages logged in the page there will be corresponding event in the Playwright context.
* {@code ConsoleMessage} objects are dispatched by page via the {@link Page#onConsoleMessage Page.onConsoleMessage()}
* event. For each console messages logged in the page there will be corresponding event in the Playwright context.
* <pre>{@code
* // Listen for all System.out.printlns
* // Listen for all console messages and print them to the standard output.
* page.onConsoleMessage(msg -> System.out.println(msg.text()));
*
* // Listen for all console events and handle errors
* // Listen for all console messages and print errors to the standard output.
* page.onConsoleMessage(msg -> {
* if ("error".equals(msg.type()))
* System.out.println("Error text: " + msg.text());
* });
*
* // Get the next System.out.println
* // Get the next console message
* ConsoleMessage msg = page.waitForConsoleMessage(() -> {
* // Issue console.log inside the page
* page.evaluate("console.log('hello', 42, { foo: 'bar' });");
@@ -44,21 +44,31 @@ import java.util.*;
*/
public interface ConsoleMessage {
/**
* List of arguments passed to a {@code console} function call. See also {@link Page#onConsoleMessage Page.onConsoleMessage()}.
* List of arguments passed to a {@code console} function call. See also {@link Page#onConsoleMessage
* Page.onConsoleMessage()}.
*
* @since v1.8
*/
List<JSHandle> args();
/**
* URL of the resource followed by 0-based line and column numbers in the resource formatted as {@code URL:line:column}.
*
* @since v1.8
*/
String location();
/**
* The text of the console message.
*
* @since v1.8
*/
String text();
/**
* One of the following values: {@code "log"}, {@code "debug"}, {@code "info"}, {@code "error"}, {@code "warning"}, {@code "dir"}, {@code "dirxml"}, {@code "table"},
* {@code "trace"}, {@code "clear"}, {@code "startGroup"}, {@code "startGroupCollapsed"}, {@code "endGroup"}, {@code "assert"}, {@code "profile"}, {@code "profileEnd"},
* {@code "count"}, {@code "timeEnd"}.
* One of the following values: {@code "log"}, {@code "debug"}, {@code "info"}, {@code "error"}, {@code "warning"}, {@code
* "dir"}, {@code "dirxml"}, {@code "table"}, {@code "trace"}, {@code "clear"}, {@code "startGroup"}, {@code
* "startGroupCollapsed"}, {@code "endGroup"}, {@code "assert"}, {@code "profile"}, {@code "profileEnd"}, {@code "count"},
* {@code "timeEnd"}.
*
* @since v1.8
*/
String type();
}
@@ -50,6 +50,8 @@ package com.microsoft.playwright;
public interface Dialog {
/**
* Returns when the dialog has been accepted.
*
* @since v1.8
*/
default void accept() {
accept(null);
@@ -58,22 +60,31 @@ public interface Dialog {
* Returns when the dialog has been accepted.
*
* @param promptText A text to enter in prompt. Does not cause any effects if the dialog's {@code type} is not prompt. Optional.
* @since v1.8
*/
void accept(String promptText);
/**
* If dialog is prompt, returns default prompt value. Otherwise, returns empty string.
*
* @since v1.8
*/
String defaultValue();
/**
* Returns when the dialog has been dismissed.
*
* @since v1.8
*/
void dismiss();
/**
* A message displayed in the dialog.
*
* @since v1.8
*/
String message();
/**
* Returns dialog's type, can be one of {@code alert}, {@code beforeunload}, {@code confirm} or {@code prompt}.
*
* @since v1.8
*/
String type();
}
@@ -36,24 +36,34 @@ import java.nio.file.Path;
*/
public interface Download {
/**
* Cancels a download. Will not fail if the download is already finished or canceled. Upon successful cancellations,
* {@code download.failure()} would resolve to {@code "canceled"}.
* Cancels a download. Will not fail if the download is already finished or canceled. Upon successful cancellations, {@code
* download.failure()} would resolve to {@code "canceled"}.
*
* @since v1.13
*/
void cancel();
/**
* Returns readable stream for current download or {@code null} if download failed.
*
* @since v1.8
*/
InputStream createReadStream();
/**
* Deletes the downloaded file. Will wait for the download to finish if necessary.
*
* @since v1.8
*/
void delete();
/**
* Returns download error if any. Will wait for the download to finish if necessary.
*
* @since v1.8
*/
String failure();
/**
* Get the page that the download belongs to.
*
* @since v1.12
*/
Page page();
/**
@@ -62,6 +72,8 @@ public interface Download {
*
* <p> Note that the download's file name is a random GUID, use {@link Download#suggestedFilename Download.suggestedFilename()}
* to get suggested file name.
*
* @since v1.8
*/
Path path();
/**
@@ -69,18 +81,23 @@ public interface Download {
* wait for the download to finish if necessary.
*
* @param path Path where the download should be copied.
* @since v1.8
*/
void saveAs(Path path);
/**
* Returns suggested filename for this download. It is typically computed by the browser from the <a
* href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition">{@code Content-Disposition}</a> response
* header or the {@code download} attribute. See the spec on <a
* href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition">{@code Content-Disposition}</a>
* response header or the {@code download} attribute. See the spec on <a
* href="https://html.spec.whatwg.org/#downloading-resources">whatwg</a>. Different browsers can use different logic for
* computing it.
*
* @since v1.8
*/
String suggestedFilename();
/**
* Returns downloaded url.
*
* @since v1.8
*/
String url();
}
File diff suppressed because it is too large Load Diff
@@ -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.getByText("Upload").click());
* FileChooser fileChooser = page.waitForFileChooser(() -> page.getByText("Upload file").click());
* fileChooser.setFiles(Paths.get("myfile.pdf"));
* }</pre>
*/
@@ -35,9 +35,9 @@ public interface FileChooser {
*/
public Boolean noWaitAfter;
/**
* Maximum time in milliseconds, defaults to 30 seconds, pass {@code 0} to disable timeout. The default value can be changed by
* using the {@link BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()} or {@link Page#setDefaultTimeout
* Page.setDefaultTimeout()} methods.
* Maximum time in milliseconds, defaults to 30 seconds, pass {@code 0} to disable timeout. The default value can be
* changed by using the {@link BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()} or {@link
* Page#setDefaultTimeout Page.setDefaultTimeout()} methods.
*/
public Double timeout;
@@ -51,9 +51,9 @@ public interface FileChooser {
return this;
}
/**
* Maximum time in milliseconds, defaults to 30 seconds, pass {@code 0} to disable timeout. The default value can be changed by
* using the {@link BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()} or {@link Page#setDefaultTimeout
* Page.setDefaultTimeout()} methods.
* Maximum time in milliseconds, defaults to 30 seconds, pass {@code 0} to disable timeout. The default value can be
* changed by using the {@link BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()} or {@link
* Page#setDefaultTimeout Page.setDefaultTimeout()} methods.
*/
public SetFilesOptions setTimeout(double timeout) {
this.timeout = timeout;
@@ -62,62 +62,84 @@ public interface FileChooser {
}
/**
* Returns input element associated with this file chooser.
*
* @since v1.8
*/
ElementHandle element();
/**
* Returns whether this file chooser accepts multiple files.
*
* @since v1.8
*/
boolean isMultiple();
/**
* Returns page this file chooser belongs to.
*
* @since v1.8
*/
Page page();
/**
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths, then
* they are resolved relative to the current working directory. For empty array, clears the selected files.
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths,
* then they are resolved relative to the current working directory. For empty array, clears the selected files.
*
* @since v1.8
*/
default void setFiles(Path files) {
setFiles(files, null);
}
/**
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths, then
* they are resolved relative to the current working directory. For empty array, clears the selected files.
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths,
* then they are resolved relative to the current working directory. For empty array, clears the selected files.
*
* @since v1.8
*/
void setFiles(Path files, SetFilesOptions options);
/**
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths, then
* they are resolved relative to the current working directory. For empty array, clears the selected files.
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths,
* then they are resolved relative to the current working directory. For empty array, clears the selected files.
*
* @since v1.8
*/
default void setFiles(Path[] files) {
setFiles(files, null);
}
/**
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths, then
* they are resolved relative to the current working directory. For empty array, clears the selected files.
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths,
* then they are resolved relative to the current working directory. For empty array, clears the selected files.
*
* @since v1.8
*/
void setFiles(Path[] files, SetFilesOptions options);
/**
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths, then
* they are resolved relative to the current working directory. For empty array, clears the selected files.
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths,
* then they are resolved relative to the current working directory. For empty array, clears the selected files.
*
* @since v1.8
*/
default void setFiles(FilePayload files) {
setFiles(files, null);
}
/**
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths, then
* they are resolved relative to the current working directory. For empty array, clears the selected files.
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths,
* then they are resolved relative to the current working directory. For empty array, clears the selected files.
*
* @since v1.8
*/
void setFiles(FilePayload files, SetFilesOptions options);
/**
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths, then
* they are resolved relative to the current working directory. For empty array, clears the selected files.
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths,
* then they are resolved relative to the current working directory. For empty array, clears the selected files.
*
* @since v1.8
*/
default void setFiles(FilePayload[] files) {
setFiles(files, null);
}
/**
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths, then
* they are resolved relative to the current working directory. For empty array, clears the selected files.
* Sets the value of the file input this chooser is associated with. If some of the {@code filePaths} are relative paths,
* then they are resolved relative to the current working directory. For empty array, clears the selected files.
*
* @since v1.8
*/
void setFiles(FilePayload[] files, SetFilesOptions options);
}
File diff suppressed because it is too large Load Diff
@@ -20,8 +20,8 @@ import com.microsoft.playwright.options.*;
import java.util.regex.Pattern;
/**
* FrameLocator represents a view to the {@code iframe} on the page. It captures the logic sufficient to retrieve the {@code iframe}
* and locate elements in that iframe. FrameLocator can be created with either {@link Page#frameLocator
* FrameLocator represents a view to the {@code iframe} on the page. It captures the logic sufficient to retrieve the
* {@code iframe} and locate elements in that iframe. FrameLocator can be created with either {@link Page#frameLocator
* Page.frameLocator()} or {@link Locator#frameLocator Locator.frameLocator()} method.
* <pre>{@code
* Locator locator = page.frameLocator("#my-frame").getByText("Submit");
@@ -34,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").getByRole("button").click();
* page.frame_locator(".result-frame").getByRole(AriaRole.BUTTON).click();
*
* // Works because we explicitly tell locator to pick the first frame:
* page.frame_locator(".result-frame").first().getByRole("button").click();
* page.frame_locator(".result-frame").first().getByRole(AriaRole.BUTTON).click();
* }</pre>
*
* <p> **Converting Locator to FrameLocator**
@@ -112,8 +112,8 @@ public interface FrameLocator {
*/
public Boolean disabled;
/**
* Whether {@code name} is matched exactly: case-sensitive and whole-string. Defaults to false. Ignored when {@code name} is a regular
* expression. Note that exact match still trims whitespace.
* Whether {@code name} is matched exactly: case-sensitive and whole-string. Defaults to false. Ignored when {@code name}
* is a regular expression. Note that exact match still trims whitespace.
*/
public Boolean exact;
/**
@@ -130,8 +130,8 @@ public interface FrameLocator {
*/
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.
* 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>.
*/
@@ -176,8 +176,8 @@ public interface FrameLocator {
return this;
}
/**
* Whether {@code name} is matched exactly: case-sensitive and whole-string. Defaults to false. Ignored when {@code name} is a regular
* expression. Note that exact match still trims whitespace.
* Whether {@code name} is matched exactly: case-sensitive and whole-string. Defaults to false. Ignored when {@code name}
* is a regular expression. Note that exact match still trims whitespace.
*/
public GetByRoleOptions setExact(boolean exact) {
this.exact = exact;
@@ -203,8 +203,8 @@ public interface FrameLocator {
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.
* 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>.
*/
@@ -293,8 +293,8 @@ public interface FrameLocator {
public Locator has;
/**
* Matches elements containing specified text somewhere inside, possibly in a child or a descendant element. When passed a
* [string], matching is case-insensitive and searches for a substring. For example, {@code "Playwright"} matches
* {@code <article><div>Playwright</div></article>}.
* [string], matching is case-insensitive and searches for a substring. For example, {@code "Playwright"} matches {@code
* <article><div>Playwright</div></article>}.
*/
public Object hasText;
@@ -310,8 +310,8 @@ public interface FrameLocator {
}
/**
* Matches elements containing specified text somewhere inside, possibly in a child or a descendant element. When passed a
* [string], matching is case-insensitive and searches for a substring. For example, {@code "Playwright"} matches
* {@code <article><div>Playwright</div></article>}.
* [string], matching is case-insensitive and searches for a substring. For example, {@code "Playwright"} matches {@code
* <article><div>Playwright</div></article>}.
*/
public LocatorOptions setHasText(String hasText) {
this.hasText = hasText;
@@ -319,8 +319,8 @@ public interface FrameLocator {
}
/**
* Matches elements containing specified text somewhere inside, possibly in a child or a descendant element. When passed a
* [string], matching is case-insensitive and searches for a substring. For example, {@code "Playwright"} matches
* {@code <article><div>Playwright</div></article>}.
* [string], matching is case-insensitive and searches for a substring. For example, {@code "Playwright"} matches {@code
* <article><div>Playwright</div></article>}.
*/
public LocatorOptions setHasText(Pattern hasText) {
this.hasText = hasText;
@@ -329,121 +329,245 @@ public interface FrameLocator {
}
/**
* Returns locator to the first matching frame.
*
* @since v1.17
*/
FrameLocator first();
/**
* When working with iframes, you can create a frame locator that will enter the iframe and allow selecting elements in
* that iframe.
*
* @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.
* @param selector A selector to use when resolving DOM element.
* @since v1.17
*/
FrameLocator frameLocator(String selector);
/**
* Allows locating elements by their alt text. For example, this method will find the image by alt text "Castle":
* Allows locating elements by their alt text.
*
* <p> **Usage**
*
* <p> For example, this method will find the image by alt text "Playwright logo":
* <pre>{@code
* page.getByAltText("Playwright logo").click();
* }</pre>
*
* @param text Text to locate the element for.
* @since v1.27
*/
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":
* Allows locating elements by their alt text.
*
* <p> **Usage**
*
* <p> For example, this method will find the image by alt text "Playwright logo":
* <pre>{@code
* page.getByAltText("Playwright logo").click();
* }</pre>
*
* @param text Text to locate the element for.
* @since v1.27
*/
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":
* Allows locating elements by their alt text.
*
* <p> **Usage**
*
* <p> For example, this method will find the image by alt text "Playwright logo":
* <pre>{@code
* page.getByAltText("Playwright logo").click();
* }</pre>
*
* @param text Text to locate the element for.
* @since v1.27
*/
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":
* Allows locating elements by their alt text.
*
* <p> **Usage**
*
* <p> For example, this method will find the image by alt text "Playwright logo":
* <pre>{@code
* page.getByAltText("Playwright logo").click();
* }</pre>
*
* @param text Text to locate the element for.
* @since v1.27
*/
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:
* Allows locating input elements by the text of the associated label.
*
* <p> **Usage**
*
* <p> For example, this method will find the input by label text "Password" in the following DOM:
* <pre>{@code
* page.getByLabel("Password").fill("secret");
* }</pre>
*
* @param text Text to locate the element for.
* @since v1.27
*/
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:
* Allows locating input elements by the text of the associated label.
*
* <p> **Usage**
*
* <p> For example, this method will find the input by label text "Password" in the following DOM:
* <pre>{@code
* page.getByLabel("Password").fill("secret");
* }</pre>
*
* @param text Text to locate the element for.
* @since v1.27
*/
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:
* Allows locating input elements by the text of the associated label.
*
* <p> **Usage**
*
* <p> For example, this method will find the input by label text "Password" in the following DOM:
* <pre>{@code
* page.getByLabel("Password").fill("secret");
* }</pre>
*
* @param text Text to locate the element for.
* @since v1.27
*/
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:
* Allows locating input elements by the text of the associated label.
*
* <p> **Usage**
*
* <p> For example, this method will find the input by label text "Password" in the following DOM:
* <pre>{@code
* page.getByLabel("Password").fill("secret");
* }</pre>
*
* @param text Text to locate the element for.
* @since v1.27
*/
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":
* Allows locating input elements by the placeholder text.
*
* <p> **Usage**
*
* <p> For example, consider the following DOM structure.
*
* <p> You can fill the input after locating it by the placeholder text:
* <pre>{@code
* page.getByPlaceholder("name@example.com").fill("playwright@microsoft.com");
* }</pre>
*
* @param text Text to locate the element for.
* @since v1.27
*/
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":
* Allows locating input elements by the placeholder text.
*
* <p> **Usage**
*
* <p> For example, consider the following DOM structure.
*
* <p> You can fill the input after locating it by the placeholder text:
* <pre>{@code
* page.getByPlaceholder("name@example.com").fill("playwright@microsoft.com");
* }</pre>
*
* @param text Text to locate the element for.
* @since v1.27
*/
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":
* Allows locating input elements by the placeholder text.
*
* <p> **Usage**
*
* <p> For example, consider the following DOM structure.
*
* <p> You can fill the input after locating it by the placeholder text:
* <pre>{@code
* page.getByPlaceholder("name@example.com").fill("playwright@microsoft.com");
* }</pre>
*
* @param text Text to locate the element for.
* @since v1.27
*/
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":
* Allows locating input elements by the placeholder text.
*
* <p> **Usage**
*
* <p> For example, consider the following DOM structure.
*
* <p> You can fill the input after locating it by the placeholder text:
* <pre>{@code
* page.getByPlaceholder("name@example.com").fill("playwright@microsoft.com");
* }</pre>
*
* @param text Text to locate the element for.
* @since v1.27
*/
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.
* href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*
* <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.
* <p> **Usage**
*
* <p> Consider the following DOM structure.
*
* <p> You can locate each element by it's implicit role:
* <pre>{@code
* assertThat(page
* .getByRole(AriaRole.HEADING,
* new Page.GetByRoleOptions().setName("Sign up")))
* .isVisible();
*
* page.getByRole(AriaRole.CHECKBOX,
* new Page.GetByRoleOptions().setName("Subscribe"))
* .check();
*
* page.getByRole(AriaRole.BUTTON,
* new Page.GetByRoleOptions().setName(
* Pattern.compile("submit", Pattern.CASE_INSENSITIVE)))
* .click();
* }</pre>
*
* <p> **Details**
*
* <p> Role selector **does not replace** accessibility audits and conformance tests, but rather gives early feedback about the
* ARIA guidelines.
*
* <p> 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.
* @since v1.27
*/
default Locator getByRole(AriaRole role) {
return getByRole(role, null);
@@ -451,27 +575,95 @@ public interface FrameLocator {
/**
* 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.
* href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
*
* <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.
* <p> **Usage**
*
* <p> Consider the following DOM structure.
*
* <p> You can locate each element by it's implicit role:
* <pre>{@code
* assertThat(page
* .getByRole(AriaRole.HEADING,
* new Page.GetByRoleOptions().setName("Sign up")))
* .isVisible();
*
* page.getByRole(AriaRole.CHECKBOX,
* new Page.GetByRoleOptions().setName("Subscribe"))
* .check();
*
* page.getByRole(AriaRole.BUTTON,
* new Page.GetByRoleOptions().setName(
* Pattern.compile("submit", Pattern.CASE_INSENSITIVE)))
* .click();
* }</pre>
*
* <p> **Details**
*
* <p> Role selector **does not replace** accessibility audits and conformance tests, but rather gives early feedback about the
* ARIA guidelines.
*
* <p> 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.
* @since v1.27
*/
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.
* Locate element by the test id.
*
* <p> **Usage**
*
* <p> Consider the following DOM structure.
*
* <p> You can locate the element by it's test id:
* <pre>{@code
* page.getByTestId("directions").click();
* }</pre>
*
* <p> **Details**
*
* <p> 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.
* @since v1.27
*/
Locator getByTestId(String testId);
/**
* Allows locating elements that contain given text. Consider the following DOM structure:
* Locate element by the test id.
*
* <p> **Usage**
*
* <p> Consider the following DOM structure.
*
* <p> You can locate the element by it's test id:
* <pre>{@code
* page.getByTestId("directions").click();
* }</pre>
*
* <p> **Details**
*
* <p> 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.
* @since v1.27
*/
Locator getByTestId(Pattern testId);
/**
* Allows locating elements that contain given text.
*
* <p> See also {@link Locator#filter Locator.filter()} that allows to match by another criteria, like an accessible role, and
* then filter by the text content.
*
* <p> **Usage**
*
* <p> Consider the following DOM structure:
*
* <p> You can locate by text substring, exact string, or a regular expression:
* <pre>{@code
@@ -491,22 +683,29 @@ public interface FrameLocator {
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE))
* }</pre>
*
* <p> See also {@link Locator#filter Locator.filter()} that allows to match by another criteria, like an accessible role, and
* then filter by the text content.
* <p> **Details**
*
* <p> <strong>NOTE:</strong> Matching by text always normalizes whitespace, even with exact match. For example, it turns multiple spaces into one,
* <p> Matching by text always normalizes whitespace, even with exact match. For example, it turns multiple spaces into one,
* turns line breaks into spaces and ignores leading and trailing whitespace.
*
* <p> <strong>NOTE:</strong> Input elements of the type {@code button} and {@code submit} are matched by their {@code value} instead of the text content. For example,
* locating by text {@code "Log in"} matches {@code <input type=button value="Log in">}.
* <p> Input elements of the type {@code button} and {@code submit} are matched by their {@code value} instead of the text
* content. For example, locating by text {@code "Log in"} matches {@code <input type=button value="Log in">}.
*
* @param text Text to locate the element for.
* @since v1.27
*/
default Locator getByText(String text) {
return getByText(text, null);
}
/**
* Allows locating elements that contain given text. Consider the following DOM structure:
* Allows locating elements that contain given text.
*
* <p> See also {@link Locator#filter Locator.filter()} that allows to match by another criteria, like an accessible role, and
* then filter by the text content.
*
* <p> **Usage**
*
* <p> Consider the following DOM structure:
*
* <p> You can locate by text substring, exact string, or a regular expression:
* <pre>{@code
@@ -526,20 +725,27 @@ public interface FrameLocator {
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE))
* }</pre>
*
* <p> See also {@link Locator#filter Locator.filter()} that allows to match by another criteria, like an accessible role, and
* then filter by the text content.
* <p> **Details**
*
* <p> <strong>NOTE:</strong> Matching by text always normalizes whitespace, even with exact match. For example, it turns multiple spaces into one,
* <p> Matching by text always normalizes whitespace, even with exact match. For example, it turns multiple spaces into one,
* turns line breaks into spaces and ignores leading and trailing whitespace.
*
* <p> <strong>NOTE:</strong> Input elements of the type {@code button} and {@code submit} are matched by their {@code value} instead of the text content. For example,
* locating by text {@code "Log in"} matches {@code <input type=button value="Log in">}.
* <p> Input elements of the type {@code button} and {@code submit} are matched by their {@code value} instead of the text
* content. For example, locating by text {@code "Log in"} matches {@code <input type=button value="Log in">}.
*
* @param text Text to locate the element for.
* @since v1.27
*/
Locator getByText(String text, GetByTextOptions options);
/**
* Allows locating elements that contain given text. Consider the following DOM structure:
* Allows locating elements that contain given text.
*
* <p> See also {@link Locator#filter Locator.filter()} that allows to match by another criteria, like an accessible role, and
* then filter by the text content.
*
* <p> **Usage**
*
* <p> Consider the following DOM structure:
*
* <p> You can locate by text substring, exact string, or a regular expression:
* <pre>{@code
@@ -559,22 +765,29 @@ public interface FrameLocator {
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE))
* }</pre>
*
* <p> See also {@link Locator#filter Locator.filter()} that allows to match by another criteria, like an accessible role, and
* then filter by the text content.
* <p> **Details**
*
* <p> <strong>NOTE:</strong> Matching by text always normalizes whitespace, even with exact match. For example, it turns multiple spaces into one,
* <p> Matching by text always normalizes whitespace, even with exact match. For example, it turns multiple spaces into one,
* turns line breaks into spaces and ignores leading and trailing whitespace.
*
* <p> <strong>NOTE:</strong> Input elements of the type {@code button} and {@code submit} are matched by their {@code value} instead of the text content. For example,
* locating by text {@code "Log in"} matches {@code <input type=button value="Log in">}.
* <p> Input elements of the type {@code button} and {@code submit} are matched by their {@code value} instead of the text
* content. For example, locating by text {@code "Log in"} matches {@code <input type=button value="Log in">}.
*
* @param text Text to locate the element for.
* @since v1.27
*/
default Locator getByText(Pattern text) {
return getByText(text, null);
}
/**
* Allows locating elements that contain given text. Consider the following DOM structure:
* Allows locating elements that contain given text.
*
* <p> See also {@link Locator#filter Locator.filter()} that allows to match by another criteria, like an accessible role, and
* then filter by the text content.
*
* <p> **Usage**
*
* <p> Consider the following DOM structure:
*
* <p> You can locate by text substring, exact string, or a regular expression:
* <pre>{@code
@@ -594,48 +807,90 @@ public interface FrameLocator {
* page.getByText(Pattern.compile("^hello$", Pattern.CASE_INSENSITIVE))
* }</pre>
*
* <p> See also {@link Locator#filter Locator.filter()} that allows to match by another criteria, like an accessible role, and
* then filter by the text content.
* <p> **Details**
*
* <p> <strong>NOTE:</strong> Matching by text always normalizes whitespace, even with exact match. For example, it turns multiple spaces into one,
* <p> Matching by text always normalizes whitespace, even with exact match. For example, it turns multiple spaces into one,
* turns line breaks into spaces and ignores leading and trailing whitespace.
*
* <p> <strong>NOTE:</strong> Input elements of the type {@code button} and {@code submit} are matched by their {@code value} instead of the text content. For example,
* locating by text {@code "Log in"} matches {@code <input type=button value="Log in">}.
* <p> Input elements of the type {@code button} and {@code submit} are matched by their {@code value} instead of the text
* content. For example, locating by text {@code "Log in"} matches {@code <input type=button value="Log in">}.
*
* @param text Text to locate the element for.
* @since v1.27
*/
Locator getByText(Pattern text, GetByTextOptions options);
/**
* Allows locating elements by their title. For example, this method will find the button by its title "Place the order":
* Allows locating elements by their title attribute.
*
* <p> **Usage**
*
* <p> Consider the following DOM structure.
*
* <p> You can check the issues count after locating it by the title text:
* <pre>{@code
* assertThat(page.getByTitle("Issues count")).hasText("25 issues");
* }</pre>
*
* @param text Text to locate the element for.
* @since v1.27
*/
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 "Place the order":
* Allows locating elements by their title attribute.
*
* <p> **Usage**
*
* <p> Consider the following DOM structure.
*
* <p> You can check the issues count after locating it by the title text:
* <pre>{@code
* assertThat(page.getByTitle("Issues count")).hasText("25 issues");
* }</pre>
*
* @param text Text to locate the element for.
* @since v1.27
*/
Locator getByTitle(String text, GetByTitleOptions options);
/**
* Allows locating elements by their title. For example, this method will find the button by its title "Place the order":
* Allows locating elements by their title attribute.
*
* <p> **Usage**
*
* <p> Consider the following DOM structure.
*
* <p> You can check the issues count after locating it by the title text:
* <pre>{@code
* assertThat(page.getByTitle("Issues count")).hasText("25 issues");
* }</pre>
*
* @param text Text to locate the element for.
* @since v1.27
*/
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 "Place the order":
* Allows locating elements by their title attribute.
*
* <p> **Usage**
*
* <p> Consider the following DOM structure.
*
* <p> You can check the issues count after locating it by the title text:
* <pre>{@code
* assertThat(page.getByTitle("Issues count")).hasText("25 issues");
* }</pre>
*
* @param text Text to locate the element for.
* @since v1.27
*/
Locator getByTitle(Pattern text, GetByTitleOptions options);
/**
* Returns locator to the last matching frame.
*
* @since v1.17
*/
FrameLocator last();
/**
@@ -644,8 +899,8 @@ public interface FrameLocator {
*
* <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.
* @param selector A selector to use when resolving DOM element.
* @since v1.17
*/
default Locator locator(String selector) {
return locator(selector, null);
@@ -656,12 +911,14 @@ public interface FrameLocator {
*
* <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.
* @param selector A selector to use when resolving DOM element.
* @since v1.17
*/
Locator locator(String selector, LocatorOptions options);
/**
* Returns locator to the n-th matching frame. It's zero based, {@code nth(0)} selects the first frame.
*
* @since v1.17
*/
FrameLocator nth(int index);
}
@@ -36,10 +36,14 @@ import java.util.*;
public interface JSHandle {
/**
* Returns either {@code null} or the object handle itself, if the object handle is an instance of {@code ElementHandle}.
*
* @since v1.8
*/
ElementHandle asElement();
/**
* The {@code jsHandle.dispose} method stops referencing the element handle.
*
* @since v1.8
*/
void dispose();
/**
@@ -48,10 +52,10 @@ public interface JSHandle {
* <p> This method passes this handle as the first argument to {@code expression}.
*
* <p> If {@code expression} returns a <a
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then
* {@code handle.evaluate} would wait for the promise to resolve and return its value.
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then {@code
* handle.evaluate} would wait for the promise to resolve and return its value.
*
* <p> Examples:
* <p> **Usage**
* <pre>{@code
* ElementHandle tweetHandle = page.querySelector(".tweet .retweets");
* assertEquals("10 retweets", tweetHandle.evaluate("node => node.innerText"));
@@ -59,6 +63,7 @@ public interface JSHandle {
*
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
* automatically invoked.
* @since v1.8
*/
default Object evaluate(String expression) {
return evaluate(expression, null);
@@ -69,10 +74,10 @@ public interface JSHandle {
* <p> This method passes this handle as the first argument to {@code expression}.
*
* <p> If {@code expression} returns a <a
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then
* {@code handle.evaluate} would wait for the promise to resolve and return its value.
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then {@code
* handle.evaluate} would wait for the promise to resolve and return its value.
*
* <p> Examples:
* <p> **Usage**
* <pre>{@code
* ElementHandle tweetHandle = page.querySelector(".tweet .retweets");
* assertEquals("10 retweets", tweetHandle.evaluate("node => node.innerText"));
@@ -81,6 +86,7 @@ public interface JSHandle {
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
* @since v1.8
*/
Object evaluate(String expression, Object arg);
/**
@@ -88,17 +94,18 @@ public interface JSHandle {
*
* <p> This method passes this handle as the first argument to {@code expression}.
*
* <p> The only difference between {@code jsHandle.evaluate} and {@code jsHandle.evaluateHandle} is that {@code jsHandle.evaluateHandle} returns
* {@code JSHandle}.
* <p> The only difference between {@code jsHandle.evaluate} and {@code jsHandle.evaluateHandle} is that {@code
* jsHandle.evaluateHandle} returns {@code JSHandle}.
*
* <p> If the function passed to the {@code jsHandle.evaluateHandle} returns a <a
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then
* {@code jsHandle.evaluateHandle} would wait for the promise to resolve and return its value.
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then {@code
* jsHandle.evaluateHandle} would wait for the promise to resolve and return its value.
*
* <p> See {@link Page#evaluateHandle Page.evaluateHandle()} for more details.
*
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
* automatically invoked.
* @since v1.8
*/
default JSHandle evaluateHandle(String expression) {
return evaluateHandle(expression, null);
@@ -108,22 +115,25 @@ public interface JSHandle {
*
* <p> This method passes this handle as the first argument to {@code expression}.
*
* <p> The only difference between {@code jsHandle.evaluate} and {@code jsHandle.evaluateHandle} is that {@code jsHandle.evaluateHandle} returns
* {@code JSHandle}.
* <p> The only difference between {@code jsHandle.evaluate} and {@code jsHandle.evaluateHandle} is that {@code
* jsHandle.evaluateHandle} returns {@code JSHandle}.
*
* <p> If the function passed to the {@code jsHandle.evaluateHandle} returns a <a
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then
* {@code jsHandle.evaluateHandle} would wait for the promise to resolve and return its value.
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then {@code
* jsHandle.evaluateHandle} would wait for the promise to resolve and return its value.
*
* <p> See {@link Page#evaluateHandle Page.evaluateHandle()} for more details.
*
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
* @since v1.8
*/
JSHandle evaluateHandle(String expression, Object arg);
/**
* The method returns a map with **own property names** as keys and JSHandle instances for the property values.
*
* <p> **Usage**
* <pre>{@code
* JSHandle handle = page.evaluateHandle("() => ({window, document}"););
* Map<String, JSHandle> properties = handle.getProperties();
@@ -131,12 +141,15 @@ public interface JSHandle {
* JSHandle documentHandle = properties.get("document");
* handle.dispose();
* }</pre>
*
* @since v1.8
*/
Map<String, JSHandle> getProperties();
/**
* Fetches a single property from the referenced object.
*
* @param propertyName property to get
* @since v1.8
*/
JSHandle getProperty(String propertyName);
/**
@@ -144,6 +157,8 @@ public interface JSHandle {
*
* <p> <strong>NOTE:</strong> The method will return an empty JSON object if the referenced object is not stringifiable. It will throw an error if the
* object has circular references.
*
* @since v1.8
*/
Object jsonValue();
}
@@ -20,7 +20,8 @@ import com.microsoft.playwright.options.*;
/**
* Keyboard provides an api for managing a virtual keyboard. The high level api is {@link Keyboard#type Keyboard.type()},
* which takes raw characters and generates proper {@code keydown}, {@code keypress}/{@code input}, and {@code keyup} events on your page.
* which takes raw characters and generates proper {@code keydown}, {@code keypress}/{@code input}, and {@code keyup}
* events on your page.
*
* <p> For finer control, you can use {@link Keyboard#down Keyboard.down()}, {@link Keyboard#up Keyboard.up()}, and {@link
* Keyboard#insertText Keyboard.insertText()} to manually fire events as if they were generated from a real keyboard.
@@ -89,18 +90,21 @@ public interface Keyboard {
* character to generate the text for. A superset of the {@code key} values can be found <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values">here</a>. Examples of the keys are:
*
* <p> {@code F1} - {@code F12}, {@code Digit0}- {@code Digit9}, {@code KeyA}- {@code KeyZ}, {@code Backquote}, {@code Minus}, {@code Equal}, {@code Backslash}, {@code Backspace}, {@code Tab},
* {@code Delete}, {@code Escape}, {@code ArrowDown}, {@code End}, {@code Enter}, {@code Home}, {@code Insert}, {@code PageDown}, {@code PageUp}, {@code ArrowRight}, {@code ArrowUp}, etc.
* <p> {@code F1} - {@code F12}, {@code Digit0}- {@code Digit9}, {@code KeyA}- {@code KeyZ}, {@code Backquote}, {@code Minus},
* {@code Equal}, {@code Backslash}, {@code Backspace}, {@code Tab}, {@code Delete}, {@code Escape}, {@code ArrowDown},
* {@code End}, {@code Enter}, {@code Home}, {@code Insert}, {@code PageDown}, {@code PageUp}, {@code ArrowRight}, {@code
* ArrowUp}, etc.
*
* <p> Following modification shortcuts are also supported: {@code Shift}, {@code Control}, {@code Alt}, {@code Meta}, {@code ShiftLeft}.
* <p> Following modification shortcuts are also supported: {@code Shift}, {@code Control}, {@code Alt}, {@code Meta}, {@code
* ShiftLeft}.
*
* <p> Holding down {@code Shift} will type the text that corresponds to the {@code key} in the upper case.
*
* <p> If {@code key} is a single character, it is case-sensitive, so the values {@code a} and {@code A} will generate different respective
* texts.
* <p> If {@code key} is a single character, it is case-sensitive, so the values {@code a} and {@code A} will generate
* different respective texts.
*
* <p> If {@code key} is a modifier key, {@code Shift}, {@code Meta}, {@code Control}, or {@code Alt}, subsequent key presses will be sent with that modifier
* active. To release the modifier key, use {@link Keyboard#up Keyboard.up()}.
* <p> If {@code key} is a modifier key, {@code Shift}, {@code Meta}, {@code Control}, or {@code Alt}, subsequent key presses
* will be sent with that modifier active. To release the modifier key, use {@link Keyboard#up Keyboard.up()}.
*
* <p> After the key is pressed once, subsequent calls to {@link Keyboard#down Keyboard.down()} will have <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/repeat">repeat</a> set to true. To release the key,
@@ -109,17 +113,22 @@ public interface Keyboard {
* <p> <strong>NOTE:</strong> Modifier keys DO influence {@code keyboard.down}. Holding down {@code Shift} will type the text in upper case.
*
* @param key Name of the key to press or a character to generate, such as {@code ArrowLeft} or {@code a}.
* @since v1.8
*/
void down(String key);
/**
* Dispatches only {@code input} event, does not emit the {@code keydown}, {@code keyup} or {@code keypress} events.
*
* <p> **Usage**
* <pre>{@code
* page.keyboard().insertText("嗨");
* }</pre>
*
* <p> <strong>NOTE:</strong> Modifier keys DO NOT effect {@code keyboard.insertText}. Holding down {@code Shift} will not type the text in upper case.
* <p> <strong>NOTE:</strong> Modifier keys DO NOT effect {@code keyboard.insertText}. Holding down {@code Shift} will not type the text in upper
* case.
*
* @param text Sets input to the specified text value.
* @since v1.8
*/
void insertText(String text);
/**
@@ -128,18 +137,23 @@ public interface Keyboard {
* character to generate the text for. A superset of the {@code key} values can be found <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values">here</a>. Examples of the keys are:
*
* <p> {@code F1} - {@code F12}, {@code Digit0}- {@code Digit9}, {@code KeyA}- {@code KeyZ}, {@code Backquote}, {@code Minus}, {@code Equal}, {@code Backslash}, {@code Backspace}, {@code Tab},
* {@code Delete}, {@code Escape}, {@code ArrowDown}, {@code End}, {@code Enter}, {@code Home}, {@code Insert}, {@code PageDown}, {@code PageUp}, {@code ArrowRight}, {@code ArrowUp}, etc.
* <p> {@code F1} - {@code F12}, {@code Digit0}- {@code Digit9}, {@code KeyA}- {@code KeyZ}, {@code Backquote}, {@code Minus},
* {@code Equal}, {@code Backslash}, {@code Backspace}, {@code Tab}, {@code Delete}, {@code Escape}, {@code ArrowDown},
* {@code End}, {@code Enter}, {@code Home}, {@code Insert}, {@code PageDown}, {@code PageUp}, {@code ArrowRight}, {@code
* ArrowUp}, etc.
*
* <p> Following modification shortcuts are also supported: {@code Shift}, {@code Control}, {@code Alt}, {@code Meta}, {@code ShiftLeft}.
* <p> Following modification shortcuts are also supported: {@code Shift}, {@code Control}, {@code Alt}, {@code Meta}, {@code
* ShiftLeft}.
*
* <p> Holding down {@code Shift} will type the text that corresponds to the {@code key} in the upper case.
*
* <p> If {@code key} is a single character, it is case-sensitive, so the values {@code a} and {@code A} will generate different respective
* texts.
* <p> If {@code key} is a single character, it is case-sensitive, so the values {@code a} and {@code A} will generate
* different respective texts.
*
* <p> Shortcuts such as {@code key: "Control+o"} or {@code key: "Control+Shift+T"} are supported as well. When specified with the
* modifier, modifier is pressed and being held while the subsequent key is being pressed.
* <p> Shortcuts such as {@code key: "Control+o"} or {@code key: "Control+Shift+T"} are supported as well. When specified with
* the modifier, modifier is pressed and being held while the subsequent key is being pressed.
*
* <p> **Usage**
* <pre>{@code
* Page page = browser.newPage();
* page.navigate("https://keycode.info");
@@ -155,6 +169,7 @@ public interface Keyboard {
* <p> Shortcut for {@link Keyboard#down Keyboard.down()} and {@link Keyboard#up Keyboard.up()}.
*
* @param key Name of the key to press or a character to generate, such as {@code ArrowLeft} or {@code a}.
* @since v1.8
*/
default void press(String key) {
press(key, null);
@@ -165,18 +180,23 @@ public interface Keyboard {
* character to generate the text for. A superset of the {@code key} values can be found <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values">here</a>. Examples of the keys are:
*
* <p> {@code F1} - {@code F12}, {@code Digit0}- {@code Digit9}, {@code KeyA}- {@code KeyZ}, {@code Backquote}, {@code Minus}, {@code Equal}, {@code Backslash}, {@code Backspace}, {@code Tab},
* {@code Delete}, {@code Escape}, {@code ArrowDown}, {@code End}, {@code Enter}, {@code Home}, {@code Insert}, {@code PageDown}, {@code PageUp}, {@code ArrowRight}, {@code ArrowUp}, etc.
* <p> {@code F1} - {@code F12}, {@code Digit0}- {@code Digit9}, {@code KeyA}- {@code KeyZ}, {@code Backquote}, {@code Minus},
* {@code Equal}, {@code Backslash}, {@code Backspace}, {@code Tab}, {@code Delete}, {@code Escape}, {@code ArrowDown},
* {@code End}, {@code Enter}, {@code Home}, {@code Insert}, {@code PageDown}, {@code PageUp}, {@code ArrowRight}, {@code
* ArrowUp}, etc.
*
* <p> Following modification shortcuts are also supported: {@code Shift}, {@code Control}, {@code Alt}, {@code Meta}, {@code ShiftLeft}.
* <p> Following modification shortcuts are also supported: {@code Shift}, {@code Control}, {@code Alt}, {@code Meta}, {@code
* ShiftLeft}.
*
* <p> Holding down {@code Shift} will type the text that corresponds to the {@code key} in the upper case.
*
* <p> If {@code key} is a single character, it is case-sensitive, so the values {@code a} and {@code A} will generate different respective
* texts.
* <p> If {@code key} is a single character, it is case-sensitive, so the values {@code a} and {@code A} will generate
* different respective texts.
*
* <p> Shortcuts such as {@code key: "Control+o"} or {@code key: "Control+Shift+T"} are supported as well. When specified with the
* modifier, modifier is pressed and being held while the subsequent key is being pressed.
* <p> Shortcuts such as {@code key: "Control+o"} or {@code key: "Control+Shift+T"} are supported as well. When specified with
* the modifier, modifier is pressed and being held while the subsequent key is being pressed.
*
* <p> **Usage**
* <pre>{@code
* Page page = browser.newPage();
* page.navigate("https://keycode.info");
@@ -192,12 +212,15 @@ public interface Keyboard {
* <p> Shortcut for {@link Keyboard#down Keyboard.down()} and {@link Keyboard#up Keyboard.up()}.
*
* @param key Name of the key to press or a character to generate, such as {@code ArrowLeft} or {@code a}.
* @since v1.8
*/
void press(String key, PressOptions options);
/**
* Sends a {@code keydown}, {@code keypress}/{@code input}, and {@code keyup} event for each character in the text.
*
* <p> To press a special key, like {@code Control} or {@code ArrowDown}, use {@link Keyboard#press Keyboard.press()}.
*
* <p> **Usage**
* <pre>{@code
* // Types instantly
* page.keyboard().type("Hello");
@@ -210,6 +233,7 @@ public interface Keyboard {
* <p> <strong>NOTE:</strong> For characters that are not on a US keyboard, only an {@code input} event will be sent.
*
* @param text A text to type into a focused element.
* @since v1.8
*/
default void type(String text) {
type(text, null);
@@ -218,6 +242,8 @@ public interface Keyboard {
* Sends a {@code keydown}, {@code keypress}/{@code input}, and {@code keyup} event for each character in the text.
*
* <p> To press a special key, like {@code Control} or {@code ArrowDown}, use {@link Keyboard#press Keyboard.press()}.
*
* <p> **Usage**
* <pre>{@code
* // Types instantly
* page.keyboard().type("Hello");
@@ -230,12 +256,14 @@ public interface Keyboard {
* <p> <strong>NOTE:</strong> For characters that are not on a US keyboard, only an {@code input} event will be sent.
*
* @param text A text to type into a focused element.
* @since v1.8
*/
void type(String text, TypeOptions options);
/**
* Dispatches a {@code keyup} event.
*
* @param key Name of the key to press or a character to generate, such as {@code ArrowLeft} or {@code a}.
* @since v1.8
*/
void up(String key);
}
File diff suppressed because it is too large Load Diff
@@ -161,17 +161,23 @@ public interface Mouse {
}
/**
* Shortcut for {@link Mouse#move Mouse.move()}, {@link Mouse#down Mouse.down()}, {@link Mouse#up Mouse.up()}.
*
* @since v1.8
*/
default void click(double x, double y) {
click(x, y, null);
}
/**
* Shortcut for {@link Mouse#move Mouse.move()}, {@link Mouse#down Mouse.down()}, {@link Mouse#up Mouse.up()}.
*
* @since v1.8
*/
void click(double x, double y, ClickOptions options);
/**
* Shortcut for {@link Mouse#move Mouse.move()}, {@link Mouse#down Mouse.down()}, {@link Mouse#up Mouse.up()}, {@link
* Mouse#down Mouse.down()} and {@link Mouse#up Mouse.up()}.
*
* @since v1.8
*/
default void dblclick(double x, double y) {
dblclick(x, y, null);
@@ -179,36 +185,50 @@ public interface Mouse {
/**
* Shortcut for {@link Mouse#move Mouse.move()}, {@link Mouse#down Mouse.down()}, {@link Mouse#up Mouse.up()}, {@link
* Mouse#down Mouse.down()} and {@link Mouse#up Mouse.up()}.
*
* @since v1.8
*/
void dblclick(double x, double y, DblclickOptions options);
/**
* Dispatches a {@code mousedown} event.
*
* @since v1.8
*/
default void down() {
down(null);
}
/**
* Dispatches a {@code mousedown} event.
*
* @since v1.8
*/
void down(DownOptions options);
/**
* Dispatches a {@code mousemove} event.
*
* @since v1.8
*/
default void move(double x, double y) {
move(x, y, null);
}
/**
* Dispatches a {@code mousemove} event.
*
* @since v1.8
*/
void move(double x, double y, MoveOptions options);
/**
* Dispatches a {@code mouseup} event.
*
* @since v1.8
*/
default void up() {
up(null);
}
/**
* Dispatches a {@code mouseup} event.
*
* @since v1.8
*/
void up(UpOptions options);
/**
@@ -219,6 +239,7 @@ public interface Mouse {
*
* @param deltaX Pixels to scroll horizontally.
* @param deltaY Pixels to scroll vertically.
* @since v1.15
*/
void wheel(double deltaX, double deltaY);
}
File diff suppressed because it is too large Load Diff
@@ -58,39 +58,53 @@ public interface Playwright extends AutoCloseable {
}
/**
* This object can be used to launch or connect to Chromium, returning instances of {@code Browser}.
*
* @since v1.8
*/
BrowserType chromium();
/**
* This object can be used to launch or connect to Firefox, returning instances of {@code Browser}.
*
* @since v1.8
*/
BrowserType firefox();
/**
* Exposes API that can be used for the Web API testing.
*
* @since v1.16
*/
APIRequest request();
/**
* Selectors can be used to install custom selector engines. See <a
* href="https://playwright.dev/java/docs/selectors">Working with selectors</a> for more information.
* href="https://playwright.dev/java/docs/extensibility">extensibility</a> for more information.
*
* @since v1.8
*/
Selectors selectors();
/**
* This object can be used to launch or connect to WebKit, returning instances of {@code Browser}.
*
* @since v1.8
*/
BrowserType webkit();
/**
* Terminates this instance of Playwright, will also close all created browsers if they are still running.
*
* @since v1.9
*/
void close();
/**
* Launches new Playwright driver process and connects to it. {@link Playwright#close Playwright.close()} should be called
* when the instance is no longer needed.
* <pre>{@code
* Playwright playwright = Playwright.create()) {
* Playwright playwright = Playwright.create();
* Browser browser = playwright.webkit().launch();
* Page page = browser.newPage();
* page.navigate("https://www.w3.org/");
* playwright.close();
* }</pre>
*
* @since v1.10
*/
static Playwright create(CreateOptions options) {
return PlaywrightImpl.create(options);
@@ -28,75 +28,98 @@ import java.util.*;
* complete.</li>
* </ul>
*
* <p> If request fails at some point, then instead of {@code "requestfinished"} event (and possibly instead of 'response' event),
* the {@link Page#onRequestFailed Page.onRequestFailed()} event is emitted.
* <p> If request fails at some point, then instead of {@code "requestfinished"} event (and possibly instead of 'response'
* event), the {@link Page#onRequestFailed Page.onRequestFailed()} event is emitted.
*
* <p> <strong>NOTE:</strong> HTTP Error responses, such as 404 or 503, are still successful responses from HTTP standpoint, so request will complete
* with {@code "requestfinished"} event.
*
* <p> If request gets a 'redirect' response, the request is successfully finished with the {@code requestfinished} event, and a new
* request is issued to a redirected url.
* <p> If request gets a 'redirect' response, the request is successfully finished with the {@code requestfinished} event, and
* a new request is issued to a redirected url.
*/
public interface Request {
/**
* An object with all the request HTTP headers associated with this request. The header names are lower-cased.
*
* @since v1.15
*/
Map<String, String> allHeaders();
/**
* The method returns {@code null} unless this request has failed, as reported by {@code requestfailed} event.
*
* <p> **Usage**
*
* <p> Example of logging of all the failed requests:
* <pre>{@code
* page.onRequestFailed(request -> {
* System.out.println(request.url() + " " + request.failure());
* });
* }</pre>
*
* @since v1.8
*/
String failure();
/**
* Returns the {@code Frame} that initiated this request.
*
* @since v1.8
*/
Frame frame();
/**
* An object with the request HTTP headers. The header names are lower-cased. Note that this method does not return
* security-related headers, including cookie-related ones. You can use {@link Request#allHeaders Request.allHeaders()} for
* complete list of headers that include {@code cookie} information.
*
* @since v1.8
*/
Map<String, String> headers();
/**
* An array with all the request HTTP headers associated with this request. Unlike {@link Request#allHeaders
* Request.allHeaders()}, header names are NOT lower-cased. Headers with multiple entries, such as {@code Set-Cookie}, appear in
* the array multiple times.
* Request.allHeaders()}, header names are NOT lower-cased. Headers with multiple entries, such as {@code Set-Cookie},
* appear in the array multiple times.
*
* @since v1.15
*/
List<HttpHeader> headersArray();
/**
* Returns the value of the header matching the name. The name is case insensitive.
*
* @param name Name of the header.
* @since v1.15
*/
String headerValue(String name);
/**
* Whether this request is driving frame's navigation.
*
* @since v1.8
*/
boolean isNavigationRequest();
/**
* Request's method (GET, POST, etc.)
*
* @since v1.8
*/
String method();
/**
* Request's post body, if any.
*
* @since v1.8
*/
String postData();
/**
* Request's post body in a binary form, if any.
*
* @since v1.8
*/
byte[] postDataBuffer();
/**
* Request that was redirected by the server to this one, if any.
*
* <p> When the server responds with a redirect, Playwright creates a new {@code Request} object. The two requests are connected by
* {@code redirectedFrom()} and {@code redirectedTo()} methods. When multiple server redirects has happened, it is possible to
* construct the whole redirect chain by repeatedly calling {@code redirectedFrom()}.
* <p> When the server responds with a redirect, Playwright creates a new {@code Request} object. The two requests are
* connected by {@code redirectedFrom()} and {@code redirectedTo()} methods. When multiple server redirects has happened,
* it is possible to construct the whole redirect chain by repeatedly calling {@code redirectedFrom()}.
*
* <p> **Usage**
*
* <p> For example, if the website {@code http://example.com} redirects to {@code https://example.com}:
* <pre>{@code
@@ -109,35 +132,49 @@ public interface Request {
* Response response = page.navigate("https://google.com");
* System.out.println(response.request().redirectedFrom()); // null
* }</pre>
*
* @since v1.8
*/
Request redirectedFrom();
/**
* New request issued by the browser if the server responded with redirect.
*
* <p> **Usage**
*
* <p> This method is the opposite of {@link Request#redirectedFrom Request.redirectedFrom()}:
* <pre>{@code
* System.out.println(request.redirectedFrom().redirectedTo() == request); // true
* }</pre>
*
* @since v1.8
*/
Request redirectedTo();
/**
* Contains the request's resource type as it was perceived by the rendering engine. ResourceType will be one of the
* following: {@code document}, {@code stylesheet}, {@code image}, {@code media}, {@code font}, {@code script}, {@code texttrack}, {@code xhr}, {@code fetch}, {@code eventsource},
* {@code websocket}, {@code manifest}, {@code other}.
* following: {@code document}, {@code stylesheet}, {@code image}, {@code media}, {@code font}, {@code script}, {@code
* texttrack}, {@code xhr}, {@code fetch}, {@code eventsource}, {@code websocket}, {@code manifest}, {@code other}.
*
* @since v1.8
*/
String resourceType();
/**
* Returns the matching {@code Response} object, or {@code null} if the response was not received due to error.
*
* @since v1.8
*/
Response response();
/**
* Returns resource size information for given request.
*
* @since v1.15
*/
Sizes sizes();
/**
* Returns resource timing information for given request. Most of the timing values become available upon the response,
* {@code responseEnd} becomes available when request finishes. Find more information at <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming">Resource Timing API</a>.
*
* <p> **Usage**
* <pre>{@code
* page.onRequestFinished(request -> {
* Timing timing = request.timing();
@@ -145,10 +182,14 @@ public interface Request {
* });
* page.navigate("http://example.com");
* }</pre>
*
* @since v1.8
*/
Timing timing();
/**
* URL of the request.
*
* @since v1.8
*/
String url();
}
@@ -25,81 +25,113 @@ import java.util.*;
public interface Response {
/**
* An object with all the response HTTP headers associated with this response.
*
* @since v1.15
*/
Map<String, String> allHeaders();
/**
* Returns the buffer with response body.
*
* @since v1.8
*/
byte[] body();
/**
* Waits for this response to finish, returns always {@code null}.
*
* @since v1.8
*/
String finished();
/**
* Returns the {@code Frame} that initiated this response.
*
* @since v1.8
*/
Frame frame();
/**
* Indicates whether this Response was fulfilled by a Service Worker's Fetch Handler (i.e. via <a
* href="https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent/respondWith">FetchEvent.respondWith</a>).
*
* @since v1.23
*/
boolean fromServiceWorker();
/**
* An object with the response HTTP headers. The header names are lower-cased. Note that this method does not return
* security-related headers, including cookie-related ones. You can use {@link Response#allHeaders Response.allHeaders()}
* for complete list of headers that include {@code cookie} information.
*
* @since v1.8
*/
Map<String, String> headers();
/**
* An array with all the request HTTP headers associated with this response. Unlike {@link Response#allHeaders
* Response.allHeaders()}, header names are NOT lower-cased. Headers with multiple entries, such as {@code Set-Cookie}, appear in
* the array multiple times.
* Response.allHeaders()}, header names are NOT lower-cased. Headers with multiple entries, such as {@code Set-Cookie},
* appear in the array multiple times.
*
* @since v1.15
*/
List<HttpHeader> headersArray();
/**
* Returns the value of the header matching the name. The name is case insensitive. If multiple headers have the same name
* (except {@code set-cookie}), they are returned as a list separated by {@code , }. For {@code set-cookie}, the {@code \n} separator is used. If
* no headers are found, {@code null} is returned.
* (except {@code set-cookie}), they are returned as a list separated by {@code , }. For {@code set-cookie}, the {@code \n}
* separator is used. If no headers are found, {@code null} is returned.
*
* @param name Name of the header.
* @since v1.15
*/
String headerValue(String name);
/**
* Returns all values of the headers matching the name, for example {@code set-cookie}. The name is case insensitive.
*
* @param name Name of the header.
* @since v1.15
*/
List<String> headerValues(String name);
/**
* Contains a boolean stating whether the response was successful (status in the range 200-299) or not.
*
* @since v1.8
*/
boolean ok();
/**
* Returns the matching {@code Request} object.
*
* @since v1.8
*/
Request request();
/**
* Returns SSL and other security information.
*
* @since v1.13
*/
SecurityDetails securityDetails();
/**
* Returns the IP address and port of the server.
*
* @since v1.13
*/
ServerAddr serverAddr();
/**
* Contains the status code of the response (e.g., 200 for a success).
*
* @since v1.8
*/
int status();
/**
* Contains the status text of the response (e.g. usually an "OK" for a success).
*
* @since v1.8
*/
String statusText();
/**
* Returns the text representation of response body.
*
* @since v1.8
*/
String text();
/**
* Contains the URL of the response.
*
* @since v1.8
*/
String url();
}
@@ -32,11 +32,11 @@ public interface Route {
*/
public Map<String, String> headers;
/**
* If set changes the request method (e.g. GET or POST)
* If set changes the request method (e.g. GET or POST).
*/
public String method;
/**
* If set changes the post data of request
* If set changes the post data of request.
*/
public Object postData;
/**
@@ -52,21 +52,21 @@ public interface Route {
return this;
}
/**
* If set changes the request method (e.g. GET or POST)
* If set changes the request method (e.g. GET or POST).
*/
public ResumeOptions setMethod(String method) {
this.method = method;
return this;
}
/**
* If set changes the post data of request
* If set changes the post data of request.
*/
public ResumeOptions setPostData(String postData) {
this.postData = postData;
return this;
}
/**
* If set changes the post data of request
* If set changes the post data of request.
*/
public ResumeOptions setPostData(byte[] postData) {
this.postData = postData;
@@ -86,11 +86,11 @@ public interface Route {
*/
public Map<String, String> headers;
/**
* If set changes the request method (e.g. GET or POST)
* If set changes the request method (e.g. GET or POST).
*/
public String method;
/**
* If set changes the post data of request
* If set changes the post data of request.
*/
public Object postData;
/**
@@ -107,21 +107,21 @@ public interface Route {
return this;
}
/**
* If set changes the request method (e.g. GET or POST)
* If set changes the request method (e.g. GET or POST).
*/
public FallbackOptions setMethod(String method) {
this.method = method;
return this;
}
/**
* If set changes the post data of request
* If set changes the post data of request.
*/
public FallbackOptions setPostData(String postData) {
this.postData = postData;
return this;
}
/**
* If set changes the post data of request
* If set changes the post data of request.
*/
public FallbackOptions setPostData(byte[] postData) {
this.postData = postData;
@@ -136,6 +136,73 @@ public interface Route {
return this;
}
}
class FetchOptions {
/**
* If set changes the request HTTP headers. Header values will be converted to a string.
*/
public Map<String, String> headers;
/**
* Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is
* exceeded. Defaults to {@code 20}. Pass {@code 0} to not follow redirects.
*/
public Integer maxRedirects;
/**
* If set changes the request method (e.g. GET or POST).
*/
public String method;
/**
* If set changes the post data of request.
*/
public Object postData;
/**
* If set changes the request URL. New URL must have same protocol as original one.
*/
public String url;
/**
* If set changes the request HTTP headers. Header values will be converted to a string.
*/
public FetchOptions setHeaders(Map<String, String> headers) {
this.headers = headers;
return this;
}
/**
* Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is
* exceeded. Defaults to {@code 20}. Pass {@code 0} to not follow redirects.
*/
public FetchOptions setMaxRedirects(int maxRedirects) {
this.maxRedirects = maxRedirects;
return this;
}
/**
* If set changes the request method (e.g. GET or POST).
*/
public FetchOptions setMethod(String method) {
this.method = method;
return this;
}
/**
* If set changes the post data of request.
*/
public FetchOptions setPostData(String postData) {
this.postData = postData;
return this;
}
/**
* If set changes the post data of request.
*/
public FetchOptions setPostData(byte[] postData) {
this.postData = postData;
return this;
}
/**
* If set changes the request URL. New URL must have same protocol as original one.
*/
public FetchOptions setUrl(String url) {
this.url = url;
return this;
}
}
class FulfillOptions {
/**
* Optional response body as text.
@@ -154,13 +221,13 @@ public interface Route {
*/
public Map<String, String> headers;
/**
* File path to respond with. The content type will be inferred from file extension. If {@code path} is a relative path, then it
* is resolved relative to the current working directory.
* File path to respond with. The content type will be inferred from file extension. If {@code path} is a relative path,
* then it is resolved relative to the current working directory.
*/
public Path path;
/**
* {@code APIResponse} to fulfill route's request with. Individual fields of the response (such as headers) can be overridden
* using fulfill options.
* {@code APIResponse} to fulfill route's request with. Individual fields of the response (such as headers) can be
* overridden using fulfill options.
*/
public APIResponse response;
/**
@@ -197,16 +264,16 @@ public interface Route {
return this;
}
/**
* File path to respond with. The content type will be inferred from file extension. If {@code path} is a relative path, then it
* is resolved relative to the current working directory.
* File path to respond with. The content type will be inferred from file extension. If {@code path} is a relative path,
* then it is resolved relative to the current working directory.
*/
public FulfillOptions setPath(Path path) {
this.path = path;
return this;
}
/**
* {@code APIResponse} to fulfill route's request with. Individual fields of the response (such as headers) can be overridden
* using fulfill options.
* {@code APIResponse} to fulfill route's request with. Individual fields of the response (such as headers) can be
* overridden using fulfill options.
*/
public FulfillOptions setResponse(APIResponse response) {
this.response = response;
@@ -222,6 +289,8 @@ public interface Route {
}
/**
* Aborts the route's request.
*
* @since v1.8
*/
default void abort() {
abort(null);
@@ -233,11 +302,11 @@ public interface Route {
* <ul>
* <li> {@code "aborted"} - An operation was aborted (due to user action)</li>
* <li> {@code "accessdenied"} - Permission to access a resource, other than the network, was denied</li>
* <li> {@code "addressunreachable"} - The IP address is unreachable. This usually means that there is no route to the specified host
* or network.</li>
* <li> {@code "addressunreachable"} - The IP address is unreachable. This usually means that there is no route to the specified
* host or network.</li>
* <li> {@code "blockedbyclient"} - The client chose to block the request.</li>
* <li> {@code "blockedbyresponse"} - The request failed because the response was delivered along with requirements which are not met
* ('X-Frame-Options' and 'Content-Security-Policy' ancestor checks, for instance).</li>
* <li> {@code "blockedbyresponse"} - The request failed because the response was delivered along with requirements which are
* not met ('X-Frame-Options' and 'Content-Security-Policy' ancestor checks, for instance).</li>
* <li> {@code "connectionaborted"} - A connection timed out as a result of not receiving an ACK for data sent.</li>
* <li> {@code "connectionclosed"} - A connection was closed (corresponding to a TCP FIN).</li>
* <li> {@code "connectionfailed"} - A connection attempt failed.</li>
@@ -248,10 +317,13 @@ public interface Route {
* <li> {@code "timedout"} - An operation timed out.</li>
* <li> {@code "failed"} - A generic failure occurred.</li>
* </ul>
* @since v1.8
*/
void abort(String errorCode);
/**
* Continues route's request with optional overrides.
*
* <p> **Usage**
* <pre>{@code
* page.route("**\/*", route -> {
* // Override headers
@@ -261,12 +333,23 @@ public interface Route {
* route.resume(new Route.ResumeOptions().setHeaders(headers));
* });
* }</pre>
*
* <p> **Details**
*
* <p> Note that any overrides such as {@code url} or {@code headers} only apply to the request being routed. If this request
* results in a redirect, overrides will not be applied to the new redirected request. If you want to propagate a header
* through redirects, use the combination of {@link Route#fetch Route.fetch()} and {@link Route#fulfill Route.fulfill()}
* instead.
*
* @since v1.8
*/
default void resume() {
resume(null);
}
/**
* Continues route's request with optional overrides.
*
* <p> **Usage**
* <pre>{@code
* page.route("**\/*", route -> {
* // Override headers
@@ -276,6 +359,15 @@ public interface Route {
* route.resume(new Route.ResumeOptions().setHeaders(headers));
* });
* }</pre>
*
* <p> **Details**
*
* <p> Note that any overrides such as {@code url} or {@code headers} only apply to the request being routed. If this request
* results in a redirect, overrides will not be applied to the new redirected request. If you want to propagate a header
* through redirects, use the combination of {@link Route#fetch Route.fetch()} and {@link Route#fulfill Route.fulfill()}
* instead.
*
* @since v1.8
*/
void resume(ResumeOptions options);
/**
@@ -283,6 +375,8 @@ public interface Route {
* registered route can always override all the previous ones. In the example below, request will be handled by the
* bottom-most handler first, then it'll fall back to the previous one and in the end will be aborted by the first
* registered route.
*
* <p> **Usage**
* <pre>{@code
* page.route("**\/*", route -> {
* // Runs last.
@@ -335,6 +429,8 @@ public interface Route {
* route.fallback(new Route.ResumeOptions().setHeaders(headers));
* });
* }</pre>
*
* @since v1.23
*/
default void fallback() {
fallback(null);
@@ -344,6 +440,8 @@ public interface Route {
* registered route can always override all the previous ones. In the example below, request will be handled by the
* bottom-most handler first, then it'll fall back to the previous one and in the end will be aborted by the first
* registered route.
*
* <p> **Usage**
* <pre>{@code
* page.route("**\/*", route -> {
* // Runs last.
@@ -396,11 +494,69 @@ public interface Route {
* route.fallback(new Route.ResumeOptions().setHeaders(headers));
* });
* }</pre>
*
* @since v1.23
*/
void fallback(FallbackOptions options);
/**
* Performs the request and fetches result without fulfilling it, so that the response could be modified and then
* fulfilled.
*
* <p> **Usage**
* <pre>{@code
* page.route("https://dog.ceo/api/breeds/list/all", route -> {
* APIResponse response = route.fetch();
* JsonObject json = new Gson().fromJson(response.text(), JsonObject.class);
* JsonObject message = itemObj.get("json").getAsJsonObject();
* message.set("big_red_dog", new JsonArray());
* route.fulfill(new Route.FulfillOptions()
* .setResponse(response)
* .setBody(json.toString()));
* });
* }</pre>
*
* <p> **Details**
*
* <p> Note that {@code headers} option will apply to the fetched request as well as any redirects initiated by it. If you want
* to only apply {@code headers} to the original request, but not to redirects, look into {@link Route#resume
* Route.resume()} instead.
*
* @since v1.29
*/
default APIResponse fetch() {
return fetch(null);
}
/**
* Performs the request and fetches result without fulfilling it, so that the response could be modified and then
* fulfilled.
*
* <p> **Usage**
* <pre>{@code
* page.route("https://dog.ceo/api/breeds/list/all", route -> {
* APIResponse response = route.fetch();
* JsonObject json = new Gson().fromJson(response.text(), JsonObject.class);
* JsonObject message = itemObj.get("json").getAsJsonObject();
* message.set("big_red_dog", new JsonArray());
* route.fulfill(new Route.FulfillOptions()
* .setResponse(response)
* .setBody(json.toString()));
* });
* }</pre>
*
* <p> **Details**
*
* <p> Note that {@code headers} option will apply to the fetched request as well as any redirects initiated by it. If you want
* to only apply {@code headers} to the original request, but not to redirects, look into {@link Route#resume
* Route.resume()} instead.
*
* @since v1.29
*/
APIResponse fetch(FetchOptions options);
/**
* Fulfills route's request with given response.
*
* <p> **Usage**
*
* <p> An example of fulfilling all requests with 404 responses:
* <pre>{@code
* page.route("**\/*", route -> {
@@ -416,6 +572,8 @@ public interface Route {
* page.route("**\/xhr_endpoint", route -> route.fulfill(
* new Route.FulfillOptions().setPath(Paths.get("mock_data.json"))));
* }</pre>
*
* @since v1.8
*/
default void fulfill() {
fulfill(null);
@@ -423,6 +581,8 @@ public interface Route {
/**
* Fulfills route's request with given response.
*
* <p> **Usage**
*
* <p> An example of fulfilling all requests with 404 responses:
* <pre>{@code
* page.route("**\/*", route -> {
@@ -438,10 +598,14 @@ public interface Route {
* page.route("**\/xhr_endpoint", route -> route.fulfill(
* new Route.FulfillOptions().setPath(Paths.get("mock_data.json"))));
* }</pre>
*
* @since v1.8
*/
void fulfill(FulfillOptions options);
/**
* A request to be routed.
*
* @since v1.8
*/
Request request();
}
@@ -20,21 +20,21 @@ import java.nio.file.Path;
/**
* Selectors can be used to install custom selector engines. See <a
* href="https://playwright.dev/java/docs/selectors">Working with selectors</a> for more information.
* href="https://playwright.dev/java/docs/extensibility">extensibility</a> for more information.
*/
public interface Selectors {
class RegisterOptions {
/**
* Whether to run this selector engine in isolated JavaScript environment. This environment has access to the same DOM, but
* not any JavaScript objects from the frame's scripts. Defaults to {@code false}. Note that running as a content script is not
* guaranteed when this engine is used together with other registered engines.
* not any JavaScript objects from the frame's scripts. Defaults to {@code false}. Note that running as a content script is
* not guaranteed when this engine is used together with other registered engines.
*/
public Boolean contentScript;
/**
* Whether to run this selector engine in isolated JavaScript environment. This environment has access to the same DOM, but
* not any JavaScript objects from the frame's scripts. Defaults to {@code false}. Note that running as a content script is not
* guaranteed when this engine is used together with other registered engines.
* not any JavaScript objects from the frame's scripts. Defaults to {@code false}. Note that running as a content script is
* not guaranteed when this engine is used together with other registered engines.
*/
public RegisterOptions setContentScript(boolean contentScript) {
this.contentScript = contentScript;
@@ -42,7 +42,11 @@ public interface Selectors {
}
}
/**
* An example of registering selector engine that queries elements based on a tag name:
* Selectors must be registered before creating the page.
*
* <p> **Usage**
*
* <p> An example of registering selector engine that queries elements based on a tag name:
* <pre>{@code
* // Script that evaluates to a selector engine instance. The script is evaluated in the page context.
* String createTagNameEngine = "{\n" +
@@ -62,22 +66,27 @@ public interface Selectors {
* page.setContent("<div><button>Click me</button></div>");
* // Use the selector prefixed with its name.
* Locator button = page.locator("tag=button");
* // Combine it with other selector engines.
* page.locator("tag=div >> text=\"Click me\"").click();
* // Combine it with built-in locators.
* page.locator("tag=div").getByText("Click me").click();
* // Can use it in any methods supporting selectors.
* int buttonCount = (int) page.locator("tag=button").count();
* browser.close();
* }</pre>
*
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May only
* contain {@code [a-zA-Z0-9_]} characters.
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May
* only contain {@code [a-zA-Z0-9_]} characters.
* @param script Script that evaluates to a selector engine instance. The script is evaluated in the page context.
* @since v1.8
*/
default void register(String name, String script) {
register(name, script, null);
}
/**
* An example of registering selector engine that queries elements based on a tag name:
* Selectors must be registered before creating the page.
*
* <p> **Usage**
*
* <p> An example of registering selector engine that queries elements based on a tag name:
* <pre>{@code
* // Script that evaluates to a selector engine instance. The script is evaluated in the page context.
* String createTagNameEngine = "{\n" +
@@ -97,20 +106,25 @@ public interface Selectors {
* page.setContent("<div><button>Click me</button></div>");
* // Use the selector prefixed with its name.
* Locator button = page.locator("tag=button");
* // Combine it with other selector engines.
* page.locator("tag=div >> text=\"Click me\"").click();
* // Combine it with built-in locators.
* page.locator("tag=div").getByText("Click me").click();
* // Can use it in any methods supporting selectors.
* int buttonCount = (int) page.locator("tag=button").count();
* browser.close();
* }</pre>
*
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May only
* contain {@code [a-zA-Z0-9_]} characters.
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May
* only contain {@code [a-zA-Z0-9_]} characters.
* @param script Script that evaluates to a selector engine instance. The script is evaluated in the page context.
* @since v1.8
*/
void register(String name, String script, RegisterOptions options);
/**
* An example of registering selector engine that queries elements based on a tag name:
* Selectors must be registered before creating the page.
*
* <p> **Usage**
*
* <p> An example of registering selector engine that queries elements based on a tag name:
* <pre>{@code
* // Script that evaluates to a selector engine instance. The script is evaluated in the page context.
* String createTagNameEngine = "{\n" +
@@ -130,22 +144,27 @@ public interface Selectors {
* page.setContent("<div><button>Click me</button></div>");
* // Use the selector prefixed with its name.
* Locator button = page.locator("tag=button");
* // Combine it with other selector engines.
* page.locator("tag=div >> text=\"Click me\"").click();
* // Combine it with built-in locators.
* page.locator("tag=div").getByText("Click me").click();
* // Can use it in any methods supporting selectors.
* int buttonCount = (int) page.locator("tag=button").count();
* browser.close();
* }</pre>
*
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May only
* contain {@code [a-zA-Z0-9_]} characters.
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May
* only contain {@code [a-zA-Z0-9_]} characters.
* @param script Script that evaluates to a selector engine instance. The script is evaluated in the page context.
* @since v1.8
*/
default void register(String name, Path script) {
register(name, script, null);
}
/**
* An example of registering selector engine that queries elements based on a tag name:
* Selectors must be registered before creating the page.
*
* <p> **Usage**
*
* <p> An example of registering selector engine that queries elements based on a tag name:
* <pre>{@code
* // Script that evaluates to a selector engine instance. The script is evaluated in the page context.
* String createTagNameEngine = "{\n" +
@@ -165,16 +184,17 @@ public interface Selectors {
* page.setContent("<div><button>Click me</button></div>");
* // Use the selector prefixed with its name.
* Locator button = page.locator("tag=button");
* // Combine it with other selector engines.
* page.locator("tag=div >> text=\"Click me\"").click();
* // Combine it with built-in locators.
* page.locator("tag=div").getByText("Click me").click();
* // Can use it in any methods supporting selectors.
* int buttonCount = (int) page.locator("tag=button").count();
* browser.close();
* }</pre>
*
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May only
* contain {@code [a-zA-Z0-9_]} characters.
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May
* only contain {@code [a-zA-Z0-9_]} characters.
* @param script Script that evaluates to a selector engine instance. The script is evaluated in the page context.
* @since v1.8
*/
void register(String name, Path script, RegisterOptions options);
/**
@@ -182,6 +202,7 @@ public interface Selectors {
* default.
*
* @param attributeName Test id attribute name.
* @since v1.27
*/
void setTestIdAttribute(String attributeName);
}
@@ -24,6 +24,10 @@ package com.microsoft.playwright;
public interface Touchscreen {
/**
* Dispatches a {@code touchstart} and {@code touchend} event with a single touch at the position ({@code x},{@code y}).
*
* <p> <strong>NOTE:</strong> {@link Page#tap Page.tap()} the method will throw if {@code hasTouch} option of the browser context is false.
*
* @since v1.8
*/
void tap(double x, double y);
}
@@ -38,8 +38,8 @@ import java.nio.file.Path;
public interface Tracing {
class StartOptions {
/**
* If specified, the trace is going to be saved into the file with the given name inside the {@code tracesDir} folder specified
* in {@link BrowserType#launch BrowserType.launch()}.
* If specified, the trace is going to be saved into the file with the given name inside the {@code tracesDir} folder
* specified in {@link BrowserType#launch BrowserType.launch()}.
*/
public String name;
/**
@@ -56,8 +56,8 @@ public interface Tracing {
public Boolean snapshots;
/**
* Whether to include source files for trace actions. List of the directories with source code for the application must be
* provided via {@code PLAYWRIGHT_JAVA_SRC} environment variable (the paths should be separated by ';' on Windows and by ':' on
* other platforms).
* provided via {@code PLAYWRIGHT_JAVA_SRC} environment variable (the paths should be separated by ';' on Windows and by
* ':' on other platforms).
*/
public Boolean sources;
/**
@@ -66,8 +66,8 @@ public interface Tracing {
public String title;
/**
* If specified, the trace is going to be saved into the file with the given name inside the {@code tracesDir} folder specified
* in {@link BrowserType#launch BrowserType.launch()}.
* If specified, the trace is going to be saved into the file with the given name inside the {@code tracesDir} folder
* specified in {@link BrowserType#launch BrowserType.launch()}.
*/
public StartOptions setName(String name) {
this.name = name;
@@ -93,8 +93,8 @@ public interface Tracing {
}
/**
* Whether to include source files for trace actions. List of the directories with source code for the application must be
* provided via {@code PLAYWRIGHT_JAVA_SRC} environment variable (the paths should be separated by ';' on Windows and by ':' on
* other platforms).
* provided via {@code PLAYWRIGHT_JAVA_SRC} environment variable (the paths should be separated by ';' on Windows and by
* ':' on other platforms).
*/
public StartOptions setSources(boolean sources) {
this.sources = sources;
@@ -154,6 +154,8 @@ public interface Tracing {
}
/**
* Start tracing.
*
* <p> **Usage**
* <pre>{@code
* context.tracing().start(new Tracing.StartOptions()
* .setScreenshots(true)
@@ -163,12 +165,16 @@ public interface Tracing {
* context.tracing().stop(new Tracing.StopOptions()
* .setPath(Paths.get("trace.zip")));
* }</pre>
*
* @since v1.12
*/
default void start() {
start(null);
}
/**
* Start tracing.
*
* <p> **Usage**
* <pre>{@code
* context.tracing().start(new Tracing.StartOptions()
* .setScreenshots(true)
@@ -178,12 +184,16 @@ public interface Tracing {
* context.tracing().stop(new Tracing.StopOptions()
* .setPath(Paths.get("trace.zip")));
* }</pre>
*
* @since v1.12
*/
void start(StartOptions options);
/**
* Start a new trace chunk. If you'd like to record multiple traces on the same {@code BrowserContext}, use {@link Tracing#start
* Tracing.start()} once, and then create multiple trace chunks with {@link Tracing#startChunk Tracing.startChunk()} and
* {@link Tracing#stopChunk Tracing.stopChunk()}.
* Start a new trace chunk. If you'd like to record multiple traces on the same {@code BrowserContext}, use {@link
* Tracing#start Tracing.start()} once, and then create multiple trace chunks with {@link Tracing#startChunk
* Tracing.startChunk()} and {@link Tracing#stopChunk Tracing.stopChunk()}.
*
* <p> **Usage**
* <pre>{@code
* context.tracing().start(new Tracing.StartOptions()
* .setScreenshots(true)
@@ -203,14 +213,18 @@ public interface Tracing {
* context.tracing().stopChunk(new Tracing.StopChunkOptions()
* .setPath(Paths.get("trace2.zip")));
* }</pre>
*
* @since v1.15
*/
default void startChunk() {
startChunk(null);
}
/**
* Start a new trace chunk. If you'd like to record multiple traces on the same {@code BrowserContext}, use {@link Tracing#start
* Tracing.start()} once, and then create multiple trace chunks with {@link Tracing#startChunk Tracing.startChunk()} and
* {@link Tracing#stopChunk Tracing.stopChunk()}.
* Start a new trace chunk. If you'd like to record multiple traces on the same {@code BrowserContext}, use {@link
* Tracing#start Tracing.start()} once, and then create multiple trace chunks with {@link Tracing#startChunk
* Tracing.startChunk()} and {@link Tracing#stopChunk Tracing.stopChunk()}.
*
* <p> **Usage**
* <pre>{@code
* context.tracing().start(new Tracing.StartOptions()
* .setScreenshots(true)
@@ -230,26 +244,36 @@ public interface Tracing {
* context.tracing().stopChunk(new Tracing.StopChunkOptions()
* .setPath(Paths.get("trace2.zip")));
* }</pre>
*
* @since v1.15
*/
void startChunk(StartChunkOptions options);
/**
* Stop tracing.
*
* @since v1.12
*/
default void stop() {
stop(null);
}
/**
* Stop tracing.
*
* @since v1.12
*/
void stop(StopOptions options);
/**
* Stop the trace chunk. See {@link Tracing#startChunk Tracing.startChunk()} for more details about multiple trace chunks.
*
* @since v1.15
*/
default void stopChunk() {
stopChunk(null);
}
/**
* Stop the trace chunk. See {@link Tracing#startChunk Tracing.startChunk()} for more details about multiple trace chunks.
*
* @since v1.15
*/
void stopChunk(StopChunkOptions options);
}
@@ -27,11 +27,15 @@ import java.nio.file.Path;
public interface Video {
/**
* Deletes the video file. Will wait for the video to finish if necessary.
*
* @since v1.11
*/
void delete();
/**
* Returns the file system path this video will be recorded to. The video is guaranteed to be written to the filesystem
* upon closing the browser context. This method throws when connected remotely.
*
* @since v1.8
*/
Path path();
/**
@@ -39,6 +43,7 @@ public interface Video {
* the page has closed. This method waits until the page is closed and the video is fully saved.
*
* @param path Path where the video should be saved.
* @since v1.11
*/
void saveAs(Path path);
}
@@ -66,8 +66,8 @@ public interface WebSocket {
*/
public Predicate<WebSocketFrame> predicate;
/**
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
* value can be changed by using the {@link BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()}.
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The
* default value can be changed by using the {@link BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()}.
*/
public Double timeout;
@@ -79,8 +79,8 @@ public interface WebSocket {
return this;
}
/**
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
* value can be changed by using the {@link BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()}.
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The
* default value can be changed by using the {@link BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()}.
*/
public WaitForFrameReceivedOptions setTimeout(double timeout) {
this.timeout = timeout;
@@ -93,8 +93,8 @@ public interface WebSocket {
*/
public Predicate<WebSocketFrame> predicate;
/**
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
* value can be changed by using the {@link BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()}.
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The
* default value can be changed by using the {@link BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()}.
*/
public Double timeout;
@@ -106,8 +106,8 @@ public interface WebSocket {
return this;
}
/**
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
* value can be changed by using the {@link BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()}.
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The
* default value can be changed by using the {@link BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()}.
*/
public WaitForFrameSentOptions setTimeout(double timeout) {
this.timeout = timeout;
@@ -116,46 +116,54 @@ public interface WebSocket {
}
/**
* Indicates that the web socket has been closed.
*
* @since v1.8
*/
boolean isClosed();
/**
* Contains the URL of the WebSocket.
*
* @since v1.8
*/
String url();
/**
* Performs action and waits for a frame to be sent. If predicate is provided, it passes {@code WebSocketFrame} value into the
* {@code predicate} function and waits for {@code predicate(webSocketFrame)} to return a truthy value. Will throw an error if the
* WebSocket or Page is closed before the frame is received.
* Performs action and waits for a frame to be sent. If predicate is provided, it passes {@code WebSocketFrame} value into
* the {@code predicate} function and waits for {@code predicate(webSocketFrame)} to return a truthy value. Will throw an
* error if the WebSocket or Page is closed before the frame is received.
*
* @param callback Callback that performs the action triggering the event.
* @since v1.10
*/
default WebSocketFrame waitForFrameReceived(Runnable callback) {
return waitForFrameReceived(null, callback);
}
/**
* Performs action and waits for a frame to be sent. If predicate is provided, it passes {@code WebSocketFrame} value into the
* {@code predicate} function and waits for {@code predicate(webSocketFrame)} to return a truthy value. Will throw an error if the
* WebSocket or Page is closed before the frame is received.
* Performs action and waits for a frame to be sent. If predicate is provided, it passes {@code WebSocketFrame} value into
* the {@code predicate} function and waits for {@code predicate(webSocketFrame)} to return a truthy value. Will throw an
* error if the WebSocket or Page is closed before the frame is received.
*
* @param callback Callback that performs the action triggering the event.
* @since v1.10
*/
WebSocketFrame waitForFrameReceived(WaitForFrameReceivedOptions options, Runnable callback);
/**
* Performs action and waits for a frame to be sent. If predicate is provided, it passes {@code WebSocketFrame} value into the
* {@code predicate} function and waits for {@code predicate(webSocketFrame)} to return a truthy value. Will throw an error if the
* WebSocket or Page is closed before the frame is sent.
* Performs action and waits for a frame to be sent. If predicate is provided, it passes {@code WebSocketFrame} value into
* the {@code predicate} function and waits for {@code predicate(webSocketFrame)} to return a truthy value. Will throw an
* error if the WebSocket or Page is closed before the frame is sent.
*
* @param callback Callback that performs the action triggering the event.
* @since v1.10
*/
default WebSocketFrame waitForFrameSent(Runnable callback) {
return waitForFrameSent(null, callback);
}
/**
* Performs action and waits for a frame to be sent. If predicate is provided, it passes {@code WebSocketFrame} value into the
* {@code predicate} function and waits for {@code predicate(webSocketFrame)} to return a truthy value. Will throw an error if the
* WebSocket or Page is closed before the frame is sent.
* Performs action and waits for a frame to be sent. If predicate is provided, it passes {@code WebSocketFrame} value into
* the {@code predicate} function and waits for {@code predicate(webSocketFrame)} to return a truthy value. Will throw an
* error if the WebSocket or Page is closed before the frame is sent.
*
* @param callback Callback that performs the action triggering the event.
* @since v1.10
*/
WebSocketFrame waitForFrameSent(WaitForFrameSentOptions options, Runnable callback);
}
@@ -18,17 +18,21 @@ package com.microsoft.playwright;
/**
* The {@code WebSocketFrame} class represents frames sent over {@code WebSocket} connections in the page. Frame payload is returned by
* either {@link WebSocketFrame#text WebSocketFrame.text()} or {@link WebSocketFrame#binary WebSocketFrame.binary()} method
* depending on the its type.
* The {@code WebSocketFrame} class represents frames sent over {@code WebSocket} connections in the page. Frame payload is
* returned by either {@link WebSocketFrame#text WebSocketFrame.text()} or {@link WebSocketFrame#binary
* WebSocketFrame.binary()} method depending on the its type.
*/
public interface WebSocketFrame {
/**
* Returns binary payload.
*
* @since v1.9
*/
byte[] binary();
/**
* Returns text payload.
*
* @since v1.9
*/
String text();
}
@@ -20,8 +20,8 @@ import java.util.function.Consumer;
/**
* The Worker class represents a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API">WebWorker</a>.
* {@code worker} event is emitted on the page object to signal a worker creation. {@code close} event is emitted on the worker object
* when the worker is gone.
* {@code worker} event is emitted on the page object to signal a worker creation. {@code close} event is emitted on the
* worker object when the worker is gone.
* <pre>{@code
* page.onWorker(worker -> {
* System.out.println("Worker created: " + worker.url());
@@ -46,14 +46,14 @@ public interface Worker {
class WaitForCloseOptions {
/**
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
* value can be changed by using the {@link BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()}.
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The
* default value can be changed by using the {@link BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()}.
*/
public Double timeout;
/**
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
* value can be changed by using the {@link BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()}.
* Maximum time to wait for in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The
* default value can be changed by using the {@link BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()}.
*/
public WaitForCloseOptions setTimeout(double timeout) {
this.timeout = timeout;
@@ -68,11 +68,12 @@ public interface Worker {
* Worker#evaluate Worker.evaluate()} would wait for the promise to resolve and return its value.
*
* <p> If the function passed to the {@link Worker#evaluate Worker.evaluate()} returns a non-[Serializable] value, then {@link
* 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}.
* 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 the expression evaluates to a function, the function is
* automatically invoked.
* @since v1.8
*/
default Object evaluate(String expression) {
return evaluate(expression, null);
@@ -85,12 +86,13 @@ public interface Worker {
* Worker#evaluate Worker.evaluate()} would wait for the promise to resolve and return its value.
*
* <p> If the function passed to the {@link Worker#evaluate Worker.evaluate()} returns a non-[Serializable] value, then {@link
* 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}.
* 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 the expression evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
* @since v1.8
*/
Object evaluate(String expression, Object arg);
/**
@@ -105,6 +107,7 @@ public interface Worker {
*
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
* automatically invoked.
* @since v1.8
*/
default JSHandle evaluateHandle(String expression) {
return evaluateHandle(expression, null);
@@ -122,13 +125,20 @@ public interface Worker {
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
* automatically invoked.
* @param arg Optional argument to pass to {@code expression}.
* @since v1.8
*/
JSHandle evaluateHandle(String expression, Object arg);
/**
*
*
* @since v1.8
*/
String url();
/**
* Performs action and waits for the Worker to close.
*
* @param callback Callback that performs the action triggering the event.
* @since v1.10
*/
default Worker waitForClose(Runnable callback) {
return waitForClose(null, callback);
@@ -137,6 +147,7 @@ public interface Worker {
* Performs action and waits for the Worker to close.
*
* @param callback Callback that performs the action triggering the event.
* @since v1.10
*/
Worker waitForClose(WaitForCloseOptions options, Runnable callback);
}
@@ -18,9 +18,8 @@ package com.microsoft.playwright.assertions;
/**
* The {@code APIResponseAssertions} class provides assertion methods that can be used to make assertions about the {@code APIResponse}
* in the tests. A new instance of {@code APIResponseAssertions} is created by calling {@link PlaywrightAssertions#assertThat
* PlaywrightAssertions.assertThat()}:
* The {@code APIResponseAssertions} class provides assertion methods that can be used to make assertions about the {@code
* APIResponse} in the tests.
* <pre>{@code
* ...
* import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
@@ -43,13 +42,19 @@ public interface APIResponseAssertions {
* <pre>{@code
* assertThat(response).not().isOK();
* }</pre>
*
* @since v1.20
*/
APIResponseAssertions not();
/**
* Ensures the response status code is within {@code 200..299} range.
*
* <p> **Usage**
* <pre>{@code
* assertThat(response).isOK();
* }</pre>
*
* @since v1.18
*/
void isOK();
}
File diff suppressed because it is too large Load Diff
@@ -19,9 +19,8 @@ package com.microsoft.playwright.assertions;
import java.util.regex.Pattern;
/**
* The {@code PageAssertions} class provides assertion methods that can be used to make assertions about the {@code Page} state in the
* tests. A new instance of {@code PageAssertions} is created by calling {@link PlaywrightAssertions#assertThat
* PlaywrightAssertions.assertThat()}:
* The {@code PageAssertions} class provides assertion methods that can be used to make assertions about the {@code Page}
* state in the tests.
* <pre>{@code
* ...
* import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
@@ -72,86 +71,112 @@ public interface PageAssertions {
* <pre>{@code
* assertThat(page).not().hasURL("error");
* }</pre>
*
* @since v1.20
*/
PageAssertions not();
/**
* Ensures the page has the given title.
*
* <p> **Usage**
* <pre>{@code
* assertThat(page).hasTitle("Playwright");
* }</pre>
*
* @param titleOrRegExp Expected title or RegExp.
* @since v1.20
*/
default void hasTitle(String titleOrRegExp) {
hasTitle(titleOrRegExp, null);
}
/**
* Ensures the page has the given title.
*
* <p> **Usage**
* <pre>{@code
* assertThat(page).hasTitle("Playwright");
* }</pre>
*
* @param titleOrRegExp Expected title or RegExp.
* @since v1.20
*/
void hasTitle(String titleOrRegExp, HasTitleOptions options);
/**
* Ensures the page has the given title.
*
* <p> **Usage**
* <pre>{@code
* assertThat(page).hasTitle("Playwright");
* }</pre>
*
* @param titleOrRegExp Expected title or RegExp.
* @since v1.20
*/
default void hasTitle(Pattern titleOrRegExp) {
hasTitle(titleOrRegExp, null);
}
/**
* Ensures the page has the given title.
*
* <p> **Usage**
* <pre>{@code
* assertThat(page).hasTitle("Playwright");
* }</pre>
*
* @param titleOrRegExp Expected title or RegExp.
* @since v1.20
*/
void hasTitle(Pattern titleOrRegExp, HasTitleOptions options);
/**
* Ensures the page is navigated to the given URL.
*
* <p> **Usage**
* <pre>{@code
* assertThat(page).hasURL(".com");
* }</pre>
*
* @param urlOrRegExp Expected URL string or RegExp.
* @since v1.20
*/
default void hasURL(String urlOrRegExp) {
hasURL(urlOrRegExp, null);
}
/**
* Ensures the page is navigated to the given URL.
*
* <p> **Usage**
* <pre>{@code
* assertThat(page).hasURL(".com");
* }</pre>
*
* @param urlOrRegExp Expected URL string or RegExp.
* @since v1.20
*/
void hasURL(String urlOrRegExp, HasURLOptions options);
/**
* Ensures the page is navigated to the given URL.
*
* <p> **Usage**
* <pre>{@code
* assertThat(page).hasURL(".com");
* }</pre>
*
* @param urlOrRegExp Expected URL string or RegExp.
* @since v1.20
*/
default void hasURL(Pattern urlOrRegExp) {
hasURL(urlOrRegExp, null);
}
/**
* Ensures the page is navigated to the given URL.
*
* <p> **Usage**
* <pre>{@code
* assertThat(page).hasURL(".com");
* }</pre>
*
* @param urlOrRegExp Expected URL string or RegExp.
* @since v1.20
*/
void hasURL(Pattern urlOrRegExp, HasURLOptions options);
}
@@ -44,20 +44,23 @@ import com.microsoft.playwright.impl.PageAssertionsImpl;
* }
* }</pre>
*
* <p> Playwright will be re-testing the node with the selector {@code .status} until fetched Node has the {@code "Submitted"} text. It
* will be re-fetching the node and checking it over and over, until the condition is met or until the timeout is reached.
* You can pass this timeout as an option.
* <p> Playwright will be re-testing the node with the selector {@code .status} until fetched Node has the {@code "Submitted"}
* text. It will be re-fetching the node and checking it over and over, until the condition is met or until the timeout is
* reached. You can pass this timeout as an option.
*
* <p> By default, the timeout for assertions is set to 5 seconds.
*/
public interface PlaywrightAssertions {
/**
* Creates a {@code APIResponseAssertions} object for the given {@code APIResponse}.
*
* <p> **Usage**
* <pre>{@code
* PlaywrightAssertions.assertThat(response).isOK();
* }</pre>
*
* @param response {@code APIResponse} object to use for assertions.
* @since v1.18
*/
static APIResponseAssertions assertThat(APIResponse response) {
return new APIResponseAssertionsImpl(response);
@@ -65,11 +68,14 @@ public interface PlaywrightAssertions {
/**
* Creates a {@code LocatorAssertions} object for the given {@code Locator}.
*
* <p> **Usage**
* <pre>{@code
* PlaywrightAssertions.assertThat(locator).isVisible();
* }</pre>
*
* @param locator {@code Locator} object to use for assertions.
* @since v1.18
*/
static LocatorAssertions assertThat(Locator locator) {
return new LocatorAssertionsImpl(locator);
@@ -77,11 +83,14 @@ public interface PlaywrightAssertions {
/**
* Creates a {@code PageAssertions} object for the given {@code Page}.
*
* <p> **Usage**
* <pre>{@code
* PlaywrightAssertions.assertThat(page).hasTitle("News");
* }</pre>
*
* @param page {@code Page} object to use for assertions.
* @since v1.18
*/
static PageAssertions assertThat(Page page) {
return new PageAssertionsImpl(page);
@@ -89,11 +98,14 @@ public interface PlaywrightAssertions {
/**
* Changes default timeout for Playwright assertions from 5 seconds to the specified value.
*
* <p> **Usage**
* <pre>{@code
* PlaywrightAssertions.setDefaultAssertionTimeout(30_000);
* }</pre>
*
* @param timeout Timeout in milliseconds.
* @since v1.25
*/
static void setDefaultAssertionTimeout(double milliseconds) {
AssertionsTimeout.setDefaultTimeout(milliseconds);
@@ -399,11 +399,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
private void route(UrlMatcher matcher, Consumer<Route> handler, RouteOptions options) {
withLogging("BrowserContext.route", () -> {
routes.add(matcher, handler, options == null ? null : options.times);
if (routes.size() == 1) {
JsonObject params = new JsonObject();
params.addProperty("enabled", true);
sendMessage("setNetworkInterceptionEnabled", params);
}
updateInterceptionPatterns();
});
}
@@ -525,30 +521,26 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
private void unroute(UrlMatcher matcher, Consumer<Route> handler) {
withLogging("BrowserContext.unroute", () -> {
routes.remove(matcher, handler);
maybeDisableNetworkInterception();
updateInterceptionPatterns();
});
}
private void maybeDisableNetworkInterception() {
if (routes.size() == 0) {
JsonObject params = new JsonObject();
params.addProperty("enabled", false);
sendMessage("setNetworkInterceptionEnabled", params);
}
private void updateInterceptionPatterns() {
sendMessage("setNetworkInterceptionPatterns", routes.interceptionPatterns());
}
void handleRoute(RouteImpl route) {
Router.HandleResult handled = routes.handle(route);
if (handled == Router.HandleResult.FoundMatchingHandler) {
maybeDisableNetworkInterception();
if (handled != Router.HandleResult.NoMatchingHandler) {
updateInterceptionPatterns();
}
if (!route.isHandled()){
if (handled == Router.HandleResult.NoMatchingHandler || handled == Router.HandleResult.Fallback) {
route.resume();
}
}
void pause() {
sendMessage("pause");
WaitableResult<JsonElement> pause() {
return sendMessageAsync("pause", new JsonObject());
}
@Override
@@ -320,6 +320,8 @@ public class Connection {
case "Selectors":
result = new SelectorsImpl(parent, type, guid, initializer);
break;
case "SocksSupport":
break;
case "Tracing":
result = new TracingImpl(parent, type, guid, initializer);
break;
@@ -375,11 +375,14 @@ public class ElementHandleImpl extends JSHandleImpl implements ElementHandle {
@Override
public List<String> selectOption(String[] values, SelectOptionOptions options) {
if (values == null) {
return selectOption(new SelectOption[0], options);
if (options == null) {
options = new SelectOptionOptions();
}
return selectOption(Arrays.asList(values).stream().map(
v -> new SelectOption().setValue(v)).toArray(SelectOption[]::new), options);
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
if (values != null) {
params.add("options", toSelectValueOrLabel(values));
}
return selectOption(params);
}
@Override
@@ -110,11 +110,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
@Override
public List<String> selectOption(String selector, String[] values, SelectOptionOptions options) {
if (values == null) {
return selectOption(selector, new SelectOption[0], options);
}
return selectOption(selector, Arrays.asList(values).stream().map(
v -> new SelectOption().setValue(v)).toArray(SelectOption[]::new), options);
return withLogging("Frame.selectOption", () -> selectOptionImpl(selector, values, options));
}
@Override
@@ -414,6 +410,11 @@ public class FrameImpl extends ChannelOwner implements Frame {
return locator(getByTestIdSelector(testId));
}
@Override
public Locator getByTestId(Pattern testId) {
return locator(getByTestIdSelector(testId));
}
@Override
public Locator getByText(String text, GetByTextOptions options) {
return locator(getByTextSelector(text, convertType(options, Locator.GetByTextOptions.class)));
@@ -688,6 +689,18 @@ public class FrameImpl extends ChannelOwner implements Frame {
return selectOption(params);
}
List<String> selectOptionImpl(String selector, String[] values, SelectOptionOptions options) {
if (options == null) {
options = new SelectOptionOptions();
}
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
params.addProperty("selector", selector);
if (values != null) {
params.add("options", toSelectValueOrLabel(values));
}
return selectOption(params);
}
@Override
public List<String> selectOption(String selector, ElementHandle[] values, SelectOptionOptions options) {
return withLogging("Frame.selectOption", () -> selectOptionImpl(selector, values, options));
@@ -84,6 +84,11 @@ class FrameLocatorImpl implements FrameLocator {
return locator(getByTestIdSelector(testId));
}
@Override
public Locator getByTestId(Pattern testId) {
return locator(getByTestIdSelector(testId));
}
@Override
public Locator getByText(String text, GetByTextOptions options) {
return locator(getByTextSelector(text, convertType(options, Locator.GetByTextOptions.class)));
@@ -148,7 +148,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
options = new HasCountOptions();
}
FrameExpectOptions commonOptions = convertType(options, FrameExpectOptions.class);
commonOptions.expectedNumber = count;
commonOptions.expectedNumber = (double) count;
List<ExpectedTextValue> expectedText = null;
expectImpl("to.have.count", expectedText, count, "Locator expected to have count", commonOptions);
}
@@ -326,6 +326,15 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
expectTrue("to.be.hidden", "Locator expected to be hidden", convertType(options, FrameExpectOptions.class));
}
@Override
public void isInViewport(IsInViewportOptions options) {
FrameExpectOptions expectOptions = convertType(options, FrameExpectOptions.class);
if (options != null && options.ratio != null) {
expectOptions.expectedNumber = options.ratio;
}
expectTrue("to.be.in.viewport", "Locator expected to be in viewport", expectOptions);
}
@Override
public void isVisible(IsVisibleOptions options) {
FrameExpectOptions frameOptions = convertType(options, FrameExpectOptions.class);
@@ -7,6 +7,7 @@ import com.microsoft.playwright.options.*;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -61,6 +62,16 @@ class LocatorImpl implements Locator {
}
}
@Override
public List<Locator> all() {
List<Locator> result = new ArrayList<>();
int count = this.count();
for (int i = 0; i < count; i++) {
result.add(nth(i));
}
return result;
}
@Override
public List<String> allInnerTexts() {
return (List<String>) frame.evalOnSelectorAll(selector, "ee => ee.map(e => e.innerText)");
@@ -245,7 +256,7 @@ class LocatorImpl implements Locator {
@Override
public Locator getByRole(AriaRole role, GetByRoleOptions options) {
return null;
return locator(getByRoleSelector(role, options));
}
@Override
@@ -253,6 +264,11 @@ class LocatorImpl implements Locator {
return locator(getByTestIdSelector(testId));
}
@Override
public Locator getByTestId(Pattern testId) {
return locator(getByTestIdSelector(testId));
}
@Override
public Locator getByText(String text, GetByTextOptions options) {
return locator(getByTextSelector(text, options));
@@ -31,7 +31,7 @@ public class LocatorUtils {
return "internal:attr=[" + attrName + "=" + escapeForAttributeSelector((String) value, exact) + "]";
}
static String getByTestIdSelector(String testId) {
static String getByTestIdSelector(Object testId) {
return getByAttributeTextSelector(testIdAttributeName, testId, true);
}
@@ -118,7 +118,7 @@ public class LocatorUtils {
// cssEscape(value).replace(/\\ /g, ' ')
// However, our attribute selectors do not conform to CSS parsing spec,
// so we escape them differently.
return '"' + value.replaceAll("\"", "\\\\\"") + '"' + (exact ? "" : "i");
return '"' + value.replaceAll("\\\\", "\\\\\\\\").replaceAll("\"", "\\\\\"") + '"' + (exact ? "" : "i");
}
private static String toJsRegExp(Pattern pattern) {
@@ -17,6 +17,7 @@
package com.microsoft.playwright.impl;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.microsoft.playwright.*;
import com.microsoft.playwright.options.*;
@@ -29,8 +30,7 @@ import java.util.function.Predicate;
import java.util.regex.Pattern;
import static com.microsoft.playwright.impl.Serialization.gson;
import static com.microsoft.playwright.impl.Utils.convertType;
import static com.microsoft.playwright.impl.Utils.isSafeCloseError;
import static com.microsoft.playwright.impl.Utils.*;
import static com.microsoft.playwright.options.ScreenshotType.JPEG;
import static com.microsoft.playwright.options.ScreenshotType.PNG;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -188,10 +188,10 @@ public class PageImpl extends ChannelOwner implements Page {
} else if ("route".equals(event)) {
RouteImpl route = connection.getExistingObject(params.getAsJsonObject("route").get("guid").getAsString());
Router.HandleResult handled = routes.handle(route);
if (handled == Router.HandleResult.FoundMatchingHandler) {
maybeDisableNetworkInterception();
if (handled != Router.HandleResult.NoMatchingHandler) {
updateInterceptionPatterns();
}
if (!route.isHandled()) {
if (handled == Router.HandleResult.NoMatchingHandler || handled == Router.HandleResult.Fallback) {
browserContext.handleRoute(route);
}
} else if ("video".equals(event)) {
@@ -782,6 +782,11 @@ public class PageImpl extends ChannelOwner implements Page {
return withLogging("Page.getByTestId", () -> mainFrame.getByTestId(testId));
}
@Override
public Locator getByTestId(Pattern testId) {
return withLogging("Page.getByTestId", () -> mainFrame.getByTestId(testId));
}
@Override
public Locator getByText(String text, GetByTextOptions options) {
return withLogging("Page.getByText",
@@ -944,8 +949,8 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public void pause() {
withLogging("BrowserContext.pause", () -> {
context().pause();
withLogging("Page.pause", () -> {
runUntil(() -> {}, new WaitableRace<>(asList(context().pause(), (Waitable<JsonElement>) waitableClosedOrCrashed)));
});
}
@@ -1032,11 +1037,7 @@ public class PageImpl extends ChannelOwner implements Page {
private void route(UrlMatcher matcher, Consumer<Route> handler, RouteOptions options) {
withLogging("Page.route", () -> {
routes.add(matcher, handler, options == null ? null : options.times);
if (routes.size() == 1) {
JsonObject params = new JsonObject();
params.addProperty("enabled", true);
sendMessage("setNetworkInterceptionEnabled", params);
}
updateInterceptionPatterns();
});
}
@@ -1045,8 +1046,6 @@ public class PageImpl extends ChannelOwner implements Page {
return withLogging("Page.screenshot", () -> screenshotImpl(options));
}
@Override
public List<String> selectOption(String selector, String value, SelectOptionOptions options) {
String[] values = value == null ? null : new String[]{ value };
@@ -1061,11 +1060,8 @@ public class PageImpl extends ChannelOwner implements Page {
@Override
public List<String> selectOption(String selector, String[] values, SelectOptionOptions options) {
if (values == null) {
return selectOption(selector, new SelectOption[0], options);
}
return selectOption(selector, Arrays.asList(values).stream().map(
v -> new SelectOption().setValue(v)).toArray(SelectOption[]::new), options);
return withLogging("Page.selectOption",
() -> mainFrame.selectOptionImpl(selector, values, convertType(options, Frame.SelectOptionOptions.class)));
}
@Override
@@ -1256,16 +1252,12 @@ public class PageImpl extends ChannelOwner implements Page {
private void unroute(UrlMatcher matcher, Consumer<Route> handler) {
withLogging("Page.unroute", () -> {
routes.remove(matcher, handler);
maybeDisableNetworkInterception();
updateInterceptionPatterns();
});
}
private void maybeDisableNetworkInterception() {
if (routes.size() == 0) {
JsonObject params = new JsonObject();
params.addProperty("enabled", false);
sendMessage("setNetworkInterceptionEnabled", params);
}
private void updateInterceptionPatterns() {
sendMessage("setNetworkInterceptionPatterns", routes.interceptionPatterns());
}
@Override
@@ -94,7 +94,7 @@ class ExpectedTextValue {
class FrameExpectOptions {
Object expressionArg;
List<ExpectedTextValue> expectedText;
Integer expectedNumber;
Double expectedNumber;
SerializedArgument expectedValue;
Boolean useInnerText;
boolean isNot;
@@ -17,9 +17,8 @@
package com.microsoft.playwright.impl;
import com.google.gson.JsonObject;
import com.microsoft.playwright.Frame;
import com.microsoft.playwright.PlaywrightException;
import com.microsoft.playwright.Route;
import com.microsoft.playwright.*;
import com.microsoft.playwright.options.RequestOptions;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@@ -34,6 +33,9 @@ public class RouteImpl extends ChannelOwner implements Route {
private final RequestImpl request;
private boolean handled;
boolean fallbackCalled;
boolean shouldResumeIfFallbackIsCalled;
public RouteImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
super(parent, type, guid, initializer);
request = connection.getExistingObject(initializer.getAsJsonObject("request").get("guid").getAsString());
@@ -62,12 +64,38 @@ public class RouteImpl extends ChannelOwner implements Route {
@Override
public void fallback(FallbackOptions options) {
fallbackCalled = true;
if (handled) {
throw new PlaywrightException("Route is already handled!");
}
applyOverrides(options);
if (shouldResumeIfFallbackIsCalled) {
resume();
}
}
@Override
public APIResponse fetch(FetchOptions fetchOptions) {
RequestOptionsImpl options = convertType(fetchOptions, RequestOptionsImpl.class);
if (options == null) {
options = new RequestOptionsImpl();
}
if (options.method == null) {
options.method = request.method();
}
if (options.headers == null) {
options.headers = request.headers();
}
if (fetchOptions != null && fetchOptions.postData != null) {
options.data = fetchOptions.postData;
} else {
options.data = request.postDataBuffer();
}
APIRequestContextImpl apiRequest = request.frame().page().context().request();
String url = (fetchOptions == null || fetchOptions.url == null) ? request().url() : fetchOptions.url;
return apiRequest.fetch(url, options);
}
private void applyOverrides(FallbackOptions options) {
if (options == null) {
return;
@@ -16,14 +16,19 @@
package com.microsoft.playwright.impl;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.microsoft.playwright.Route;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
class Router {
private List<RouteInfo> routes = new ArrayList<>();
@@ -65,7 +70,7 @@ class Router {
return routes.size();
}
enum HandleResult { NoMatchingHandler, FoundMatchingHandler}
enum HandleResult { NoMatchingHandler, Handled, Fallback, PendingHandler }
HandleResult handle(RouteImpl route) {
HandleResult result = HandleResult.NoMatchingHandler;
for (Iterator<RouteInfo> it = routes.iterator(); it.hasNext();) {
@@ -76,12 +81,45 @@ class Router {
if (info.decrementRemainingCallCount()) {
it.remove();
}
result = HandleResult.FoundMatchingHandler;
route.fallbackCalled = false;
info.handle(route);
if (route.isHandled()) {
break;
return HandleResult.Handled;
}
// Not immediately handled and fallback() was not called => the route
// must be handled asynchronously.
if (!route.fallbackCalled) {
route.shouldResumeIfFallbackIsCalled = true;
return HandleResult.PendingHandler;
}
// Fallback was called, continue to the remaining handlers.
result = HandleResult.Fallback;
}
return result;
}
JsonObject interceptionPatterns() {
JsonArray jsonPatterns = new JsonArray();
for (RouteInfo route : routes) {
JsonObject jsonPattern = new JsonObject();
Object urlFilter = route.matcher.rawSource;
if (urlFilter instanceof String) {
jsonPattern.addProperty("glob", (String) urlFilter);
} else if (urlFilter instanceof Pattern) {
Pattern pattern = (Pattern) urlFilter;
jsonPattern.addProperty("regexSource", pattern.pattern());
jsonPattern.addProperty("regexFlags", toJsRegexFlags(pattern));
} else {
// Match all requests.
jsonPattern.addProperty("glob", "**/*");
jsonPatterns = new JsonArray();
jsonPatterns.add(jsonPattern);
break;
}
jsonPatterns.add(jsonPattern);
}
JsonObject result = new JsonObject();
result.add("patterns", jsonPatterns);
return result;
}
}
@@ -32,9 +32,13 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Pattern;
@@ -43,6 +47,8 @@ import static com.microsoft.playwright.impl.Utils.fromJsRegexFlags;
class Serialization {
private static final Gson gson = new GsonBuilder().disableHtmlEscaping()
.registerTypeAdapter(Date.class, new DateSerializer())
.registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer())
.registerTypeAdapter(SameSiteAttribute.class, new SameSiteAdapter().nullSafe())
.registerTypeAdapter(BrowserChannel.class, new ToLowerCaseAndDashSerializer<BrowserChannel>())
.registerTypeAdapter(ColorScheme.class, new ToLowerCaseAndDashSerializer<ColorScheme>())
@@ -348,6 +354,16 @@ class Serialization {
return array;
}
static JsonArray toSelectValueOrLabel(String[] values) {
JsonArray jsonOptions = new JsonArray();
for (String value : values) {
JsonObject option = new JsonObject();
option.addProperty("valueOrLabel", value);
jsonOptions.add(option);
}
return jsonOptions;
}
static Map<String, String> fromNameValues(JsonArray array) {
Map<String, String> map = new LinkedHashMap<>();
for (JsonElement element : array) {
@@ -411,12 +427,6 @@ class Serialization {
}
}
private static class BrowserChannelSerializer implements JsonSerializer<BrowserChannel> {
@Override
public JsonElement serialize(BrowserChannel src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.toString().toLowerCase().replace('_', '-'));
}
}
private static class ToLowerCaseAndDashSerializer<E extends Enum<E>> implements JsonSerializer<E> {
@Override
public JsonElement serialize(E src, Type typeOfSrc, JsonSerializationContext context) {
@@ -464,5 +474,29 @@ class Serialization {
return SameSiteAttribute.valueOf(value.toUpperCase());
}
}
private static DateFormat iso8601Format() {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault());
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
return dateFormat;
}
private static final DateFormat dateFormat = iso8601Format();
private static class DateSerializer implements JsonSerializer<Date> {
@Override
public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(dateFormat.format(src));
}
}
private static class LocalDateTimeSerializer implements JsonSerializer<LocalDateTime> {
@Override
public JsonElement serialize(LocalDateTime src, Type typeOfSrc, JsonSerializationContext context) {
ZoneOffset offset = ZoneId.systemDefault().getRules().getOffset(src);
Instant instant = src.toInstant(offset);
return new JsonPrimitive(dateFormat.format(Date.from(instant)));
}
}
}
@@ -27,7 +27,7 @@ import java.util.regex.Pattern;
import static com.microsoft.playwright.impl.Utils.globToRegex;
class UrlMatcher {
private final Object rawSource;
final Object rawSource;
private final Predicate<String> predicate;
private static Predicate<String> toPredicate(Pattern pattern) {
@@ -21,6 +21,7 @@ import com.google.gson.JsonObject;
import com.microsoft.playwright.PlaywrightException;
import com.microsoft.playwright.options.FilePayload;
import com.microsoft.playwright.options.HttpHeader;
import com.microsoft.playwright.options.SelectOption;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -34,6 +34,8 @@ import java.nio.file.Path;
public interface FormData {
/**
* Creates new instance of {@code FormData}.
*
* @since v1.18
*/
static FormData create() {
return new FormDataImpl();
@@ -43,6 +45,7 @@ public interface FormData {
*
* @param name Field name.
* @param value Field value.
* @since v1.18
*/
FormData set(String name, String value);
/**
@@ -50,6 +53,7 @@ public interface FormData {
*
* @param name Field name.
* @param value Field value.
* @since v1.18
*/
FormData set(String name, boolean value);
/**
@@ -57,6 +61,7 @@ public interface FormData {
*
* @param name Field name.
* @param value Field value.
* @since v1.18
*/
FormData set(String name, int value);
/**
@@ -64,6 +69,7 @@ public interface FormData {
*
* @param name Field name.
* @param value Field value.
* @since v1.18
*/
FormData set(String name, Path value);
/**
@@ -71,6 +77,7 @@ public interface FormData {
*
* @param name Field name.
* @param value Field value.
* @since v1.18
*/
FormData set(String name, FilePayload value);
}
@@ -19,8 +19,8 @@ package com.microsoft.playwright.options;
import com.microsoft.playwright.impl.RequestOptionsImpl;
/**
* The {@code RequestOptions} allows to create form data to be sent via {@code APIRequestContext}. Playwright will automatically
* determine content type of the request.
* The {@code RequestOptions} allows to create form data to be sent via {@code APIRequestContext}. Playwright will
* automatically determine content type of the request.
* <pre>{@code
* context.request().post(
* "https://example.com/submit",
@@ -31,8 +31,8 @@ import com.microsoft.playwright.impl.RequestOptionsImpl;
*
* <p> **Uploading html form data**
*
* <p> {@code FormData} class can be used to send a form to the server, by default the request will use
* {@code application/x-www-form-urlencoded} encoding:
* <p> {@code FormData} class can be used to send a form to the server, by default the request will use {@code
* application/x-www-form-urlencoded} encoding:
* <pre>{@code
* context.request().post("https://example.com/signup", RequestOptions.create().setForm(
* FormData.create()
@@ -59,6 +59,8 @@ import com.microsoft.playwright.impl.RequestOptionsImpl;
public interface RequestOptions {
/**
* Creates new instance of {@code RequestOptions}.
*
* @since v1.18
*/
static RequestOptions create() {
return new RequestOptionsImpl();
@@ -67,52 +69,60 @@ public interface RequestOptions {
* Sets the request's post data.
*
* @param data Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string and
* {@code content-type} header will be set to {@code application/json} if not explicitly set. Otherwise the {@code content-type} header will
* be set to {@code application/octet-stream} if not explicitly set.
* {@code content-type} header will be set to {@code application/json} if not explicitly set. Otherwise the {@code
* content-type} header will be set to {@code application/octet-stream} if not explicitly set.
* @since v1.18
*/
RequestOptions setData(String data);
/**
* Sets the request's post data.
*
* @param data Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string and
* {@code content-type} header will be set to {@code application/json} if not explicitly set. Otherwise the {@code content-type} header will
* be set to {@code application/octet-stream} if not explicitly set.
* {@code content-type} header will be set to {@code application/json} if not explicitly set. Otherwise the {@code
* content-type} header will be set to {@code application/octet-stream} if not explicitly set.
* @since v1.18
*/
RequestOptions setData(byte[] data);
/**
* Sets the request's post data.
*
* @param data Allows to set post data of the request. If the data parameter is an object, it will be serialized to json string and
* {@code content-type} header will be set to {@code application/json} if not explicitly set. Otherwise the {@code content-type} header will
* be set to {@code application/octet-stream} if not explicitly set.
* {@code content-type} header will be set to {@code application/json} if not explicitly set. Otherwise the {@code
* content-type} header will be set to {@code application/octet-stream} if not explicitly set.
* @since v1.18
*/
RequestOptions setData(Object data);
/**
*
*
* @param failOnStatusCode Whether to throw on response codes other than 2xx and 3xx. By default response object is returned for all status codes.
* @since v1.18
*/
RequestOptions setFailOnStatusCode(boolean failOnStatusCode);
/**
* Provides {@code FormData} object that will be serialized as html form using {@code application/x-www-form-urlencoded} encoding and
* sent as this request body. If this parameter is specified {@code content-type} header will be set to
* {@code application/x-www-form-urlencoded} unless explicitly provided.
* Provides {@code FormData} object that will be serialized as html form using {@code application/x-www-form-urlencoded}
* encoding and sent as this request body. If this parameter is specified {@code content-type} header will be set to {@code
* application/x-www-form-urlencoded} unless explicitly provided.
*
* @param form Form data to be serialized as html form using {@code application/x-www-form-urlencoded} encoding and sent as this request
* body.
* @param form Form data to be serialized as html form using {@code application/x-www-form-urlencoded} encoding and sent as this
* request body.
* @since v1.18
*/
RequestOptions setForm(FormData form);
/**
* Sets an HTTP header to the request.
* Sets an HTTP header to the request. This header will apply to the fetched request as well as any redirects initiated by
* it.
*
* @param name Header name.
* @param value Header value.
* @since v1.18
*/
RequestOptions setHeader(String name, String value);
/**
*
*
* @param ignoreHTTPSErrors Whether to ignore HTTPS errors when sending network requests.
* @since v1.18
*/
RequestOptions setIgnoreHTTPSErrors(boolean ignoreHTTPSErrors);
/**
@@ -120,6 +130,7 @@ public interface RequestOptions {
*
* @param maxRedirects Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is
* exceeded. Defaults to {@code 20}. Pass {@code 0} to not follow redirects.
* @since v1.26
*/
RequestOptions setMaxRedirects(int maxRedirects);
/**
@@ -127,14 +138,16 @@ public interface RequestOptions {
* href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST">POST</a>).
*
* @param method Request method, e.g. <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST">POST</a>.
* @since v1.18
*/
RequestOptions setMethod(String method);
/**
* Provides {@code FormData} object that will be serialized as html form using {@code multipart/form-data} encoding and sent as this
* request body. If this parameter is specified {@code content-type} header will be set to {@code multipart/form-data} unless
* explicitly provided.
* Provides {@code FormData} object that will be serialized as html form using {@code multipart/form-data} encoding and
* sent as this request body. If this parameter is specified {@code content-type} header will be set to {@code
* multipart/form-data} unless explicitly provided.
*
* @param form Form data to be serialized as html form using {@code multipart/form-data} encoding and sent as this request body.
* @since v1.18
*/
RequestOptions setMultipart(FormData form);
/**
@@ -142,6 +155,7 @@ public interface RequestOptions {
*
* @param name Parameter name.
* @param value Parameter value.
* @since v1.18
*/
RequestOptions setQueryParam(String name, String value);
/**
@@ -149,6 +163,7 @@ public interface RequestOptions {
*
* @param name Parameter name.
* @param value Parameter value.
* @since v1.18
*/
RequestOptions setQueryParam(String name, boolean value);
/**
@@ -156,12 +171,14 @@ public interface RequestOptions {
*
* @param name Parameter name.
* @param value Parameter value.
* @since v1.18
*/
RequestOptions setQueryParam(String name, int value);
/**
* Sets request timeout in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout.
*
* @param timeout Request timeout in milliseconds.
* @since v1.18
*/
RequestOptions setTimeout(double timeout);
}
@@ -0,0 +1,54 @@
package com.microsoft.playwright;
import com.microsoft.playwright.assertions.LocatorAssertions;
import org.junit.jupiter.api.Test;
import org.opentest4j.AssertionFailedError;
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
// Copied from expect-misc.spec.ts > toBeInViewport
public class TestAssertThatIsInViewport extends TestBase {
@Test
void shouldWork() {
page.setContent("<div id=big style=\"height: 10000px;\"></div>\n" +
" <div id=small>foo</div>");
assertThat(page.locator("#big")).isInViewport();
assertThat(page.locator("#small")).not().isInViewport();
page.locator("#small").scrollIntoViewIfNeeded();
assertThat(page.locator("#small")).isInViewport();
assertThat(page.locator("#small")).isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(1));
}
@Test
void shouldRespectRatioOption() {
page.setContent("<style>body, div, html { padding: 0; margin: 0; }</style>\n" +
" <div id=big style=\"height: 400vh;\"></div>");
assertThat(page.locator("div")).isInViewport();
assertThat(page.locator("div")).isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.1));
assertThat(page.locator("div")).isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.2));
assertThat(page.locator("div")).isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.24));
// In this test, element's ratio is 0.25.
assertThat(page.locator("div")).isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.25));
assertThat(page.locator("div")).not().isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.26));
assertThat(page.locator("div")).not().isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.3));
assertThat(page.locator("div")).not().isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.7));
assertThat(page.locator("div")).not().isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.8));
}
@Test
void shouldHaveGoodStack() {
AssertionFailedError error = assertThrows(AssertionFailedError.class, () -> assertThat(page.locator("body")).not().isInViewport(new LocatorAssertions.IsInViewportOptions().setTimeout(100)));
assertNotNull(error);
assertTrue(error.getMessage().contains("Locator expected not to be in viewport"), error.getMessage());
}
@Test
void shouldReportIntersectionEvenIfFullyCoveredByOtherElement() {
page.setContent("<h1>hello</h1>\n" +
" <div style=\"position: relative; height: 10000px; top: -5000px;></div>");
assertThat(page.locator("h1")).isInViewport();
}
}
@@ -9,6 +9,9 @@ import org.junit.jupiter.api.io.TempDir;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@@ -479,6 +482,28 @@ public class TestBrowserContextFetch extends TestBase {
assertEquals("data", new String(req.get().postBody));
}
public static class TestData {
public String name;
public LocalDateTime localDateTime;
public Date date;
public LocalDateTime nullLocalDateTime;
public Date nullDate;
}
@Test
void shouldSerializeDateAndLocalDateTime() throws ExecutionException, InterruptedException, ParseException {
Request pageReq = page.waitForRequest("**/*", () -> page.navigate(server.EMPTY_PAGE));
Future<Server.Request> req = server.futureRequest("/empty.html");
TestData testData = new TestData();
testData.name = "foo";
long currentMillis = 1671776098818L;
testData.date = new Date(currentMillis);
testData.localDateTime = testData.date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
context.request().fetch(pageReq, RequestOptions.create().setMethod("POST").setData(testData));
assertEquals("{\"name\":\"foo\",\"localDateTime\":\"2022-12-23T06:14:58.818Z\",\"date\":\"2022-12-23T06:14:58.818Z\"}",
new String(req.get().postBody));
}
@Test
void shouldSupportApplicationXWwwFormUrlencoded() throws ExecutionException, InterruptedException {
Future<Server.Request> req = server.futureRequest("/empty.html");
@@ -16,6 +16,8 @@
package com.microsoft.playwright;
import com.microsoft.playwright.options.AriaRole;
import com.microsoft.playwright.options.WaitUntilState;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledIf;
import org.junit.jupiter.api.condition.EnabledIf;
@@ -83,4 +83,13 @@ public class TestElementHandleMisc extends TestBase {
input.setChecked(false);
assertEquals(false, page.evaluate("checkbox.checked"));
}
@Test
void shouldFallBackToSelectingByLabel() {
page.navigate(server.PREFIX + "/input/select.html");
page.querySelector("select").selectOption("Blue");
assertEquals(asList("blue"), page.evaluate("() => window['result'].onInput"));
assertEquals(asList("blue"), page.evaluate("() => window['result'].onChange"));
}
}
@@ -164,10 +164,10 @@ public class TestGlobalFetch extends TestBase {
@Test
void shouldSupportGlobalTimeoutOption() {
APIRequestContext request = playwright.request().newContext(new APIRequest.NewContextOptions().setTimeout(1));
APIRequestContext request = playwright.request().newContext(new APIRequest.NewContextOptions().setTimeout(100));
server.setRoute("/empty.html", exchange -> {});
PlaywrightException e = assertThrows(PlaywrightException.class, () -> request.get(server.EMPTY_PAGE));
assertTrue(e.getMessage().contains("Request timed out after 1ms"), e.getMessage());
assertTrue(e.getMessage().contains("Request timed out after 100ms"), e.getMessage());
}
@@ -193,7 +193,7 @@ public class TestLocatorAssertions extends TestBase {
assertThat(locator).not().hasText(new String[] {}, new LocatorAssertions.HasTextOptions().setTimeout(1000));
});
assertEquals("[]", e.getExpected().getStringRepresentation());
assertEquals("null", e.getActual().getStringRepresentation());
assertEquals("[]", e.getActual().getStringRepresentation());
assertTrue(e.getMessage().contains("Locator expected not to have text"), e.getMessage());
}
@@ -0,0 +1,22 @@
package com.microsoft.playwright;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import static java.util.Arrays.asList;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class TestLocatorList extends TestBase {
@Test
void locatorAllShouldWork() {
page.setContent("<div><p>A</p><p>B</p><p>C</p></div>");
List<String> texts = new ArrayList<>();
for (Locator p : page.locator("div >> p").all()) {
texts.add(p.textContent());
}
assertEquals(asList("A", "B", "C"), texts);
}
}
@@ -44,7 +44,7 @@ public class TestPageFill extends TestBase {
for (String type : new String[]{"button", "checkbox", "file", "image", "radio", "reset", "submit"}) {
page.evalOnSelector("input", "(input, type) => input.setAttribute('type', type)", type);
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.fill("input", ""));
assertTrue(e.getMessage().contains("input of type \"" + type + "\" cannot be filled"), "type = " + type + e.getMessage());
assertTrue(e.getMessage().contains("Error: Input of type \"" + type + "\" cannot be filled"), "type = " + type + e.getMessage());
}
}
@@ -3,6 +3,8 @@ package com.microsoft.playwright;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import static org.junit.jupiter.api.Assertions.*;
@@ -57,4 +59,50 @@ public class TestPageInterception extends TestBase {
}
}
@Test
void shouldFulfillInterceptedResponseUsingAlias() {
page.route("**/*", route -> {
APIResponse response = route.fetch();
System.out.println(response.headers().get("content-type"));
route.fulfill(new Route.FulfillOptions().setResponse(response));
});
Response response = page.navigate(server.PREFIX + "/empty.html");
assertEquals(200, response.status());
assertTrue(response.headers().get("content-type").contains("text/html"));
}
@Test
void shouldInterceptWithUrlOverride() {
page.route("**/*.html", route -> {
APIResponse response = route.fetch(new Route.FetchOptions().setUrl(server.PREFIX + "/one-style.html"));
route.fulfill(new Route.FulfillOptions().setResponse(response));
});
Response response = page.navigate(server.PREFIX + "/empty.html");
assertEquals(200, response.status());
assertTrue(response.text().contains("one-style.css"), response.text());
}
@Test
void shouldInterceptWithPostDataOverride() throws ExecutionException, InterruptedException {
Future<Server.Request> request = server.futureRequest("/empty.html");
page.route("**/*.html", route -> {
APIResponse response = route.fetch(new Route.FetchOptions().setPostData("{ \"foo\": \"bar\" }"));
route.fulfill(new Route.FulfillOptions().setResponse(response));
});
page.navigate(server.PREFIX + "/empty.html");
assertEquals("{ \"foo\": \"bar\" }", new String(request.get().postBody));
}
@Test
void shouldNotFollowRedirectsWhenMaxRedirectsIsSetTo0InRouteFetch() {
server.setRedirect("/foo", "/empty.html");
page.route("**/*", route -> {
APIResponse response = route.fetch(new Route.FetchOptions().setMaxRedirects(0));
assertEquals("/empty.html", response.headers().get("location"));
assertEquals(302, response.status());
route.fulfill(new Route.FulfillOptions().setBody("hello"));
});
page.navigate(server.PREFIX + "/foo");
assertTrue(page.content().contains("hello"));
}
}
@@ -19,11 +19,12 @@ package com.microsoft.playwright;
import com.microsoft.playwright.options.HttpHeader;
import org.junit.jupiter.api.Test;
import java.io.OutputStreamWriter;
import java.util.List;
import java.util.stream.Collectors;
import static java.util.Arrays.asList;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.*;
public class TestPageNetworkResponse extends TestBase {
@Test
@@ -45,4 +46,51 @@ public class TestPageNetworkResponse extends TestBase {
assertEquals(asList("a=b", "c=d"), response.headerValues("set-cookie"));
}
@Test
void shouldRejectResponseFinishedIfPageCloses() {
page.navigate(server.EMPTY_PAGE);
server.setRoute("/get", exchange -> {
// In Firefox, |fetch| will be hanging until it receives |Content-Type| header
// from server.
exchange.getResponseHeaders().add("Content-Type", "text/plain; charset=utf-8");
exchange.sendResponseHeaders(200, 0);
OutputStreamWriter writer = new OutputStreamWriter(exchange.getResponseBody());
writer.write("hello ");
});
// send request and wait for server response
Response pageResponse = page.waitForResponse("**/get", () -> {
page.evaluate("() => fetch('./get', { method: 'GET' })");
});
// In 1s send a request which will trigger a request event while pageResponse.finished() is still
// on the callstack.
page.onRequest(request -> page.close());
page.evaluate("() => setTimeout(() => fetch('./empty.html', { method: 'GET' }), 1000)");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> pageResponse.finished());
assertTrue(e.getMessage().contains("closed"), e.getMessage());
}
@Test
void shouldRejectResponseFinishedIfContextCloses() {
page.navigate(server.EMPTY_PAGE);
server.setRoute("/get", exchange -> {
// In Firefox, |fetch| will be hanging until it receives |Content-Type| header
// from server.
exchange.getResponseHeaders().add("Content-Type", "text/plain; charset=utf-8");
exchange.sendResponseHeaders(200, 0);
OutputStreamWriter writer = new OutputStreamWriter(exchange.getResponseBody());
writer.write("hello ");
});
// send request and wait for server response
Response pageResponse = page.waitForResponse("**/get", () -> {
page.evaluate("() => fetch('./get', { method: 'GET' })");
});
// In 1s send a request which will trigger a request event while pageResponse.finished() is still
// on the callstack.
page.onRequest(request -> context.close());
page.evaluate("() => setTimeout(() => fetch('./empty.html', { method: 'GET' }), 1000)");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> pageResponse.finished());
assertTrue(e.getMessage().contains("closed"), e.getMessage());
}
}
@@ -73,7 +73,7 @@ public class TestPageRequestContinue extends TestBase {
done[0] = true;
});
PlaywrightException e = assertThrows(PlaywrightException.class, () -> page.navigate(server.EMPTY_PAGE));
assertTrue(e.getMessage().contains("Navigation failed because page was closed") ||
assertTrue(e.getMessage().contains("Target page, context or browser has been closed") ||
e.getMessage().contains("frame was detached"), e.getMessage());
assertTrue(done[0]);
}
@@ -469,7 +469,7 @@ public class TestPageRoute extends TestBase {
}
@Test
void shouldThrowIfResumeIsCalledAfterRouteHandlerFinished() {
void shouldNotThrowIfResumeIsCalledAfterRouteHandlerFinished() {
page.setContent("<iframe></iframe>");
Route[] route = {null};
page.route("**/*", r -> route[0] = r);
@@ -477,8 +477,7 @@ public class TestPageRoute extends TestBase {
page.waitForRequest("**", () -> page.evalOnSelector("iframe", "(frame, url) => frame.src = url", server.EMPTY_PAGE));
// Delete frame to cause request to be canceled.
page.evalOnSelector("iframe", "frame => frame.remove()");
PlaywrightException e = assertThrows(PlaywrightException.class, () -> route[0].resume());
assertTrue(e.getMessage().contains("Route is already handled!"), e.getMessage());
route[0].resume();
}
@Test
@@ -731,4 +730,77 @@ public class TestPageRoute extends TestBase {
page.navigate(server.EMPTY_PAGE);
assertEquals(asList(3, 2, 1), intercepted);
}
@Test
void shouldAllowToCallRouteAsynchronously() {
page.navigate(server.EMPTY_PAGE);
Route[] route = new Route[] { null };
page.route("**/cars", r -> {
route[0] = r;
});
page.evaluate("async () => {\n" +
" window.didReceiveResponse = false;\n" +
" window.pendingFetch = fetch('/cars', {\n" +
" method: 'POST',\n" +
" headers: { 'Content-Type': 'application/json' },\n" +
" mode: 'cors',\n" +
" body: JSON.stringify({ 'number': 1 })\n" +
" }).then(r => { window.didReceiveResponse = true; return r; });\n" +
" }");
while (route[0] == null) {
page.waitForTimeout(10);
}
assertNotNull(route[0]);
page.waitForTimeout(1000); // Allow some time for didReceiveResponse to be updated.
assertEquals(false, page.evaluate("window.didReceiveResponse"));
route[0].fulfill(new Route.FulfillOptions()
.setContentType("text/plain")
.setStatus(200)
.setBody("Hi!"));
Object response = page.evaluate("async () => (await pendingFetch).text()\n");
assertEquals("Hi!", response);
}
@Test
void shouldResumeIfFallbackIsCalledAsynchronously() {
page.navigate(server.EMPTY_PAGE);
Route[] route = new Route[] { null };
page.route("**/simple.json", r -> {
route[0] = r;
});
page.evaluate("async () => {\n" +
" window.didReceiveResponse = false;\n" +
" window.pendingFetch = fetch('" + server.PREFIX + "/simple.json', {\n" +
" method: 'POST',\n" +
" headers: { 'Content-Type': 'application/json' },\n" +
" mode: 'cors',\n" +
" body: JSON.stringify({ 'number': 1 })\n" +
" }).then(r => { window.didReceiveResponse = true; return r; });\n" +
" }");
while (route[0] == null) {
page.waitForTimeout(10);
}
assertNotNull(route[0]);
page.waitForTimeout(1000); // Allow some time for didReceiveResponse to be updated.
assertEquals(false, page.evaluate("window.didReceiveResponse"));
route[0].fallback();
Object response = page.evaluate("async () => (await pendingFetch).text()\n");
assertEquals("{\"foo\": \"bar\"}\n", response);
}
@Test
void shouldContinueIfAllHandlersCalledFallback() {
List<Integer> intercepted = new ArrayList<>();
Predicate<String> predicate = r -> true;
page.route(predicate, route -> {
intercepted.add(1);
route.fallback();
});
context.route(predicate, route -> {
intercepted.add(2);
route.fallback();
});
page.navigate(server.EMPTY_PAGE);
assertEquals(asList(1, 2), intercepted);
}
}
@@ -43,6 +43,14 @@ public class TestPageSelectOption extends TestBase {
assertEquals(asList("blue"), page.evaluate("() => window['result'].onChange"));
}
@Test
void shouldFallBackToSelectingByLabel() {
page.navigate(server.PREFIX + "/input/select.html");
page.selectOption("select", "Blue");
assertEquals(asList("blue"), page.evaluate("() => window['result'].onInput"));
assertEquals(asList("blue"), page.evaluate("() => window['result'].onChange"));
}
@Test
void shouldSelectSingleOptionByLabel() {
page.navigate(server.PREFIX + "/input/select.html");
@@ -1,5 +1,6 @@
package com.microsoft.playwright;
import com.microsoft.playwright.assertions.LocatorAssertions;
import com.microsoft.playwright.options.AriaRole;
import org.junit.jupiter.api.Test;
@@ -25,6 +26,14 @@ public class TestSelectorsGetBy extends TestBase {
assertThat(page.getByTestId("He\"llo")).hasText("Hello world");
}
@Test
void getByTestIdShouldWorkForRegex() {
page.setContent("<div><div data-testid='Hello'>Hello world</div></div>");
assertThat(page.getByTestId(Pattern.compile("He[l]*o"))).hasText("Hello world");
assertThat(page.mainFrame().getByTestId("Hello")).hasText("Hello world");
assertThat(page.locator("div").getByTestId("Hello")).hasText("Hello world");
}
@Test
void getByTextShouldWork() {
page.setContent("<div>yo</div><div>ya</div><div>\nye </div>");
@@ -139,6 +148,11 @@ public class TestSelectorsGetBy extends TestBase {
assertThat(page.getByPlaceholder("hello my\nworld")).hasAttribute("id", "control");
assertThat(page.getByAltText("hello my\nworld")).hasAttribute("id", "control");
assertThat(page.getByTitle("hello my\nworld")).hasAttribute("id", "control");
page.setContent("<div id=target title='my title'>Text here</div>");
assertThat(page.getByTitle("my title", new Page.GetByTitleOptions().setExact(true))).hasCount(1, new LocatorAssertions.HasCountOptions().setTimeout(500));
assertThat(page.getByTitle("my t\\itle", new Page.GetByTitleOptions().setExact(true))).hasCount(0, new LocatorAssertions.HasCountOptions().setTimeout(500));
assertThat(page.getByTitle("my t\\\\itle", new Page.GetByTitleOptions().setExact(true))).hasCount(0, new LocatorAssertions.HasCountOptions().setTimeout(500));
}
@Test
@@ -170,5 +184,23 @@ public class TestSelectorsGetBy extends TestBase {
assertEquals(
asList("<a href=\"https://playwright.dev\">he llo 56</a>"),
page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName(" he \n llo 56 ").setExact(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(
asList("<button>Click me</button>"),
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Click me").setExact(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(
asList(),
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Click \\me").setExact(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(
asList(),
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Click \\\\me").setExact(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
}
@Test
void locatorGetByRole() {
page.setContent("<div><button>Click me</button></div>");
assertEquals(
asList("<button>Click me</button>"),
page.locator("div").getByRole(AriaRole.BUTTON).evaluateAll("els => els.map(e => e.outerHTML)"));
}
}
@@ -153,26 +153,42 @@ public class TestSelectorsRole extends TestBase {
@Test
void shouldSupportExpanded() {
page.setContent("<button>Hi</button>\n" +
" <button aria-expanded=\"true\">Hello</button>\n" +
" <button aria-expanded=\"false\">Bye</button>");
page.setContent("<div role=\"treeitem\">Hi</div>\n" +
" <div role=\"treeitem\" aria-expanded=\"true\">Hello</div>\n" +
" <div role=\"treeitem\" aria-expanded=\"false\">Bye</div>");
assertEquals(asList(
"<button aria-expanded=\"true\">Hello</button>"
), page.locator("role=button[expanded]").evaluateAll("els => els.map(e => e.outerHTML)"));
"<div role=\"treeitem\">Hi</div>",
"<div role=\"treeitem\" aria-expanded=\"true\">Hello</div>",
"<div role=\"treeitem\" aria-expanded=\"false\">Bye</div>"
), page.locator("role=treeitem").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)"));
"<div role=\"treeitem\">Hi</div>",
"<div role=\"treeitem\" aria-expanded=\"true\">Hello</div>",
"<div role=\"treeitem\" aria-expanded=\"false\">Bye</div>"
), page.getByRole(AriaRole.TREEITEM).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)"));
"<div role=\"treeitem\" aria-expanded=\"true\">Hello</div>"
), page.locator("role=treeitem[expanded]").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)"));
"<div role=\"treeitem\" aria-expanded=\"true\">Hello</div>"
), page.locator("role=treeitem[expanded=true]").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)"));
"<div role=\"treeitem\" aria-expanded=\"true\">Hello</div>"
), page.getByRole(AriaRole.TREEITEM, new Page.GetByRoleOptions().setExpanded(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<div role=\"treeitem\" aria-expanded=\"false\">Bye</div>"
), page.locator("role=treeitem[expanded=false]").evaluateAll("els => els.map(e => e.outerHTML)"));
assertEquals(asList(
"<div role=\"treeitem\" aria-expanded=\"false\">Bye</div>"
), page.getByRole(AriaRole.TREEITEM, new Page.GetByRoleOptions().setExpanded(false)).evaluateAll("els => els.map(e => e.outerHTML)"));
// Workaround for expanded='none'.
assertEquals(asList(
"<div role=\"treeitem\">Hi</div>"
), page.locator("[role=treeitem]:not([aria-expanded])").evaluateAll("els => els.map(e => e.outerHTML)"));
}
@Test
@@ -149,7 +149,7 @@ class Utils {
case "chromium":
switch (getOS()) {
case MAC:
return Arrays.asList("net::ERR_CERT_INVALID");
return Arrays.asList("net::ERR_CERT_INVALID", "net::ERR_CERT_AUTHORITY_INVALID");
default:
return Arrays.asList("net::ERR_CERT_AUTHORITY_INVALID");
}
+48 -47
View File
@@ -6,7 +6,7 @@
<groupId>com.microsoft.playwright</groupId>
<artifactId>parent-pom</artifactId>
<version>1.28.0-SNAPSHOT</version>
<version>1.31.0</version>
<packaging>pom</packaging>
<name>Playwright Parent Project</name>
<description>Java library to automate Chromium, Firefox and WebKit with a single API.
@@ -42,7 +42,8 @@
</modules>
<properties>
<compiler.version>1.8</compiler.version>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<gson.version>2.8.9</gson.version>
<junit.version>5.7.0</junit.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -90,26 +91,35 @@
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>3.2.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${compiler.version}</source>
<target>${compiler.version}</target>
</configuration>
<version>3.10.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -119,14 +129,6 @@
<additionalOptions>--allow-script-in-comments</additionalOptions>
<failOnError>false</failOnError>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -143,6 +145,9 @@
</configurationParameters>
</properties>
<failIfNoTests>false</failIfNoTests>
<!-- Activate the use of TCP to transmit events to the plugin and avoid
[WARNING] Corrupted STDOUT by directly writing to native stream in forked JVM -->
<forkNode implementation="org.apache.maven.plugin.surefire.extensions.SurefireForkNodeFactory"/>
</configuration>
</plugin>
<plugin>
@@ -150,15 +155,10 @@
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.7</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
@@ -171,29 +171,30 @@
</pluginManagement>
<plugins>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<profiles>
<profile>
<id>release</id>
+1 -1
View File
@@ -1 +1 @@
1.28.0
1.31.1
+1 -1
View File
@@ -6,7 +6,7 @@
<groupId>com.microsoft.playwright</groupId>
<artifactId>api-generator</artifactId>
<version>1.28.0-SNAPSHOT</version>
<version>1.31.0</version>
<name>Playwright - API Generator</name>
<description>
This is an internal module used to generate Java API from the upstream Playwright
@@ -90,6 +90,9 @@ abstract class Element {
if (!json.has("spec")) {
return "";
}
if (json.has("deprecated")) {
return "@deprecated " + beautify(json.get("deprecated").getAsString());
}
return formatSpec(json.getAsJsonArray("spec"));
}
@@ -143,15 +146,17 @@ abstract class Element {
out.add("</" + currentItemList + ">");
currentItemList = null;
}
return String.join("\n", out);
}
private static String beautify(String paragraph) {
String linkified = linkifyMemberRefs(paragraph);
linkified = updateExternalLinks(linkified);
return wrapText(linkified, 120, "")
linkified = updateExternalLinks(linkified)
.replaceAll("", " ")
.replaceAll("`'([^`]+)'`", "{@code \"$1\"}")
.replaceAll("`([^`]+)`", "{@code $1}");
return wrapText(linkified, 120, "");
}
private static String linkifyMemberRefs(String paragraph) {
@@ -774,6 +779,14 @@ class Method extends Element {
String returnComment = jsonElement.getAsJsonObject().get("returnComment").getAsString();
sections.add("@return " + returnComment);
}
if (jsonElement.getAsJsonObject().has("since")) {
if (!hasBlankLine) {
sections.add("");
hasBlankLine = true;
}
String since = jsonElement.getAsJsonObject().get("since").getAsString();
sections.add("@since " + since);
}
writeJavadoc(output, offset, String.join("\n", sections));
}
}
+38
View File
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.microsoft.playwright</groupId>
<artifactId>test-cli-fatjar</artifactId>
<version>1.31.0</version>
<name>Test Playwright Command Line FatJar</name>
<properties>
<compiler.version>1.8</compiler.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${compiler.version}</source>
<target>${compiler.version}</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>driver-bundle</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,28 @@
package com.microsoft.playwright.testclifatjar;
import com.microsoft.playwright.Browser;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Playwright;
import com.microsoft.playwright.impl.driver.Driver;
import com.microsoft.playwright.impl.driver.jar.DriverJar;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.util.Collections;
public class TestApp {
public static void main(String[] args) throws IOException, URISyntaxException {
URI uri = DriverJar.getDriverResourceURI();
FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap());
if (fs == null) {
throw new RuntimeException();
}
try (Playwright playwright = Playwright.create()) {
Browser browser = playwright.chromium().launch();
Page page = browser.newPage();
}
}
}
+10
View File
@@ -0,0 +1,10 @@
#!/bin/bash
set -e
set +x
trap "cd $(pwd -P)" EXIT
cd "$(dirname $0)"
echo "Running TestApp..."
mvn compile exec:java -e -Dexec.mainClass=com.microsoft.playwright.testclifatjar.TestApp
+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.28.0-SNAPSHOT</version>
<version>1.31.0</version>
<name>Test Playwright Command Line Version</name>
<properties>
<compiler.version>1.8</compiler.version>
+1 -1
View File
@@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.microsoft.playwright</groupId>
<artifactId>test-local-installation</artifactId>
<version>1.28.0-SNAPSHOT</version>
<version>1.31.0</version>
<name>Test local installation</name>
<description>Runs Playwright test suite (copied from playwright module) against locally cached Playwright</description>
<properties>
+1 -1
View File
@@ -9,7 +9,7 @@
</parent>
<groupId>com.microsoft.playwright</groupId>
<artifactId>test-spring-boot-starter</artifactId>
<version>1.28.0-SNAPSHOT</version>
<version>1.31.0</version>
<name>Test Playwright With Spring Boot</name>
<properties>
<spring.version>2.4.3</spring.version>
+1 -1
View File
@@ -6,7 +6,7 @@
<groupId>com.microsoft.playwright</groupId>
<artifactId>update-version</artifactId>
<version>1.28.0-SNAPSHOT</version>
<version>1.31.0</version>
<name>Playwright - Update Version in Documentation</name>
<description>
This is an internal module used to update versions in the documentation based on
+3 -1
View File
@@ -1,5 +1,7 @@
FROM ubuntu:focal
ARG DEBIAN_FRONTEND=noninteractive
ARG TZ=America/Los_Angeles
ARG DOCKER_IMAGE_NAME_TEMPLATE="mcr.microsoft.com/playwright/java:v%version%-focal"
# === INSTALL JDK and Maven ===
@@ -22,7 +24,7 @@ RUN apt-get update && \
# Create the pwuser
adduser pwuser
RUN VERSION=3.8.6 && \
RUN VERSION=3.8.7 && \
curl -o - https://dlcdn.apache.org/maven/maven-3/$VERSION/binaries/apache-maven-$VERSION-bin.tar.gz | tar zxfv - -C /opt/ && \
ln -s /opt/apache-maven-$VERSION/bin/mvn /usr/local/bin/