Compare commits
40 Commits
v1.26.1
...
release-1.29
| Author | SHA1 | Date | |
|---|---|---|---|
| 96cc9e6e62 | |||
| b2e17853d7 | |||
| d792d460b1 | |||
| 1b1343649e | |||
| 65624d6658 | |||
| 93a62868a1 | |||
| 28e547fe2b | |||
| 22b2932d2d | |||
| 8c0231b0f7 | |||
| c1891cb9f7 | |||
| 81d31d24f8 | |||
| 17d8a9ac7a | |||
| 4246c375ac | |||
| ec5f9604cd | |||
| d9fea34baa | |||
| 45f81c0659 | |||
| 74fafc4d7e | |||
| 4efa174368 | |||
| 048bca9d59 | |||
| afa20b91ae | |||
| 8904de9bb8 | |||
| a061ba0f30 | |||
| 5a3daf64b9 | |||
| 170d07a005 | |||
| 1674f95bd1 | |||
| 3cc198ea26 | |||
| 071ca8b90c | |||
| 805fa3a8cb | |||
| 1825c13fde | |||
| 48d9528675 | |||
| 4275ee3455 | |||
| 69f81ea8e9 | |||
| 261160e4cf | |||
| 9ac9347dc5 | |||
| 02ac0380a8 | |||
| bb4f3297e8 | |||
| ae54a7da55 | |||
| c6192db180 | |||
| b5c09a3141 | |||
| 8ef960a5f7 |
@@ -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'
|
||||
@@ -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 }}
|
||||
@@ -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
|
||||
|
||||
@@ -16,6 +16,6 @@ jobs:
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Authorization: token ${GH_TOKEN}" \
|
||||
--data "{\"event_type\": \"playwright_tests_java\", \"client_payload\": {\"ref\": \"${GITHUB_SHA}\"}}" \
|
||||
https://api.github.com/repos/microsoft/playwright-internal/dispatches
|
||||
https://api.github.com/repos/microsoft/playwright-browsers/dispatches
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }}
|
||||
|
||||
@@ -11,9 +11,9 @@ Playwright is a Java library to automate [Chromium](https://www.chromium.org/Hom
|
||||
|
||||
| | Linux | macOS | Windows |
|
||||
| :--- | :---: | :---: | :---: |
|
||||
| Chromium <!-- GEN:chromium-version -->106.0.5249.30<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| WebKit <!-- GEN:webkit-version -->16.0<!-- GEN:stop --> | ✅ | ✅ | ✅ |
|
||||
| Firefox <!-- GEN:firefox-version -->104.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| Chromium <!-- GEN:chromium-version -->109.0.5414.46<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| WebKit <!-- GEN:webkit-version -->16.4<!-- GEN:stop --> | ✅ | ✅ | ✅ |
|
||||
| Firefox <!-- GEN:firefox-version -->107.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,15 +43,15 @@ To run Playwright simply add following dependency to your Maven project:
|
||||
<dependency>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>playwright</artifactId>
|
||||
<version>1.17.0</version>
|
||||
<version>1.28.1</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
To run Playwright using Gradle add following dependency to your build.gradle file:
|
||||
|
||||
```json lines
|
||||
```gradle
|
||||
dependencies {
|
||||
implementation group: 'com.microsoft.playwright', name: 'playwright', version: '1.25.0'
|
||||
implementation group: 'com.microsoft.playwright', name: 'playwright', version: '1.28.1'
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.26.0-SNAPSHOT</version>
|
||||
<version>1.29.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>driver-bundle</artifactId>
|
||||
|
||||
+15
-4
@@ -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
|
||||
|
||||
@@ -17,13 +17,11 @@
|
||||
package com.microsoft.playwright.impl.driver.jar;
|
||||
|
||||
import com.microsoft.playwright.impl.driver.Driver;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.26.0-SNAPSHOT</version>
|
||||
<version>1.29.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>driver</artifactId>
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>org.example</groupId>
|
||||
<artifactId>examples</artifactId>
|
||||
<version>1.26.0-SNAPSHOT</version>
|
||||
<version>1.29.0</version>
|
||||
<name>Playwright Client Examples</name>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.26.0-SNAPSHOT</version>
|
||||
<version>1.29.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>playwright</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,46 +75,157 @@ 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> **Usage**
|
||||
* <pre>{@code
|
||||
* Map<String, Object> data = new HashMap();
|
||||
* data.put("title", "Book Title");
|
||||
* data.put("body", "John Doe");
|
||||
* request.fetch("https://example.com/api/createBook", RequestOptions.create().setMethod("post").setData(data));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> The common way to send file(s) in the body of a request is to encode it as form fields with {@code multipart/form-data}
|
||||
* encoding. You can achieve that with Playwright API like this:
|
||||
* <pre>{@code
|
||||
* // Pass file path to the form data constructor:
|
||||
* Path file = Paths.get("team.csv");
|
||||
* APIResponse response = request.fetch("https://example.com/api/uploadTeamList",
|
||||
* RequestOptions.create().setMethod("post").setMultipart(
|
||||
* FormData.create().set("fileField", file)));
|
||||
*
|
||||
* // Or you can pass the file content directly as FilePayload object:
|
||||
* FilePayload filePayload = new FilePayload("f.js", "text/javascript",
|
||||
* "console.log(2022);".getBytes(StandardCharsets.UTF_8));
|
||||
* APIResponse response = request.fetch("https://example.com/api/uploadTeamList",
|
||||
* RequestOptions.create().setMethod("post").setMultipart(
|
||||
* FormData.create().set("fileField", filePayload)));
|
||||
* }</pre>
|
||||
*
|
||||
* @param urlOrRequest Target URL or Request to get all parameters from.
|
||||
* @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> **Usage**
|
||||
* <pre>{@code
|
||||
* Map<String, Object> data = new HashMap();
|
||||
* data.put("title", "Book Title");
|
||||
* data.put("body", "John Doe");
|
||||
* request.fetch("https://example.com/api/createBook", RequestOptions.create().setMethod("post").setData(data));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> The common way to send file(s) in the body of a request is to encode it as form fields with {@code multipart/form-data}
|
||||
* encoding. You can achieve that with Playwright API like this:
|
||||
* <pre>{@code
|
||||
* // Pass file path to the form data constructor:
|
||||
* Path file = Paths.get("team.csv");
|
||||
* APIResponse response = request.fetch("https://example.com/api/uploadTeamList",
|
||||
* RequestOptions.create().setMethod("post").setMultipart(
|
||||
* FormData.create().set("fileField", file)));
|
||||
*
|
||||
* // Or you can pass the file content directly as FilePayload object:
|
||||
* FilePayload filePayload = new FilePayload("f.js", "text/javascript",
|
||||
* "console.log(2022);".getBytes(StandardCharsets.UTF_8));
|
||||
* APIResponse response = request.fetch("https://example.com/api/uploadTeamList",
|
||||
* RequestOptions.create().setMethod("post").setMultipart(
|
||||
* FormData.create().set("fileField", filePayload)));
|
||||
* }</pre>
|
||||
*
|
||||
* @param urlOrRequest Target URL or Request to get all parameters from.
|
||||
* @param params Optional request parameters.
|
||||
* @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> **Usage**
|
||||
* <pre>{@code
|
||||
* Map<String, Object> data = new HashMap();
|
||||
* data.put("title", "Book Title");
|
||||
* data.put("body", "John Doe");
|
||||
* request.fetch("https://example.com/api/createBook", RequestOptions.create().setMethod("post").setData(data));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> The common way to send file(s) in the body of a request is to encode it as form fields with {@code multipart/form-data}
|
||||
* encoding. You can achieve that with Playwright API like this:
|
||||
* <pre>{@code
|
||||
* // Pass file path to the form data constructor:
|
||||
* Path file = Paths.get("team.csv");
|
||||
* APIResponse response = request.fetch("https://example.com/api/uploadTeamList",
|
||||
* RequestOptions.create().setMethod("post").setMultipart(
|
||||
* FormData.create().set("fileField", file)));
|
||||
*
|
||||
* // Or you can pass the file content directly as FilePayload object:
|
||||
* FilePayload filePayload = new FilePayload("f.js", "text/javascript",
|
||||
* "console.log(2022);".getBytes(StandardCharsets.UTF_8));
|
||||
* APIResponse response = request.fetch("https://example.com/api/uploadTeamList",
|
||||
* RequestOptions.create().setMethod("post").setMultipart(
|
||||
* FormData.create().set("fileField", filePayload)));
|
||||
* }</pre>
|
||||
*
|
||||
* @param urlOrRequest Target URL or Request to get all parameters from.
|
||||
* @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> **Usage**
|
||||
* <pre>{@code
|
||||
* Map<String, Object> data = new HashMap();
|
||||
* data.put("title", "Book Title");
|
||||
* data.put("body", "John Doe");
|
||||
* request.fetch("https://example.com/api/createBook", RequestOptions.create().setMethod("post").setData(data));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> The common way to send file(s) in the body of a request is to encode it as form fields with {@code multipart/form-data}
|
||||
* encoding. You can achieve that with Playwright API like this:
|
||||
* <pre>{@code
|
||||
* // Pass file path to the form data constructor:
|
||||
* Path file = Paths.get("team.csv");
|
||||
* APIResponse response = request.fetch("https://example.com/api/uploadTeamList",
|
||||
* RequestOptions.create().setMethod("post").setMultipart(
|
||||
* FormData.create().set("fileField", file)));
|
||||
*
|
||||
* // Or you can pass the file content directly as FilePayload object:
|
||||
* FilePayload filePayload = new FilePayload("f.js", "text/javascript",
|
||||
* "console.log(2022);".getBytes(StandardCharsets.UTF_8));
|
||||
* APIResponse response = request.fetch("https://example.com/api/uploadTeamList",
|
||||
* RequestOptions.create().setMethod("post").setMultipart(
|
||||
* FormData.create().set("fileField", filePayload)));
|
||||
* }</pre>
|
||||
*
|
||||
* @param urlOrRequest Target URL or Request to get all parameters from.
|
||||
* @param params Optional request parameters.
|
||||
* @since v1.16
|
||||
*/
|
||||
APIResponse fetch(Request urlOrRequest, RequestOptions params);
|
||||
/**
|
||||
@@ -121,7 +233,17 @@ 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()
|
||||
* .setQueryParam("isbn", "1234")
|
||||
* .setQueryParam("page", 23));
|
||||
* }</pre>
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @since v1.16
|
||||
*/
|
||||
default APIResponse get(String url) {
|
||||
return get(url, null);
|
||||
@@ -131,8 +253,18 @@ 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()
|
||||
* .setQueryParam("isbn", "1234")
|
||||
* .setQueryParam("page", 23));
|
||||
* }</pre>
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @param params Optional request parameters.
|
||||
* @since v1.16
|
||||
*/
|
||||
APIResponse get(String url, RequestOptions params);
|
||||
/**
|
||||
@@ -141,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);
|
||||
@@ -152,6 +285,7 @@ public interface APIRequestContext {
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @param params Optional request parameters.
|
||||
* @since v1.16
|
||||
*/
|
||||
APIResponse head(String url, RequestOptions params);
|
||||
/**
|
||||
@@ -160,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);
|
||||
@@ -171,6 +306,7 @@ public interface APIRequestContext {
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @param params Optional request parameters.
|
||||
* @since v1.16
|
||||
*/
|
||||
APIResponse patch(String url, RequestOptions params);
|
||||
/**
|
||||
@@ -178,7 +314,44 @@ 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();
|
||||
* data.put("title", "Book Title");
|
||||
* data.put("body", "John Doe");
|
||||
* request.post("https://example.com/api/createBook", RequestOptions.create().setData(data));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> To send form data to the server use {@code form} option. Its value will be encoded into the request body with {@code
|
||||
* application/x-www-form-urlencoded} encoding (see below how to use {@code multipart/form-data} form encoding to send
|
||||
* files):
|
||||
* <pre>{@code
|
||||
* request.post("https://example.com/api/findBook", RequestOptions.create().setForm(
|
||||
* FormData.create().set("title", "Book Title").set("body", "John Doe")
|
||||
* ));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> The common way to send file(s) in the body of a request is to upload them as form fields with {@code
|
||||
* multipart/form-data} encoding. You can achieve that with Playwright API like this:
|
||||
* <pre>{@code
|
||||
* // Pass file path to the form data constructor:
|
||||
* Path file = Paths.get("team.csv");
|
||||
* APIResponse response = request.post("https://example.com/api/uploadTeamList",
|
||||
* RequestOptions.create().setMultipart(
|
||||
* FormData.create().set("fileField", file)));
|
||||
*
|
||||
* // Or you can pass the file content directly as FilePayload object:
|
||||
* FilePayload filePayload = new FilePayload("f.js", "text/javascript",
|
||||
* "console.log(2022);".getBytes(StandardCharsets.UTF_8));
|
||||
* APIResponse response = request.post("https://example.com/api/uploadTeamList",
|
||||
* RequestOptions.create().setMultipart(
|
||||
* FormData.create().set("fileField", filePayload)));
|
||||
* }</pre>
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @since v1.16
|
||||
*/
|
||||
default APIResponse post(String url) {
|
||||
return post(url, null);
|
||||
@@ -188,8 +361,45 @@ 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();
|
||||
* data.put("title", "Book Title");
|
||||
* data.put("body", "John Doe");
|
||||
* request.post("https://example.com/api/createBook", RequestOptions.create().setData(data));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> To send form data to the server use {@code form} option. Its value will be encoded into the request body with {@code
|
||||
* application/x-www-form-urlencoded} encoding (see below how to use {@code multipart/form-data} form encoding to send
|
||||
* files):
|
||||
* <pre>{@code
|
||||
* request.post("https://example.com/api/findBook", RequestOptions.create().setForm(
|
||||
* FormData.create().set("title", "Book Title").set("body", "John Doe")
|
||||
* ));
|
||||
* }</pre>
|
||||
*
|
||||
* <p> The common way to send file(s) in the body of a request is to upload them as form fields with {@code
|
||||
* multipart/form-data} encoding. You can achieve that with Playwright API like this:
|
||||
* <pre>{@code
|
||||
* // Pass file path to the form data constructor:
|
||||
* Path file = Paths.get("team.csv");
|
||||
* APIResponse response = request.post("https://example.com/api/uploadTeamList",
|
||||
* RequestOptions.create().setMultipart(
|
||||
* FormData.create().set("fileField", file)));
|
||||
*
|
||||
* // Or you can pass the file content directly as FilePayload object:
|
||||
* FilePayload filePayload = new FilePayload("f.js", "text/javascript",
|
||||
* "console.log(2022);".getBytes(StandardCharsets.UTF_8));
|
||||
* APIResponse response = request.post("https://example.com/api/uploadTeamList",
|
||||
* RequestOptions.create().setMultipart(
|
||||
* FormData.create().set("fileField", filePayload)));
|
||||
* }</pre>
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @param params Optional request parameters.
|
||||
* @since v1.16
|
||||
*/
|
||||
APIResponse post(String url, RequestOptions params);
|
||||
/**
|
||||
@@ -198,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);
|
||||
@@ -209,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);
|
||||
@@ -221,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,10 +82,11 @@ 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. 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 ColorScheme colorScheme;
|
||||
public Optional<ColorScheme> colorScheme;
|
||||
/**
|
||||
* Specify device scale factor (can be thought of as dpr). Defaults to {@code 1}.
|
||||
*/
|
||||
@@ -93,10 +96,11 @@ 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. 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 ForcedColors forcedColors;
|
||||
public Optional<ForcedColors> forcedColors;
|
||||
public Geolocation geolocation;
|
||||
/**
|
||||
* Specifies if viewport supports touch events. Defaults to false.
|
||||
@@ -111,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;
|
||||
/**
|
||||
@@ -120,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;
|
||||
/**
|
||||
@@ -142,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 persistet 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;
|
||||
/**
|
||||
@@ -170,25 +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. 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 ReducedMotion reducedMotion;
|
||||
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>
|
||||
*/
|
||||
@@ -205,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;
|
||||
/**
|
||||
@@ -221,7 +227,8 @@ 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. {@code null} disables the default
|
||||
* viewport.
|
||||
*/
|
||||
public Optional<ViewportSize> viewportSize;
|
||||
|
||||
@@ -236,11 +243,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>
|
||||
@@ -257,11 +266,12 @@ 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. 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 = colorScheme;
|
||||
this.colorScheme = Optional.ofNullable(colorScheme);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
@@ -279,11 +289,12 @@ 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. 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 = forcedColors;
|
||||
this.forcedColors = Optional.ofNullable(forcedColors);
|
||||
return this;
|
||||
}
|
||||
public NewContextOptions setGeolocation(double latitude, double longitude) {
|
||||
@@ -321,8 +332,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;
|
||||
@@ -336,8 +347,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;
|
||||
@@ -380,17 +391,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 persistet 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;
|
||||
@@ -430,39 +442,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. 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 = 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;
|
||||
@@ -471,8 +484,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>
|
||||
*/
|
||||
@@ -498,9 +511,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;
|
||||
@@ -523,13 +536,15 @@ 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. {@code null} disables the default
|
||||
* viewport.
|
||||
*/
|
||||
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. {@code null} disables the default
|
||||
* viewport.
|
||||
*/
|
||||
public NewContextOptions setViewportSize(ViewportSize viewportSize) {
|
||||
this.viewportSize = Optional.ofNullable(viewportSize);
|
||||
@@ -545,11 +560,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>
|
||||
@@ -560,10 +577,11 @@ 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. 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 ColorScheme colorScheme;
|
||||
public Optional<ColorScheme> colorScheme;
|
||||
/**
|
||||
* Specify device scale factor (can be thought of as dpr). Defaults to {@code 1}.
|
||||
*/
|
||||
@@ -573,10 +591,11 @@ 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. 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 ForcedColors forcedColors;
|
||||
public Optional<ForcedColors> forcedColors;
|
||||
public Geolocation geolocation;
|
||||
/**
|
||||
* Specifies if viewport supports touch events. Defaults to false.
|
||||
@@ -591,8 +610,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;
|
||||
/**
|
||||
@@ -600,8 +619,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;
|
||||
/**
|
||||
@@ -622,14 +641,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 persistet 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;
|
||||
/**
|
||||
@@ -650,25 +670,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. 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 ReducedMotion reducedMotion;
|
||||
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>
|
||||
*/
|
||||
@@ -685,9 +706,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;
|
||||
/**
|
||||
@@ -701,7 +722,8 @@ 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. {@code null} disables the default
|
||||
* viewport.
|
||||
*/
|
||||
public Optional<ViewportSize> viewportSize;
|
||||
|
||||
@@ -716,11 +738,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>
|
||||
@@ -737,11 +761,12 @@ 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. 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 = colorScheme;
|
||||
this.colorScheme = Optional.ofNullable(colorScheme);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
@@ -759,11 +784,12 @@ 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. 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 = forcedColors;
|
||||
this.forcedColors = Optional.ofNullable(forcedColors);
|
||||
return this;
|
||||
}
|
||||
public NewPageOptions setGeolocation(double latitude, double longitude) {
|
||||
@@ -801,8 +827,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;
|
||||
@@ -816,8 +842,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;
|
||||
@@ -860,17 +886,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 persistet 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;
|
||||
@@ -910,39 +937,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. 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 = 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;
|
||||
@@ -951,8 +979,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>
|
||||
*/
|
||||
@@ -978,9 +1006,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;
|
||||
@@ -1003,13 +1031,15 @@ 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. {@code null} disables the default
|
||||
* viewport.
|
||||
*/
|
||||
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. {@code null} disables the default
|
||||
* viewport.
|
||||
*/
|
||||
public NewPageOptions setViewportSize(ViewportSize viewportSize) {
|
||||
this.viewportSize = Optional.ofNullable(viewportSize);
|
||||
@@ -1054,6 +1084,8 @@ public interface Browser extends AutoCloseable {
|
||||
}
|
||||
/**
|
||||
* Get the browser type (chromium, firefox or webkit) that the browser belongs to.
|
||||
*
|
||||
* @since v1.23
|
||||
*/
|
||||
BrowserType browserType();
|
||||
/**
|
||||
@@ -1068,29 +1100,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.
|
||||
@@ -1103,6 +1145,8 @@ public interface Browser extends AutoCloseable {
|
||||
* context.close();
|
||||
* browser.close();
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
default BrowserContext newContext() {
|
||||
return newContext(null);
|
||||
@@ -1110,10 +1154,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.
|
||||
@@ -1126,6 +1172,8 @@ public interface Browser extends AutoCloseable {
|
||||
* context.close();
|
||||
* browser.close();
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
BrowserContext newContext(NewContextOptions options);
|
||||
/**
|
||||
@@ -1134,6 +1182,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);
|
||||
@@ -1144,6 +1194,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);
|
||||
/**
|
||||
@@ -1154,6 +1206,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")));
|
||||
@@ -1162,6 +1216,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);
|
||||
@@ -1174,12 +1229,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);
|
||||
@@ -1192,6 +1251,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")));
|
||||
@@ -1200,6 +1261,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);
|
||||
/**
|
||||
@@ -1209,10 +1271,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);
|
||||
/**
|
||||
@@ -185,7 +185,8 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*/
|
||||
public HarNotFound notFound;
|
||||
/**
|
||||
* If specified, updates the given HAR with the actual network information instead of serving from file.
|
||||
* If specified, updates the given HAR with the actual network information instead of serving from file. The file is
|
||||
* written to disk when {@link BrowserContext#close BrowserContext.close()} is called.
|
||||
*/
|
||||
public Boolean update;
|
||||
/**
|
||||
@@ -207,7 +208,8 @@ public interface BrowserContext extends AutoCloseable {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* If specified, updates the given HAR with the actual network information instead of serving from file.
|
||||
* If specified, updates the given HAR with the actual network information instead of serving from file. The file is
|
||||
* written to disk when {@link BrowserContext#close BrowserContext.close()} is called.
|
||||
*/
|
||||
public RouteFromHAROptions setUpdate(boolean update) {
|
||||
this.update = update;
|
||||
@@ -252,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;
|
||||
|
||||
@@ -265,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;
|
||||
@@ -276,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);
|
||||
/**
|
||||
@@ -292,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.
|
||||
@@ -302,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);
|
||||
/**
|
||||
@@ -315,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.
|
||||
@@ -325,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);
|
||||
@@ -363,6 +387,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* are returned.
|
||||
*
|
||||
* @param urls Optional list of URLs.
|
||||
* @since v1.8
|
||||
*/
|
||||
List<Cookie> cookies(String urls);
|
||||
/**
|
||||
@@ -370,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.*;
|
||||
@@ -404,7 +432,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* "</script>\n" +
|
||||
* "<button onclick=\"onClick()\">Click me</button>\n" +
|
||||
* "<div></div>");
|
||||
* page.locator("button").click();
|
||||
* page.getByRole(AriaRole.BUTTON).click();
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
@@ -427,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.*;
|
||||
@@ -463,7 +494,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* "</script>\n" +
|
||||
* "<button onclick=\"onClick()\">Click me</button>\n" +
|
||||
* "<div></div>");
|
||||
* page.locator("button").click();
|
||||
* page.getByRole(AriaRole.BUTTON).click();
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
@@ -486,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}.
|
||||
*
|
||||
@@ -500,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.*;
|
||||
@@ -533,7 +567,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* "</script>\n" +
|
||||
* "<button onclick=\"onClick()\">Click me</button>\n" +
|
||||
* "<div></div>\n");
|
||||
* page.locator("button").click();
|
||||
* page.getByRole(AriaRole.BUTTON).click();
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
@@ -541,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);
|
||||
/**
|
||||
@@ -565,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);
|
||||
@@ -591,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();
|
||||
/**
|
||||
@@ -613,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();
|
||||
@@ -649,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);
|
||||
@@ -665,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();
|
||||
@@ -701,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);
|
||||
/**
|
||||
@@ -715,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();
|
||||
@@ -751,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);
|
||||
@@ -767,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();
|
||||
@@ -803,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);
|
||||
/**
|
||||
@@ -817,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();
|
||||
@@ -853,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);
|
||||
@@ -869,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();
|
||||
@@ -905,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);
|
||||
/**
|
||||
@@ -919,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);
|
||||
@@ -933,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);
|
||||
/**
|
||||
@@ -953,6 +1016,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* BrowserContext.setDefaultNavigationTimeout()}.
|
||||
*
|
||||
* @param timeout Maximum navigation time in milliseconds
|
||||
* @since v1.8
|
||||
*/
|
||||
void setDefaultNavigationTimeout(double timeout);
|
||||
/**
|
||||
@@ -964,6 +1028,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* BrowserContext.setDefaultTimeout()}.
|
||||
*
|
||||
* @param timeout Maximum time in milliseconds
|
||||
* @since v1.8
|
||||
*/
|
||||
void setDefaultTimeout(double timeout);
|
||||
/**
|
||||
@@ -975,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,
|
||||
@@ -1010,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);
|
||||
@@ -1021,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);
|
||||
/**
|
||||
@@ -1029,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);
|
||||
@@ -1040,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);
|
||||
/**
|
||||
@@ -1048,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);
|
||||
@@ -1059,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,17 +408,18 @@ 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. 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 ColorScheme colorScheme;
|
||||
public Optional<ColorScheme> colorScheme;
|
||||
/**
|
||||
* Specify device scale factor (can be thought of as dpr). Defaults to {@code 1}.
|
||||
*/
|
||||
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;
|
||||
/**
|
||||
@@ -440,10 +443,11 @@ 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. 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 ForcedColors forcedColors;
|
||||
public Optional<ForcedColors> forcedColors;
|
||||
public Geolocation geolocation;
|
||||
/**
|
||||
* Close the browser process on SIGHUP. Defaults to {@code true}.
|
||||
@@ -464,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;
|
||||
/**
|
||||
@@ -473,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;
|
||||
/**
|
||||
@@ -487,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;
|
||||
/**
|
||||
@@ -496,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;
|
||||
/**
|
||||
@@ -514,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 persistet 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;
|
||||
/**
|
||||
@@ -542,25 +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. 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 ReducedMotion reducedMotion;
|
||||
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>
|
||||
*/
|
||||
@@ -570,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;
|
||||
/**
|
||||
@@ -595,7 +601,8 @@ 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. {@code null} disables the default
|
||||
* viewport.
|
||||
*/
|
||||
public Optional<ViewportSize> viewportSize;
|
||||
|
||||
@@ -618,11 +625,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>
|
||||
@@ -665,11 +674,12 @@ 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. 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 = colorScheme;
|
||||
this.colorScheme = Optional.ofNullable(colorScheme);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
@@ -680,8 +690,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;
|
||||
@@ -720,11 +730,12 @@ 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. 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 = forcedColors;
|
||||
this.forcedColors = Optional.ofNullable(forcedColors);
|
||||
return this;
|
||||
}
|
||||
public LaunchPersistentContextOptions setGeolocation(double latitude, double longitude) {
|
||||
@@ -765,8 +776,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;
|
||||
@@ -786,16 +797,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;
|
||||
@@ -809,8 +820,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;
|
||||
@@ -824,8 +835,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;
|
||||
@@ -860,17 +871,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 persistet 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;
|
||||
@@ -910,39 +922,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. 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 = 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;
|
||||
@@ -951,8 +964,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>
|
||||
*/
|
||||
@@ -968,17 +981,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;
|
||||
@@ -1008,13 +1021,15 @@ 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. {@code null} disables the default
|
||||
* viewport.
|
||||
*/
|
||||
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. {@code null} disables the default
|
||||
* viewport.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setViewportSize(ViewportSize viewportSize) {
|
||||
this.viewportSize = Optional.ofNullable(viewportSize);
|
||||
@@ -1022,21 +1037,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);
|
||||
/**
|
||||
@@ -1045,14 +1062,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);
|
||||
@@ -1063,23 +1083,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".
|
||||
@@ -1105,6 +1132,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);
|
||||
@@ -1112,6 +1141,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".
|
||||
@@ -1137,6 +1168,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);
|
||||
/**
|
||||
@@ -1148,8 +1181,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);
|
||||
@@ -1163,12 +1197,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,8 +19,8 @@ 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
|
||||
* page.onConsoleMessage(msg -> System.out.println(msg.text()));
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -27,14 +27,8 @@ import java.nio.file.Path;
|
||||
* <p> Download event is emitted once the download starts. Download path becomes available once download completes:
|
||||
* <pre>{@code
|
||||
* // wait for download to start
|
||||
* Download download = page.waitForDownload(() -> page.locator("a").click());
|
||||
* // wait for download to complete
|
||||
* Path path = download.path();
|
||||
* }</pre>
|
||||
* <pre>{@code
|
||||
* // wait for download to start
|
||||
* Download download = page.waitForDownload(() -> {
|
||||
* page.locator("a").click();
|
||||
* page.getByText("Download file").click();
|
||||
* });
|
||||
* // wait for download to complete
|
||||
* Path path = download.path();
|
||||
@@ -42,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();
|
||||
/**
|
||||
@@ -68,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();
|
||||
/**
|
||||
@@ -75,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.locator("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
@@ -16,14 +16,15 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
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").locator("text=Submit");
|
||||
* Locator locator = page.frameLocator("#my-frame").getByText("Submit");
|
||||
* locator.click();
|
||||
* }</pre>
|
||||
*
|
||||
@@ -33,10 +34,10 @@ import java.util.regex.Pattern;
|
||||
* a given selector.
|
||||
* <pre>{@code
|
||||
* // Throws if there are several frames in DOM:
|
||||
* page.frame_locator(".result-frame").locator("button").click();
|
||||
* page.frame_locator(".result-frame").getByRole(AriaRole.BUTTON).click();
|
||||
*
|
||||
* // Works because we explicitly tell locator to pick the first frame:
|
||||
* page.frame_locator(".result-frame").first().locator("button").click();
|
||||
* page.frame_locator(".result-frame").first().getByRole(AriaRole.BUTTON).click();
|
||||
* }</pre>
|
||||
*
|
||||
* <p> **Converting Locator to FrameLocator**
|
||||
@@ -48,6 +49,240 @@ import java.util.regex.Pattern;
|
||||
* }</pre>
|
||||
*/
|
||||
public interface FrameLocator {
|
||||
class GetByAltTextOptions {
|
||||
/**
|
||||
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
|
||||
* expression. Note that exact match still trims whitespace.
|
||||
*/
|
||||
public Boolean exact;
|
||||
|
||||
/**
|
||||
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
|
||||
* expression. Note that exact match still trims whitespace.
|
||||
*/
|
||||
public GetByAltTextOptions setExact(boolean exact) {
|
||||
this.exact = exact;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class GetByLabelOptions {
|
||||
/**
|
||||
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
|
||||
* expression. Note that exact match still trims whitespace.
|
||||
*/
|
||||
public Boolean exact;
|
||||
|
||||
/**
|
||||
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
|
||||
* expression. Note that exact match still trims whitespace.
|
||||
*/
|
||||
public GetByLabelOptions setExact(boolean exact) {
|
||||
this.exact = exact;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class GetByPlaceholderOptions {
|
||||
/**
|
||||
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
|
||||
* expression. Note that exact match still trims whitespace.
|
||||
*/
|
||||
public Boolean exact;
|
||||
|
||||
/**
|
||||
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
|
||||
* expression. Note that exact match still trims whitespace.
|
||||
*/
|
||||
public GetByPlaceholderOptions setExact(boolean exact) {
|
||||
this.exact = exact;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class GetByRoleOptions {
|
||||
/**
|
||||
* An attribute that is usually set by {@code aria-checked} or native {@code <input type=checkbox>} controls.
|
||||
*
|
||||
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-checked">{@code aria-checked}</a>.
|
||||
*/
|
||||
public Boolean checked;
|
||||
/**
|
||||
* An attribute that is usually set by {@code aria-disabled} or {@code disabled}.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Unlike most other attributes, {@code disabled} is inherited through the DOM hierarchy. Learn more about <a
|
||||
* href="https://www.w3.org/TR/wai-aria-1.2/#aria-disabled">{@code aria-disabled}</a>.
|
||||
*/
|
||||
public Boolean disabled;
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* An attribute that is usually set by {@code aria-expanded}.
|
||||
*
|
||||
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-expanded">{@code aria-expanded}</a>.
|
||||
*/
|
||||
public Boolean expanded;
|
||||
/**
|
||||
* Option that controls whether hidden elements are matched. By default, only non-hidden elements, as <a
|
||||
* href="https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion">defined by ARIA</a>, are matched by role selector.
|
||||
*
|
||||
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-hidden">{@code aria-hidden}</a>.
|
||||
*/
|
||||
public Boolean includeHidden;
|
||||
/**
|
||||
* A number attribute that is usually present for roles {@code heading}, {@code listitem}, {@code row}, {@code treeitem},
|
||||
* with default values for {@code <h1>-<h6>} elements.
|
||||
*
|
||||
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-level">{@code aria-level}</a>.
|
||||
*/
|
||||
public Integer level;
|
||||
/**
|
||||
* Option to match the <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>. By default,
|
||||
* matching is case-insensitive and searches for a substring, use {@code exact} to control this behavior.
|
||||
*
|
||||
* <p> Learn more about <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
|
||||
*/
|
||||
public Object name;
|
||||
/**
|
||||
* An attribute that is usually set by {@code aria-pressed}.
|
||||
*
|
||||
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-pressed">{@code aria-pressed}</a>.
|
||||
*/
|
||||
public Boolean pressed;
|
||||
/**
|
||||
* An attribute that is usually set by {@code aria-selected}.
|
||||
*
|
||||
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-selected">{@code aria-selected}</a>.
|
||||
*/
|
||||
public Boolean selected;
|
||||
|
||||
/**
|
||||
* An attribute that is usually set by {@code aria-checked} or native {@code <input type=checkbox>} controls.
|
||||
*
|
||||
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-checked">{@code aria-checked}</a>.
|
||||
*/
|
||||
public GetByRoleOptions setChecked(boolean checked) {
|
||||
this.checked = checked;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* An attribute that is usually set by {@code aria-disabled} or {@code disabled}.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Unlike most other attributes, {@code disabled} is inherited through the DOM hierarchy. Learn more about <a
|
||||
* href="https://www.w3.org/TR/wai-aria-1.2/#aria-disabled">{@code aria-disabled}</a>.
|
||||
*/
|
||||
public GetByRoleOptions setDisabled(boolean disabled) {
|
||||
this.disabled = disabled;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 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;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* An attribute that is usually set by {@code aria-expanded}.
|
||||
*
|
||||
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-expanded">{@code aria-expanded}</a>.
|
||||
*/
|
||||
public GetByRoleOptions setExpanded(boolean expanded) {
|
||||
this.expanded = expanded;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Option that controls whether hidden elements are matched. By default, only non-hidden elements, as <a
|
||||
* href="https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion">defined by ARIA</a>, are matched by role selector.
|
||||
*
|
||||
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-hidden">{@code aria-hidden}</a>.
|
||||
*/
|
||||
public GetByRoleOptions setIncludeHidden(boolean includeHidden) {
|
||||
this.includeHidden = includeHidden;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* A number attribute that is usually present for roles {@code heading}, {@code listitem}, {@code row}, {@code treeitem},
|
||||
* with default values for {@code <h1>-<h6>} elements.
|
||||
*
|
||||
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-level">{@code aria-level}</a>.
|
||||
*/
|
||||
public GetByRoleOptions setLevel(int level) {
|
||||
this.level = level;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Option to match the <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>. By default,
|
||||
* matching is case-insensitive and searches for a substring, use {@code exact} to control this behavior.
|
||||
*
|
||||
* <p> Learn more about <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
|
||||
*/
|
||||
public GetByRoleOptions setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Option to match the <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>. By default,
|
||||
* matching is case-insensitive and searches for a substring, use {@code exact} to control this behavior.
|
||||
*
|
||||
* <p> Learn more about <a href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>.
|
||||
*/
|
||||
public GetByRoleOptions setName(Pattern name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* An attribute that is usually set by {@code aria-pressed}.
|
||||
*
|
||||
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-pressed">{@code aria-pressed}</a>.
|
||||
*/
|
||||
public GetByRoleOptions setPressed(boolean pressed) {
|
||||
this.pressed = pressed;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* An attribute that is usually set by {@code aria-selected}.
|
||||
*
|
||||
* <p> Learn more about <a href="https://www.w3.org/TR/wai-aria-1.2/#aria-selected">{@code aria-selected}</a>.
|
||||
*/
|
||||
public GetByRoleOptions setSelected(boolean selected) {
|
||||
this.selected = selected;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class GetByTextOptions {
|
||||
/**
|
||||
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
|
||||
* expression. Note that exact match still trims whitespace.
|
||||
*/
|
||||
public Boolean exact;
|
||||
|
||||
/**
|
||||
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
|
||||
* expression. Note that exact match still trims whitespace.
|
||||
*/
|
||||
public GetByTextOptions setExact(boolean exact) {
|
||||
this.exact = exact;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class GetByTitleOptions {
|
||||
/**
|
||||
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
|
||||
* expression. Note that exact match still trims whitespace.
|
||||
*/
|
||||
public Boolean exact;
|
||||
|
||||
/**
|
||||
* Whether to find an exact match: case-sensitive and whole-string. Default to false. Ignored when locating by a regular
|
||||
* expression. Note that exact match still trims whitespace.
|
||||
*/
|
||||
public GetByTitleOptions setExact(boolean exact) {
|
||||
this.exact = exact;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class LocatorOptions {
|
||||
/**
|
||||
* Matches elements containing an element that matches an inner locator. Inner locator is queried against the outer one.
|
||||
@@ -58,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;
|
||||
|
||||
@@ -75,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;
|
||||
@@ -84,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;
|
||||
@@ -94,38 +329,376 @@ 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":
|
||||
*
|
||||
* @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":
|
||||
*
|
||||
* @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":
|
||||
*
|
||||
* @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":
|
||||
*
|
||||
* @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:
|
||||
*
|
||||
* @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:
|
||||
*
|
||||
* @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:
|
||||
*
|
||||
* @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:
|
||||
*
|
||||
* @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":
|
||||
*
|
||||
* @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":
|
||||
*
|
||||
* @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":
|
||||
*
|
||||
* @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":
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* <p> Note that many html elements have an implicitly <a
|
||||
* href="https://w3c.github.io/html-aam/#html-element-role-mappings">defined role</a> that is recognized by the role
|
||||
* selector. You can find all the <a href="https://www.w3.org/TR/wai-aria-1.2/#role_definitions">supported roles here</a>.
|
||||
* ARIA guidelines **do not recommend** duplicating implicit roles and attributes by setting {@code role} and/or {@code
|
||||
* aria-*} attributes to default values.
|
||||
*
|
||||
* @param role Required aria role.
|
||||
* @since v1.27
|
||||
*/
|
||||
default Locator getByRole(AriaRole role) {
|
||||
return getByRole(role, null);
|
||||
}
|
||||
/**
|
||||
* Allows locating elements by their <a href="https://www.w3.org/TR/wai-aria-1.2/#roles">ARIA role</a>, <a
|
||||
* href="https://www.w3.org/TR/wai-aria-1.2/#aria-attributes">ARIA attributes</a> and <a
|
||||
* href="https://w3c.github.io/accname/#dfn-accessible-name">accessible name</a>. Note that role selector **does not
|
||||
* replace** accessibility audits and conformance tests, but rather gives early feedback about the ARIA guidelines.
|
||||
*
|
||||
* <p> Note that many html elements have an implicitly <a
|
||||
* href="https://w3c.github.io/html-aam/#html-element-role-mappings">defined role</a> that is recognized by the role
|
||||
* selector. You can find all the <a href="https://www.w3.org/TR/wai-aria-1.2/#role_definitions">supported roles here</a>.
|
||||
* ARIA guidelines **do not recommend** duplicating implicit roles and attributes by setting {@code role} and/or {@code
|
||||
* aria-*} attributes to default values.
|
||||
*
|
||||
* @param role Required aria role.
|
||||
* @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.
|
||||
*
|
||||
* @param testId Id to locate the element by.
|
||||
* @since v1.27
|
||||
*/
|
||||
Locator getByTestId(String testId);
|
||||
/**
|
||||
* Locate element by the test id. By default, the {@code data-testid} attribute is used as a test id. Use {@link
|
||||
* Selectors#setTestIdAttribute Selectors.setTestIdAttribute()} to configure a different test id attribute if necessary.
|
||||
*
|
||||
* @param testId Id to locate the element by.
|
||||
* @since v1.27
|
||||
*/
|
||||
Locator getByTestId(Pattern testId);
|
||||
/**
|
||||
* Allows locating elements that contain given text. Consider the following DOM structure:
|
||||
*
|
||||
* <p> You can locate by text substring, exact string, or a regular expression:
|
||||
* <pre>{@code
|
||||
* // Matches <span>
|
||||
* page.getByText("world")
|
||||
*
|
||||
* // Matches first <div>
|
||||
* page.getByText("Hello world")
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true))
|
||||
*
|
||||
* // Matches both <div>s
|
||||
* page.getByText(Pattern.compile("Hello"))
|
||||
*
|
||||
* // Matches second <div>
|
||||
* 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> <strong>NOTE:</strong> 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">}.
|
||||
*
|
||||
* @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:
|
||||
*
|
||||
* <p> You can locate by text substring, exact string, or a regular expression:
|
||||
* <pre>{@code
|
||||
* // Matches <span>
|
||||
* page.getByText("world")
|
||||
*
|
||||
* // Matches first <div>
|
||||
* page.getByText("Hello world")
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true))
|
||||
*
|
||||
* // Matches both <div>s
|
||||
* page.getByText(Pattern.compile("Hello"))
|
||||
*
|
||||
* // Matches second <div>
|
||||
* 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> <strong>NOTE:</strong> 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">}.
|
||||
*
|
||||
* @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:
|
||||
*
|
||||
* <p> You can locate by text substring, exact string, or a regular expression:
|
||||
* <pre>{@code
|
||||
* // Matches <span>
|
||||
* page.getByText("world")
|
||||
*
|
||||
* // Matches first <div>
|
||||
* page.getByText("Hello world")
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true))
|
||||
*
|
||||
* // Matches both <div>s
|
||||
* page.getByText(Pattern.compile("Hello"))
|
||||
*
|
||||
* // Matches second <div>
|
||||
* 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> <strong>NOTE:</strong> 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">}.
|
||||
*
|
||||
* @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:
|
||||
*
|
||||
* <p> You can locate by text substring, exact string, or a regular expression:
|
||||
* <pre>{@code
|
||||
* // Matches <span>
|
||||
* page.getByText("world")
|
||||
*
|
||||
* // Matches first <div>
|
||||
* page.getByText("Hello world")
|
||||
*
|
||||
* // Matches second <div>
|
||||
* page.getByText("Hello", new Page.GetByTextOptions().setExact(true))
|
||||
*
|
||||
* // Matches both <div>s
|
||||
* page.getByText(Pattern.compile("Hello"))
|
||||
*
|
||||
* // Matches second <div>
|
||||
* 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> <strong>NOTE:</strong> 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">}.
|
||||
*
|
||||
* @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":
|
||||
*
|
||||
* @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":
|
||||
*
|
||||
* @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":
|
||||
*
|
||||
* @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":
|
||||
*
|
||||
* @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();
|
||||
/**
|
||||
* The method finds an element matching the specified selector in the FrameLocator's subtree.
|
||||
* The method finds an element matching the specified selector in the locator's subtree. It also accepts filter options,
|
||||
* similar to {@link Locator#filter Locator.filter()} method.
|
||||
*
|
||||
* @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.
|
||||
* <p> <a href="https://playwright.dev/java/docs/locators">Learn more about locators</a>.
|
||||
*
|
||||
* @param selector A selector to use when resolving DOM element.
|
||||
* @since v1.17
|
||||
*/
|
||||
default Locator locator(String selector) {
|
||||
return locator(selector, null);
|
||||
}
|
||||
/**
|
||||
* The method finds an element matching the specified selector in the FrameLocator's subtree.
|
||||
* The method finds an element matching the specified selector in the locator's subtree. It also accepts filter options,
|
||||
* similar to {@link Locator#filter Locator.filter()} method.
|
||||
*
|
||||
* @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.
|
||||
* <p> <a href="https://playwright.dev/java/docs/locators">Learn more about locators</a>.
|
||||
*
|
||||
* @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,17 +52,18 @@ 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"));
|
||||
* }</pre>
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
|
||||
* as a function. Otherwise, evaluated as an expression.
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
* @since v1.8
|
||||
*/
|
||||
default Object evaluate(String expression) {
|
||||
return evaluate(expression, null);
|
||||
@@ -69,18 +74,19 @@ 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"));
|
||||
* }</pre>
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
|
||||
* as a function. Otherwise, evaluated as an expression.
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the 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 it looks like a function declaration, it is interpreted
|
||||
* as a function. Otherwise, evaluated as an expression.
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the 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 it looks like a function declaration, it is interpreted
|
||||
* as a function. Otherwise, evaluated as an expression.
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the 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 keydown, keypress/input, and 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,27 +58,39 @@ 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();
|
||||
/**
|
||||
@@ -91,6 +103,8 @@ public interface Playwright extends AutoCloseable {
|
||||
* 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 '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,60 @@ 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;
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
/**
|
||||
* 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 +208,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 +251,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 +276,8 @@ public interface Route {
|
||||
}
|
||||
/**
|
||||
* Aborts the route's request.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
default void abort() {
|
||||
abort(null);
|
||||
@@ -233,11 +289,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 +304,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 +320,16 @@ public interface Route {
|
||||
* route.resume(new Route.ResumeOptions().setHeaders(headers));
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* @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 +339,8 @@ public interface Route {
|
||||
* route.resume(new Route.ResumeOptions().setHeaders(headers));
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
void resume(ResumeOptions options);
|
||||
/**
|
||||
@@ -283,6 +348,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 +402,8 @@ public interface Route {
|
||||
* route.fallback(new Route.ResumeOptions().setHeaders(headers));
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.23
|
||||
*/
|
||||
default void fallback() {
|
||||
fallback(null);
|
||||
@@ -344,6 +413,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 +467,57 @@ 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>
|
||||
*
|
||||
* @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>
|
||||
*
|
||||
* @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 +533,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 +542,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 +559,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,9 @@ public interface Selectors {
|
||||
}
|
||||
}
|
||||
/**
|
||||
* An example of registering selector engine that queries elements based on a tag name:
|
||||
* **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" +
|
||||
@@ -69,15 +71,18 @@ public interface Selectors {
|
||||
* 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:
|
||||
* **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" +
|
||||
@@ -104,13 +109,16 @@ public interface Selectors {
|
||||
* 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:
|
||||
* **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" +
|
||||
@@ -137,15 +145,18 @@ public interface Selectors {
|
||||
* 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:
|
||||
* **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" +
|
||||
@@ -172,10 +183,19 @@ public interface Selectors {
|
||||
* 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);
|
||||
/**
|
||||
* Defines custom attribute name to be used in {@link Page#getByTestId Page.getByTestId()}. {@code data-testid} is used by
|
||||
* default.
|
||||
*
|
||||
* @param attributeName Test id attribute name.
|
||||
* @since v1.27
|
||||
*/
|
||||
void setTestIdAttribute(String attributeName);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ 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}).
|
||||
*
|
||||
* @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)
|
||||
@@ -192,7 +202,7 @@ public interface Tracing {
|
||||
* page.navigate("https://playwright.dev");
|
||||
*
|
||||
* context.tracing().startChunk();
|
||||
* page.locator("text=Get Started").click();
|
||||
* page.getByText("Get Started").click();
|
||||
* // Everything between startChunk and stopChunk will be recorded in the trace.
|
||||
* context.tracing().stopChunk(new Tracing.StopChunkOptions()
|
||||
* .setPath(Paths.get("trace1.zip")));
|
||||
@@ -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)
|
||||
@@ -219,7 +233,7 @@ public interface Tracing {
|
||||
* page.navigate("https://playwright.dev");
|
||||
*
|
||||
* context.tracing().startChunk();
|
||||
* page.locator("text=Get Started").click();
|
||||
* page.getByText("Get Started").click();
|
||||
* // Everything between startChunk and stopChunk will be recorded in the trace.
|
||||
* context.tracing().stopChunk(new Tracing.StopChunkOptions()
|
||||
* .setPath(Paths.get("trace1.zip")));
|
||||
@@ -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 it looks like a function declaration, it is interpreted
|
||||
* as a function. Otherwise, evaluated as an expression.
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the 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 it looks like a function declaration, it is interpreted
|
||||
* as a function. Otherwise, evaluated as an expression.
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the 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);
|
||||
/**
|
||||
@@ -103,8 +105,9 @@ public interface Worker {
|
||||
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then {@link
|
||||
* Worker#evaluateHandle Worker.evaluateHandle()} would wait for the promise to resolve and return its value.
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
|
||||
* as a function. Otherwise, evaluated as an expression.
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
* @since v1.8
|
||||
*/
|
||||
default JSHandle evaluateHandle(String expression) {
|
||||
return evaluateHandle(expression, null);
|
||||
@@ -119,16 +122,23 @@ public interface Worker {
|
||||
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then {@link
|
||||
* Worker#evaluateHandle Worker.evaluateHandle()} would wait for the promise to resolve and return its value.
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
|
||||
* as a function. Otherwise, evaluated as an expression.
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the 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);
|
||||
}
|
||||
|
||||
+9
-3
@@ -18,9 +18,9 @@ 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. A new instance of {@code APIResponseAssertions} is created by calling {@link
|
||||
* PlaywrightAssertions#assertThat PlaywrightAssertions.assertThat()}:
|
||||
* <pre>{@code
|
||||
* ...
|
||||
* import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
||||
@@ -43,13 +43,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();
|
||||
}
|
||||
|
||||
+320
-100
File diff suppressed because it is too large
Load Diff
@@ -19,9 +19,9 @@ 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. A new instance of {@code PageAssertions} is created by calling {@link
|
||||
* PlaywrightAssertions#assertThat PlaywrightAssertions.assertThat()}:
|
||||
* <pre>{@code
|
||||
* ...
|
||||
* import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
||||
@@ -31,7 +31,7 @@ import java.util.regex.Pattern;
|
||||
* @Test
|
||||
* void navigatesToLoginPage() {
|
||||
* ...
|
||||
* page.locator("#login").click();
|
||||
* page.getByText("Sign in").click();
|
||||
* assertThat(page).hasURL(Pattern.compile(".*\/login"));
|
||||
* }
|
||||
* }
|
||||
@@ -72,86 +72,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);
|
||||
}
|
||||
|
||||
+15
-3
@@ -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);
|
||||
|
||||
@@ -26,7 +26,6 @@ import java.nio.file.Path;
|
||||
import static com.microsoft.playwright.impl.Utils.writeToFile;
|
||||
|
||||
class ArtifactImpl extends ChannelOwner {
|
||||
boolean isRemote;
|
||||
public ArtifactImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
}
|
||||
@@ -57,7 +56,7 @@ class ArtifactImpl extends ChannelOwner {
|
||||
}
|
||||
|
||||
public Path pathAfterFinished() {
|
||||
if (isRemote) {
|
||||
if (connection.isRemote) {
|
||||
throw new PlaywrightException("Path is not available when using browserType.connect(). Use download.saveAs() to save a local copy.");
|
||||
}
|
||||
JsonObject json = sendMessage("pathAfterFinished").getAsJsonObject();
|
||||
@@ -65,7 +64,7 @@ class ArtifactImpl extends ChannelOwner {
|
||||
}
|
||||
|
||||
public void saveAs(Path path) {
|
||||
if (isRemote) {
|
||||
if (connection.isRemote) {
|
||||
JsonObject jsonObject = sendMessage("saveAsStream").getAsJsonObject();
|
||||
Stream stream = connection.getExistingObject(jsonObject.getAsJsonObject("stream").get("guid").getAsString());
|
||||
writeToFile(stream.stream(), path);
|
||||
|
||||
@@ -49,7 +49,15 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
private boolean isClosedOrClosing;
|
||||
final Map<String, BindingCallback> bindings = new HashMap<>();
|
||||
PageImpl ownerPage;
|
||||
private final ListenerCollection<EventType> listeners = new ListenerCollection<>();
|
||||
private static final Map<EventType, String> eventSubscriptions() {
|
||||
Map<EventType, String> result = new HashMap<>();
|
||||
result.put(EventType.REQUEST, "request");
|
||||
result.put(EventType.RESPONSE, "response");
|
||||
result.put(EventType.REQUESTFINISHED, "requestFinished");
|
||||
result.put(EventType.REQUESTFAILED, "requestFailed");
|
||||
return result;
|
||||
}
|
||||
private final ListenerCollection<EventType> listeners = new ListenerCollection<>(eventSubscriptions(), this);
|
||||
final TimeoutSettings timeoutSettings = new TimeoutSettings();
|
||||
Path videosDir;
|
||||
URL baseUrl;
|
||||
@@ -82,7 +90,6 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
browser = null;
|
||||
}
|
||||
this.tracing = connection.getExistingObject(initializer.getAsJsonObject("tracing").get("guid").getAsString());
|
||||
tracing.isRemote = browser != null && browser.isRemote;
|
||||
this.request = connection.getExistingObject(initializer.getAsJsonObject("requestContext").get("guid").getAsString());
|
||||
}
|
||||
|
||||
@@ -201,12 +208,6 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
params.addProperty("harId", entry.getKey());
|
||||
JsonObject json = sendMessage("harExport", params).getAsJsonObject();
|
||||
ArtifactImpl artifact = connection.getExistingObject(json.getAsJsonObject("artifact").get("guid").getAsString());
|
||||
// In case of CDP connection browser is null but since the connection is established by
|
||||
// the driver it is safe to consider the artifact local.
|
||||
if (browser() != null && browser().isRemote) {
|
||||
artifact.isRemote = true;
|
||||
}
|
||||
|
||||
// Server side will compress artifact if content is attach or if file is .zip.
|
||||
HarRecorder harParams = entry.getValue();
|
||||
boolean isCompressed = harParams.contentPolicy == HarContentPolicy.ATTACH || harParams.path.toString().endsWith(".zip");
|
||||
@@ -538,10 +539,10 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
|
||||
void handleRoute(RouteImpl route) {
|
||||
Router.HandleResult handled = routes.handle(route);
|
||||
if (handled == Router.HandleResult.FoundMatchingHandler) {
|
||||
if (handled != Router.HandleResult.NoMatchingHandler) {
|
||||
maybeDisableNetworkInterception();
|
||||
}
|
||||
if (!route.isHandled()){
|
||||
if (handled == Router.HandleResult.NoMatchingHandler || handled == Router.HandleResult.Fallback) {
|
||||
route.resume();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ import static com.microsoft.playwright.impl.Utils.convertType;
|
||||
class BrowserImpl extends ChannelOwner implements Browser {
|
||||
final Set<BrowserContextImpl> contexts = new HashSet<>();
|
||||
private final ListenerCollection<EventType> listeners = new ListenerCollection<>();
|
||||
boolean isRemote;
|
||||
boolean isConnectedOverWebSocket;
|
||||
private boolean isConnected = true;
|
||||
BrowserTypeImpl browserType;
|
||||
|
||||
@@ -83,9 +83,9 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
|
||||
headers.addProperty("x-playwright-browser", name());
|
||||
}
|
||||
|
||||
JsonObject json = sendMessage("connect", params).getAsJsonObject();
|
||||
JsonObject json = connection.localUtils().sendMessage("connect", params).getAsJsonObject();
|
||||
JsonPipe pipe = connection.getExistingObject(json.getAsJsonObject("pipe").get("guid").getAsString());
|
||||
Connection connection = new Connection(pipe, this.connection.env);
|
||||
Connection connection = new Connection(pipe, this.connection.env, this.connection.localUtils);
|
||||
PlaywrightImpl playwright = connection.initializePlaywright();
|
||||
if (!playwright.initializer.has("preLaunchedBrowser")) {
|
||||
try {
|
||||
@@ -97,7 +97,6 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
|
||||
}
|
||||
playwright.initSharedSelectors(this.connection.getExistingObject("Playwright"));
|
||||
BrowserImpl browser = connection.getExistingObject(playwright.initializer.getAsJsonObject("preLaunchedBrowser").get("guid").getAsString());
|
||||
browser.isRemote = true;
|
||||
browser.isConnectedOverWebSocket = true;
|
||||
browser.browserType = this;
|
||||
Consumer<JsonPipe> connectionCloseListener = t -> browser.notifyRemoteClosed();
|
||||
@@ -132,7 +131,6 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
|
||||
JsonObject json = sendMessage("connectOverCDP", params).getAsJsonObject();
|
||||
|
||||
BrowserImpl browser = connection.getExistingObject(json.getAsJsonObject("browser").get("guid").getAsString());
|
||||
browser.isRemote = true;
|
||||
browser.browserType = this;
|
||||
if (json.has("defaultContext")) {
|
||||
String contextId = json.getAsJsonObject("defaultContext").get("guid").getAsString();
|
||||
|
||||
@@ -55,6 +55,7 @@ public class Connection {
|
||||
private final Transport transport;
|
||||
private final Map<String, ChannelOwner> objects = new HashMap<>();
|
||||
private final Root root;
|
||||
final boolean isRemote;
|
||||
private int lastId = 0;
|
||||
private final StackTraceCollector stackTraceCollector;
|
||||
private final Map<Integer, WaitableResult<JsonElement>> callbacks = new HashMap<>();
|
||||
@@ -80,8 +81,18 @@ public class Connection {
|
||||
}
|
||||
}
|
||||
|
||||
Connection(Transport pipe, Map<String, String> env, LocalUtils localUtils) {
|
||||
this(pipe, env, true);
|
||||
this.localUtils = localUtils;
|
||||
}
|
||||
|
||||
Connection(Transport transport, Map<String, String> env) {
|
||||
this(transport, env, false);
|
||||
}
|
||||
|
||||
private Connection(Transport transport, Map<String, String> env, boolean isRemote) {
|
||||
this.env = env;
|
||||
this.isRemote = isRemote;
|
||||
if (isLogging) {
|
||||
transport = new TransportLogger(transport);
|
||||
}
|
||||
@@ -283,8 +294,10 @@ public class Connection {
|
||||
result = new JsonPipe(parent, type, guid, initializer);
|
||||
break;
|
||||
case "LocalUtils":
|
||||
localUtils = new LocalUtils(parent, type, guid, initializer);
|
||||
result = localUtils;
|
||||
result = new LocalUtils(parent, type, guid, initializer);
|
||||
if (localUtils == null) {
|
||||
localUtils = (LocalUtils) result;
|
||||
}
|
||||
break;
|
||||
case "Page":
|
||||
result = new PageImpl(parent, type, guid, initializer);
|
||||
@@ -307,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
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.microsoft.playwright.impl.LocatorUtils.*;
|
||||
import static com.microsoft.playwright.impl.Utils.*;
|
||||
import static com.microsoft.playwright.options.WaitUntilState.*;
|
||||
import static com.microsoft.playwright.impl.Serialization.*;
|
||||
@@ -109,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
|
||||
@@ -373,6 +370,71 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
return withLogging("Frame.getAttribute", () -> getAttributeImpl(selector, name, options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByAltText(String text, GetByAltTextOptions options) {
|
||||
return locator(getByAltTextSelector(text, convertType(options, Locator.GetByAltTextOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByAltText(Pattern text, GetByAltTextOptions options) {
|
||||
return locator(getByAltTextSelector(text, convertType(options, Locator.GetByAltTextOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByLabel(String text, GetByLabelOptions options) {
|
||||
return locator(getByLabelSelector(text, convertType(options, Locator.GetByLabelOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByLabel(Pattern text, GetByLabelOptions options) {
|
||||
return locator(getByLabelSelector(text, convertType(options, Locator.GetByLabelOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByPlaceholder(String text, GetByPlaceholderOptions options) {
|
||||
return locator(getByPlaceholderSelector(text, convertType(options, Locator.GetByPlaceholderOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByPlaceholder(Pattern text, GetByPlaceholderOptions options) {
|
||||
return locator(getByPlaceholderSelector(text, convertType(options, Locator.GetByPlaceholderOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByRole(AriaRole role, GetByRoleOptions options) {
|
||||
return locator(getByRoleSelector(role, convertType(options, Locator.GetByRoleOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByTestId(String testId) {
|
||||
return locator(getByTestIdSelector(testId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByTestId(Pattern testId) {
|
||||
return locator(getByTestIdSelector(testId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByText(String text, GetByTextOptions options) {
|
||||
return locator(getByTextSelector(text, convertType(options, Locator.GetByTextOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByText(Pattern text, GetByTextOptions options) {
|
||||
return locator(getByTextSelector(text, convertType(options, Locator.GetByTextOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByTitle(String text, GetByTitleOptions options) {
|
||||
return locator(getByTitleSelector(text, convertType(options, Locator.GetByTitleOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByTitle(Pattern text, GetByTitleOptions options) {
|
||||
return locator(getByTitleSelector(text, convertType(options, Locator.GetByTitleOptions.class)));
|
||||
}
|
||||
|
||||
String getAttributeImpl(String selector, String name, GetAttributeOptions options) {
|
||||
if (options == null) {
|
||||
options = new GetAttributeOptions();
|
||||
@@ -627,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));
|
||||
|
||||
@@ -18,7 +18,11 @@ package com.microsoft.playwright.impl;
|
||||
|
||||
import com.microsoft.playwright.FrameLocator;
|
||||
import com.microsoft.playwright.Locator;
|
||||
import com.microsoft.playwright.options.AriaRole;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.microsoft.playwright.impl.LocatorUtils.*;
|
||||
import static com.microsoft.playwright.impl.Utils.convertType;
|
||||
|
||||
class FrameLocatorImpl implements FrameLocator {
|
||||
@@ -37,7 +41,72 @@ class FrameLocatorImpl implements FrameLocator {
|
||||
|
||||
@Override
|
||||
public FrameLocatorImpl frameLocator(String selector) {
|
||||
return new FrameLocatorImpl(frame, frameSelector + " >> control=enter-frame >> " + selector);
|
||||
return new FrameLocatorImpl(frame, frameSelector + " >> internal:control=enter-frame >> " + selector);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByAltText(String text, GetByAltTextOptions options) {
|
||||
return locator(getByAltTextSelector(text, convertType(options, Locator.GetByAltTextOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByAltText(Pattern text, GetByAltTextOptions options) {
|
||||
return locator(getByAltTextSelector(text, convertType(options, Locator.GetByAltTextOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByLabel(String text, GetByLabelOptions options) {
|
||||
return locator(getByLabelSelector(text, convertType(options, Locator.GetByLabelOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByLabel(Pattern text, GetByLabelOptions options) {
|
||||
return locator(getByLabelSelector(text, convertType(options, Locator.GetByLabelOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByPlaceholder(String text, GetByPlaceholderOptions options) {
|
||||
return locator(getByPlaceholderSelector(text, convertType(options, Locator.GetByPlaceholderOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByPlaceholder(Pattern text, GetByPlaceholderOptions options) {
|
||||
return locator(getByPlaceholderSelector(text, convertType(options, Locator.GetByPlaceholderOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByRole(AriaRole role, GetByRoleOptions options) {
|
||||
return locator(getByRoleSelector(role, convertType(options, Locator.GetByRoleOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByTestId(String testId) {
|
||||
return locator(getByTestIdSelector(testId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByTestId(Pattern testId) {
|
||||
return locator(getByTestIdSelector(testId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByText(String text, GetByTextOptions options) {
|
||||
return locator(getByTextSelector(text, convertType(options, Locator.GetByTextOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByText(Pattern text, GetByTextOptions options) {
|
||||
return locator(getByTextSelector(text, convertType(options, Locator.GetByTextOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByTitle(String text, GetByTitleOptions options) {
|
||||
return locator(getByTitleSelector(text, convertType(options, Locator.GetByTitleOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByTitle(Pattern text, GetByTitleOptions options) {
|
||||
return locator(getByTitleSelector(text, convertType(options, Locator.GetByTitleOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -47,7 +116,7 @@ class FrameLocatorImpl implements FrameLocator {
|
||||
|
||||
@Override
|
||||
public Locator locator(String selector, LocatorOptions options) {
|
||||
return new LocatorImpl(frame, frameSelector + " >> control=enter-frame >> " + selector, convertType(options, Locator.LocatorOptions.class));
|
||||
return new LocatorImpl(frame, frameSelector + " >> internal:control=enter-frame >> " + selector, convertType(options, Locator.LocatorOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,14 +16,23 @@
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
class ListenerCollection <EventType> {
|
||||
private final HashMap<EventType, List<Consumer<?>>> listeners = new HashMap<>();
|
||||
private final Map<EventType, String> eventSubscriptions;
|
||||
private final ChannelOwner channelOwner;
|
||||
|
||||
ListenerCollection() {
|
||||
this(null, null);
|
||||
}
|
||||
ListenerCollection(Map<EventType, String> eventSubscriptions, ChannelOwner channelOwner) {
|
||||
this.eventSubscriptions = eventSubscriptions;
|
||||
this.channelOwner = channelOwner;
|
||||
}
|
||||
|
||||
<T> void notify(EventType eventType, T param) {
|
||||
List<Consumer<?>> list = listeners.get(eventType);
|
||||
@@ -41,6 +50,7 @@ class ListenerCollection <EventType> {
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
listeners.put(type, list);
|
||||
updateSubscription(type, true);
|
||||
}
|
||||
list.add(listener);
|
||||
}
|
||||
@@ -52,6 +62,7 @@ class ListenerCollection <EventType> {
|
||||
}
|
||||
list.removeAll(Collections.singleton(listener));
|
||||
if (list.isEmpty()) {
|
||||
updateSubscription(type, false);
|
||||
listeners.remove(type);
|
||||
}
|
||||
}
|
||||
@@ -59,4 +70,18 @@ class ListenerCollection <EventType> {
|
||||
boolean hasListeners(EventType type) {
|
||||
return listeners.containsKey(type);
|
||||
}
|
||||
|
||||
private void updateSubscription(EventType eventType, boolean enabled) {
|
||||
if (eventSubscriptions == null) {
|
||||
return;
|
||||
}
|
||||
String protocolEvent = eventSubscriptions.get(eventType);
|
||||
if (protocolEvent == null) {
|
||||
return;
|
||||
}
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("event", protocolEvent);
|
||||
params.addProperty("enabled", enabled);
|
||||
channelOwner.sendMessageAsync("updateSubscription", params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,19 +3,18 @@ package com.microsoft.playwright.impl;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.*;
|
||||
import com.microsoft.playwright.options.BoundingBox;
|
||||
import com.microsoft.playwright.options.FilePayload;
|
||||
import com.microsoft.playwright.options.SelectOption;
|
||||
import com.microsoft.playwright.options.WaitForSelectorState;
|
||||
import com.microsoft.playwright.options.*;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.microsoft.playwright.impl.LocatorUtils.*;
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
import static com.microsoft.playwright.impl.Utils.convertType;
|
||||
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
|
||||
@@ -24,57 +23,18 @@ class LocatorImpl implements Locator {
|
||||
private final FrameImpl frame;
|
||||
private final String selector;
|
||||
|
||||
private static class Filters {
|
||||
private final Map<Field, String> filterFieldToEngine = new LinkedHashMap<>();
|
||||
private void addFilter(String name, String engine) throws NoSuchFieldException {
|
||||
filterFieldToEngine.put(LocatorOptions.class.getField(name), engine);
|
||||
}
|
||||
{
|
||||
try {
|
||||
addFilter("has", "has");
|
||||
// addFilter("leftOf", "left-of");
|
||||
// addFilter("rightOf", "right-of");
|
||||
// addFilter("above", "above");
|
||||
// addFilter("below", "below");
|
||||
// addFilter("near", "near");
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
String addFiltersToSelector(String selector, LocatorOptions options, Frame frame) {
|
||||
try {
|
||||
for (Map.Entry<Field, String> p : filterFieldToEngine.entrySet()) {
|
||||
LocatorImpl filter = (LocatorImpl) p.getKey().get(options);
|
||||
if (filter == null) {
|
||||
continue;
|
||||
}
|
||||
if (filter.frame != frame) {
|
||||
throw new PlaywrightException("Inner '" + p.getKey().getName() + "' locator must belong to the same frame.");
|
||||
}
|
||||
selector += " >> " + p.getValue() + "=" + gson().toJson(filter.selector);
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new PlaywrightException("Unexpected options", e);
|
||||
}
|
||||
return selector;
|
||||
}
|
||||
}
|
||||
private static final Filters filters = new Filters();
|
||||
|
||||
public LocatorImpl(FrameImpl frame, String selector, LocatorOptions options) {
|
||||
this.frame = frame;
|
||||
if (options != null) {
|
||||
if (options.hasText != null) {
|
||||
if (options.hasText instanceof Pattern) {
|
||||
Pattern pattern = (Pattern) options.hasText;
|
||||
String jsRegex = "/" + pattern.pattern() + "/" + toJsRegexFlags(pattern);
|
||||
selector += " >> has=" + gson().toJson("text=" + jsRegex);
|
||||
} else if (options.hasText instanceof String) {
|
||||
String text = (String) options.hasText;
|
||||
selector += " >> :scope:has-text(" + escapeWithQuotes(text) + ")";
|
||||
}
|
||||
selector += " >> internal:has-text=" + escapeForTextSelector(options.hasText, false);
|
||||
}
|
||||
if (options.has != null) {
|
||||
LocatorImpl locator = (LocatorImpl) options.has;
|
||||
if (locator.frame != frame)
|
||||
throw new Error("Inner 'has' locator must belong to the same frame.");
|
||||
selector += " >> internal:has=" + gson().toJson(locator.selector);
|
||||
}
|
||||
selector = filters.addFiltersToSelector(selector, options, frame);
|
||||
}
|
||||
this.selector = selector;
|
||||
}
|
||||
@@ -102,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)");
|
||||
@@ -112,6 +82,21 @@ class LocatorImpl implements Locator {
|
||||
return (List<String>) frame.evalOnSelectorAll(selector, "ee => ee.map(e => e.textContent || '')");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void blur(BlurOptions options) {
|
||||
frame.withLogging("Locator.blur", () -> blurImpl(options));
|
||||
}
|
||||
|
||||
private void blurImpl(BlurOptions options) {
|
||||
if (options == null) {
|
||||
options = new BlurOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
params.addProperty("strict", true);
|
||||
frame.sendMessage("blur", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoundingBox boundingBox(BoundingBoxOptions options) {
|
||||
return withElement((h, o) -> h.boundingBox(), options);
|
||||
@@ -125,6 +110,11 @@ class LocatorImpl implements Locator {
|
||||
frame.check(selector, convertType(options, Frame.CheckOptions.class).setStrict(true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear(ClearOptions options) {
|
||||
fill("", convertType(options, FillOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void click(ClickOptions options) {
|
||||
if (options == null) {
|
||||
@@ -234,6 +224,71 @@ class LocatorImpl implements Locator {
|
||||
return frame.getAttribute(selector, name, convertType(options, Frame.GetAttributeOptions.class).setStrict(true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByAltText(String text, GetByAltTextOptions options) {
|
||||
return locator(getByAltTextSelector(text, options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByAltText(Pattern text, GetByAltTextOptions options) {
|
||||
return locator(getByAltTextSelector(text, options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByLabel(String text, GetByLabelOptions options) {
|
||||
return locator(getByLabelSelector(text, options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByLabel(Pattern text, GetByLabelOptions options) {
|
||||
return locator(getByLabelSelector(text, options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByPlaceholder(String text, GetByPlaceholderOptions options) {
|
||||
return locator(getByPlaceholderSelector(text, options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByPlaceholder(Pattern text, GetByPlaceholderOptions options) {
|
||||
return locator(getByPlaceholderSelector(text, options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByRole(AriaRole role, GetByRoleOptions options) {
|
||||
return locator(getByRoleSelector(role, options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByTestId(String testId) {
|
||||
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));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByText(Pattern text, GetByTextOptions options) {
|
||||
return locator(getByTextSelector(text, options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByTitle(String text, GetByTitleOptions options) {
|
||||
return locator(getByTitleSelector(text, options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByTitle(Pattern text, GetByTitleOptions options) {
|
||||
return locator(getByTitleSelector(text, options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void highlight() {
|
||||
frame.highlightImpl(selector);
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.microsoft.playwright.Locator;
|
||||
import com.microsoft.playwright.options.AriaRole;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
|
||||
|
||||
public class LocatorUtils {
|
||||
private static volatile String testIdAttributeName = "data-testid";;
|
||||
|
||||
static void setTestIdAttributeName(String name) {
|
||||
testIdAttributeName = name;
|
||||
}
|
||||
|
||||
static String getByTextSelector(Object text, Locator.GetByTextOptions options) {
|
||||
boolean exact = options != null && options.exact != null && options.exact;
|
||||
return "internal:text=" + escapeForTextSelector(text, exact);
|
||||
}
|
||||
|
||||
static String getByLabelSelector(Object text, Locator.GetByLabelOptions options) {
|
||||
boolean exact = options != null && options.exact != null && options.exact;
|
||||
return "internal:label=" + escapeForTextSelector(text, exact);
|
||||
}
|
||||
|
||||
private static String getByAttributeTextSelector(String attrName, Object value, boolean exact) {
|
||||
if (value instanceof Pattern) {
|
||||
return "internal:attr=[" + attrName + "=" + toJsRegExp((Pattern) value) + "]";
|
||||
}
|
||||
return "internal:attr=[" + attrName + "=" + escapeForAttributeSelector((String) value, exact) + "]";
|
||||
}
|
||||
|
||||
static String getByTestIdSelector(Object testId) {
|
||||
return getByAttributeTextSelector(testIdAttributeName, testId, true);
|
||||
}
|
||||
|
||||
static String getByAltTextSelector(Object text, Locator.GetByAltTextOptions options) {
|
||||
boolean exact = options != null && options.exact != null && options.exact;
|
||||
return getByAttributeTextSelector("alt", text, exact);
|
||||
}
|
||||
|
||||
static String getByTitleSelector(Object text, Locator.GetByTitleOptions options) {
|
||||
boolean exact = options != null && options.exact != null && options.exact;
|
||||
return getByAttributeTextSelector("title", text, exact);
|
||||
}
|
||||
|
||||
static String getByPlaceholderSelector(Object text, Locator.GetByPlaceholderOptions options) {
|
||||
boolean exact = options != null && options.exact != null && options.exact;
|
||||
return getByAttributeTextSelector("placeholder", text, exact);
|
||||
}
|
||||
|
||||
private static void addAttr(StringBuilder result, String name, String value) {
|
||||
result.append("[").append(name).append("=").append(value).append("]");
|
||||
}
|
||||
|
||||
static String getByRoleSelector(AriaRole role, Locator.GetByRoleOptions options) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append("internal:role=").append(role.name().toLowerCase());
|
||||
if (options != null) {
|
||||
if (options.checked != null)
|
||||
addAttr(result, "checked", options.checked.toString());
|
||||
if (options.disabled != null)
|
||||
addAttr(result, "disabled", options.disabled.toString());
|
||||
if (options.selected != null)
|
||||
addAttr(result, "selected", options.selected.toString());
|
||||
if (options.expanded != null)
|
||||
addAttr(result, "expanded", options.expanded.toString());
|
||||
if (options.includeHidden != null)
|
||||
addAttr(result, "include-hidden", options.includeHidden.toString());
|
||||
if (options.level != null)
|
||||
addAttr(result, "level", options.level.toString());
|
||||
if (options.name != null) {
|
||||
String name;
|
||||
if (options.name instanceof String) {
|
||||
name = escapeForAttributeSelector((String) options.name, options.exact != null && options.exact);
|
||||
} else if (options.name instanceof Pattern) {
|
||||
name = toJsRegExp((Pattern) options.name);
|
||||
} else {
|
||||
throw new IllegalArgumentException("options.name can be String or Pattern, found: " + options.name);
|
||||
}
|
||||
addAttr(result, "name", name);
|
||||
}
|
||||
if (options.pressed != null)
|
||||
addAttr(result, "pressed", options.pressed.toString());
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
static String escapeForTextSelector(Object text, boolean exact) {
|
||||
return escapeForTextSelector(text, exact, false);
|
||||
}
|
||||
|
||||
private static String escapeForTextSelector(Object param, boolean exact, boolean caseSensitive) {
|
||||
if (param instanceof Pattern) {
|
||||
return toJsRegExp((Pattern) param);
|
||||
}
|
||||
if (!(param instanceof String)) {
|
||||
throw new IllegalArgumentException("text parameter must be Pattern or String: " + param);
|
||||
}
|
||||
String text = (String) param;
|
||||
if (exact) {
|
||||
return '"' + text.replace("\"", "\\\"") + '"';
|
||||
}
|
||||
|
||||
if (text.contains("\"") || text.contains(">>") || text.startsWith("/")) {
|
||||
return "/" + escapeForRegex(text).replaceAll("\\s+", "\\\\s+") + "/" + (caseSensitive ? "" : "i");
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
private static String escapeForRegex(String text) {
|
||||
return text.replaceAll("[.*+?^>${}()|\\[\\]\\\\]", "\\\\\\\\$0");
|
||||
}
|
||||
|
||||
private static String escapeForAttributeSelector(String value, boolean exact) {
|
||||
// TODO: this should actually be
|
||||
// cssEscape(value).replace(/\\ /g, ' ')
|
||||
// However, our attribute selectors do not conform to CSS parsing spec,
|
||||
// so we escape them differently.
|
||||
return '"' + value.replaceAll("\"", "\\\\\"") + '"' + (exact ? "" : "i");
|
||||
}
|
||||
|
||||
private static String toJsRegExp(Pattern pattern) {
|
||||
return "/" + pattern.pattern() + "/" + toJsRegexFlags(pattern);
|
||||
}
|
||||
}
|
||||
@@ -29,8 +29,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;
|
||||
@@ -48,23 +47,16 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
private ViewportSize viewport;
|
||||
private final Router routes = new Router();
|
||||
private final Set<FrameImpl> frames = new LinkedHashSet<>();
|
||||
final ListenerCollection<EventType> listeners = new ListenerCollection<EventType>() {
|
||||
@Override
|
||||
void add(EventType eventType, Consumer<?> listener) {
|
||||
if (eventType == EventType.FILECHOOSER) {
|
||||
willAddFileChooserListener();
|
||||
}
|
||||
super.add(eventType, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
void remove(EventType eventType, Consumer<?> listener) {
|
||||
super.remove(eventType, listener);
|
||||
if (eventType == EventType.FILECHOOSER) {
|
||||
didRemoveFileChooserListener();
|
||||
}
|
||||
}
|
||||
};
|
||||
private static final Map<EventType, String> eventSubscriptions() {
|
||||
Map<EventType, String> result = new HashMap<>();
|
||||
result.put(EventType.REQUEST, "request");
|
||||
result.put(EventType.RESPONSE, "response");
|
||||
result.put(EventType.REQUESTFINISHED, "requestFinished");
|
||||
result.put(EventType.REQUESTFAILED, "requestFailed");
|
||||
result.put(EventType.FILECHOOSER, "fileChooser");
|
||||
return result;
|
||||
}
|
||||
final ListenerCollection<EventType> listeners = new ListenerCollection<EventType>(eventSubscriptions(), this);
|
||||
final Map<String, BindingCallback> bindings = new HashMap<>();
|
||||
BrowserContextImpl ownedContext;
|
||||
private boolean isClosed;
|
||||
@@ -151,7 +143,6 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
} else if ("download".equals(event)) {
|
||||
String artifactGuid = params.getAsJsonObject("artifact").get("guid").getAsString();
|
||||
ArtifactImpl artifact = connection.getExistingObject(artifactGuid);
|
||||
artifact.isRemote = browserContext.browser() != null && browserContext.browser().isRemote;
|
||||
DownloadImpl download = new DownloadImpl(this, artifact, params);
|
||||
listeners.notify(EventType.DOWNLOAD, download);
|
||||
} else if ("fileChooser".equals(event)) {
|
||||
@@ -196,10 +187,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) {
|
||||
if (handled != Router.HandleResult.NoMatchingHandler) {
|
||||
maybeDisableNetworkInterception();
|
||||
}
|
||||
if (!route.isHandled()) {
|
||||
if (handled == Router.HandleResult.NoMatchingHandler || handled == Router.HandleResult.Fallback) {
|
||||
browserContext.handleRoute(route);
|
||||
}
|
||||
} else if ("video".equals(event)) {
|
||||
@@ -233,24 +224,6 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
listeners.notify(EventType.CLOSE, this);
|
||||
}
|
||||
|
||||
private void willAddFileChooserListener() {
|
||||
if (!listeners.hasListeners(EventType.FILECHOOSER)) {
|
||||
updateFileChooserInterception(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void didRemoveFileChooserListener() {
|
||||
if (!listeners.hasListeners(EventType.FILECHOOSER)) {
|
||||
updateFileChooserInterception(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateFileChooserInterception(boolean enabled) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("intercepted", enabled);
|
||||
sendMessage("setFileChooserInterceptedNoReply", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(Consumer<Page> handler) {
|
||||
listeners.add(EventType.CLOSE, handler);
|
||||
@@ -761,6 +734,82 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
() -> mainFrame.getAttributeImpl(selector, name, convertType(options, Frame.GetAttributeOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByAltText(String text, GetByAltTextOptions options) {
|
||||
return withLogging("Page.getAttribute",
|
||||
() -> mainFrame.getByAltText(text, convertType(options, Frame.GetByAltTextOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByAltText(Pattern text, GetByAltTextOptions options) {
|
||||
return withLogging("Page.getByAltText",
|
||||
() -> mainFrame.getByAltText(text, convertType(options, Frame.GetByAltTextOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByLabel(String text, GetByLabelOptions options) {
|
||||
return withLogging("Page.getByLabel",
|
||||
() -> mainFrame.getByLabel(text, convertType(options, Frame.GetByLabelOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByLabel(Pattern text, GetByLabelOptions options) {
|
||||
return withLogging("Page.getByLabel",
|
||||
() -> mainFrame.getByLabel(text, convertType(options, Frame.GetByLabelOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByPlaceholder(String text, GetByPlaceholderOptions options) {
|
||||
return withLogging("Page.getByPlaceholder",
|
||||
() -> mainFrame.getByPlaceholder(text, convertType(options, Frame.GetByPlaceholderOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByPlaceholder(Pattern text, GetByPlaceholderOptions options) {
|
||||
return withLogging("Page.getByPlaceholder",
|
||||
() -> mainFrame.getByPlaceholder(text, convertType(options, Frame.GetByPlaceholderOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByRole(AriaRole role, GetByRoleOptions options) {
|
||||
return withLogging("Page.getByRole",
|
||||
() -> mainFrame.getByRole(role, convertType(options, Frame.GetByRoleOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByTestId(String testId) {
|
||||
return withLogging("Page.getByTestId", () -> mainFrame.getByTestId(testId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByTestId(Pattern testId) {
|
||||
return withLogging("Page.getByTestId", () -> mainFrame.getByTestId(testId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByText(String text, GetByTextOptions options) {
|
||||
return withLogging("Page.getByText",
|
||||
() -> mainFrame.getByText(text, convertType(options, Frame.GetByTextOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByText(Pattern text, GetByTextOptions options) {
|
||||
return withLogging("Page.getByText",
|
||||
() -> mainFrame.getByText(text, convertType(options, Frame.GetByTextOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByTitle(String text, GetByTitleOptions options) {
|
||||
return withLogging("Page.getByTitle",
|
||||
() -> mainFrame.getByTitle(text, convertType(options, Frame.GetByTitleOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator getByTitle(Pattern text, GetByTitleOptions options) {
|
||||
return withLogging("Page.getByTitle",
|
||||
() -> mainFrame.getByTitle(text, convertType(options, Frame.GetByTitleOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response goBack(GoBackOptions options) {
|
||||
return withLogging("Page.goBack", () -> goBackImpl(options));
|
||||
@@ -1000,8 +1049,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 };
|
||||
@@ -1016,11 +1063,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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -65,7 +65,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,11 +76,19 @@ 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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
@@ -378,7 +394,7 @@ class Serialization {
|
||||
public JsonElement serialize(Optional<?> src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
assert isSupported(typeOfSrc) : "Unexpected optional type: " + typeOfSrc.getTypeName();
|
||||
if (!src.isPresent()) {
|
||||
return new JsonPrimitive("null");
|
||||
return new JsonPrimitive("no-override");
|
||||
}
|
||||
return context.serialize(src.get());
|
||||
}
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.microsoft.playwright.impl.LocatorUtils.setTestIdAttributeName;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
public class SharedSelectors extends LoggingSupport implements Selectors {
|
||||
@@ -61,6 +62,12 @@ public class SharedSelectors extends LoggingSupport implements Selectors {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTestIdAttribute(String attributeName) {
|
||||
// TODO: set it per playwright insttance
|
||||
setTestIdAttributeName(attributeName);
|
||||
}
|
||||
|
||||
void addChannel(SelectorsImpl channel) {
|
||||
registrations.forEach(r -> channel.registerImpl(r.name, r.script, r.options));
|
||||
channels.add(channel);
|
||||
|
||||
@@ -69,7 +69,13 @@ class StackTraceCollector {
|
||||
if (file == null) {
|
||||
return "";
|
||||
}
|
||||
return resolveSourcePath(Paths.get(pkg).resolve(file));
|
||||
try {
|
||||
// The file name can contain an arbitrary string which may cause Path implementation
|
||||
// to throw. See https://github.com/microsoft/playwright-java/issues/1115
|
||||
return resolveSourcePath(Paths.get(pkg).resolve(file));
|
||||
} catch (RuntimeException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveSourcePath(Path relativePath) {
|
||||
|
||||
@@ -26,8 +26,6 @@ import java.nio.file.Path;
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
|
||||
class TracingImpl extends ChannelOwner implements Tracing {
|
||||
boolean isRemote;
|
||||
|
||||
TracingImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
}
|
||||
@@ -36,7 +34,7 @@ class TracingImpl extends ChannelOwner implements Tracing {
|
||||
JsonObject params = new JsonObject();
|
||||
String mode = "doNotSave";
|
||||
if (path != null) {
|
||||
if (isRemote) {
|
||||
if (connection.isRemote) {
|
||||
mode = "compressTrace";
|
||||
} else {
|
||||
mode = "compressTraceAndSources";
|
||||
@@ -48,16 +46,13 @@ class TracingImpl extends ChannelOwner implements Tracing {
|
||||
return;
|
||||
}
|
||||
ArtifactImpl artifact = connection.getExistingObject(json.getAsJsonObject("artifact").get("guid").getAsString());
|
||||
// In case of CDP connection browser is null but since the connection is established by
|
||||
// the driver it is safe to consider the artifact local.
|
||||
if (isRemote) {
|
||||
artifact.isRemote = true;
|
||||
}
|
||||
artifact.saveAs(path);
|
||||
artifact.delete();
|
||||
|
||||
// Add local sources to the remote trace if necessary.
|
||||
if (isRemote && json.has("sourceEntries")) {
|
||||
// In case of CDP connection since the connection is established by
|
||||
// the driver it is safe to consider the artifact local.
|
||||
if (connection.isRemote && json.has("sourceEntries")) {
|
||||
JsonArray entries = json.getAsJsonArray("sourceEntries");
|
||||
connection.localUtils.zip(path, entries);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -165,7 +166,7 @@ class Utils {
|
||||
}
|
||||
|
||||
static void addLargeFileUploadParams(Path[] files, JsonObject params, BrowserContextImpl context) {
|
||||
if (context.browser().isRemote) {
|
||||
if (context.connection.isRemote) {
|
||||
List<WritableStream> streams = new ArrayList<>();
|
||||
JsonArray jsonStreams = new JsonArray();
|
||||
for (Path path : files) {
|
||||
|
||||
@@ -27,16 +27,13 @@ import static java.util.Arrays.asList;
|
||||
class VideoImpl implements Video {
|
||||
private final PageImpl page;
|
||||
private final WaitableResult<ArtifactImpl> waitableArtifact = new WaitableResult<>();
|
||||
private final boolean isRemote;
|
||||
|
||||
VideoImpl(PageImpl page) {
|
||||
this.page = page;
|
||||
BrowserImpl browser = page.context().browser();
|
||||
isRemote = browser != null && browser.isRemote;
|
||||
}
|
||||
|
||||
void setArtifact(ArtifactImpl artifact) {
|
||||
artifact.isRemote = isRemote;
|
||||
waitableArtifact.complete(artifact);
|
||||
}
|
||||
|
||||
@@ -58,7 +55,7 @@ class VideoImpl implements Video {
|
||||
@Override
|
||||
public Path path() {
|
||||
return page.withLogging("Video.path", () -> {
|
||||
if (isRemote) {
|
||||
if (page.connection.isRemote) {
|
||||
throw new PlaywrightException("Path is not available when using browserType.connect(). Use saveAs() to save a local copy.");
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.microsoft.playwright.options;
|
||||
|
||||
public enum AriaRole {
|
||||
ALERT,
|
||||
ALERTDIALOG,
|
||||
APPLICATION,
|
||||
ARTICLE,
|
||||
BANNER,
|
||||
BLOCKQUOTE,
|
||||
BUTTON,
|
||||
CAPTION,
|
||||
CELL,
|
||||
CHECKBOX,
|
||||
CODE,
|
||||
COLUMNHEADER,
|
||||
COMBOBOX,
|
||||
COMPLEMENTARY,
|
||||
CONTENTINFO,
|
||||
DEFINITION,
|
||||
DELETION,
|
||||
DIALOG,
|
||||
DIRECTORY,
|
||||
DOCUMENT,
|
||||
EMPHASIS,
|
||||
FEED,
|
||||
FIGURE,
|
||||
FORM,
|
||||
GENERIC,
|
||||
GRID,
|
||||
GRIDCELL,
|
||||
GROUP,
|
||||
HEADING,
|
||||
IMG,
|
||||
INSERTION,
|
||||
LINK,
|
||||
LIST,
|
||||
LISTBOX,
|
||||
LISTITEM,
|
||||
LOG,
|
||||
MAIN,
|
||||
MARQUEE,
|
||||
MATH,
|
||||
METER,
|
||||
MENU,
|
||||
MENUBAR,
|
||||
MENUITEM,
|
||||
MENUITEMCHECKBOX,
|
||||
MENUITEMRADIO,
|
||||
NAVIGATION,
|
||||
NONE,
|
||||
NOTE,
|
||||
OPTION,
|
||||
PARAGRAPH,
|
||||
PRESENTATION,
|
||||
PROGRESSBAR,
|
||||
RADIO,
|
||||
RADIOGROUP,
|
||||
REGION,
|
||||
ROW,
|
||||
ROWGROUP,
|
||||
ROWHEADER,
|
||||
SCROLLBAR,
|
||||
SEARCH,
|
||||
SEARCHBOX,
|
||||
SEPARATOR,
|
||||
SLIDER,
|
||||
SPINBUTTON,
|
||||
STATUS,
|
||||
STRONG,
|
||||
SUBSCRIPT,
|
||||
SUPERSCRIPT,
|
||||
SWITCH,
|
||||
TAB,
|
||||
TABLE,
|
||||
TABLIST,
|
||||
TABPANEL,
|
||||
TERM,
|
||||
TEXTBOX,
|
||||
TIME,
|
||||
TIMER,
|
||||
TOOLBAR,
|
||||
TOOLTIP,
|
||||
TREE,
|
||||
TREEGRID,
|
||||
TREEITEM
|
||||
}
|
||||
@@ -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,39 +69,44 @@ 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);
|
||||
/**
|
||||
@@ -107,12 +114,14 @@ public interface RequestOptions {
|
||||
*
|
||||
* @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 +129,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 +137,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 +154,7 @@ public interface RequestOptions {
|
||||
*
|
||||
* @param name Parameter name.
|
||||
* @param value Parameter value.
|
||||
* @since v1.18
|
||||
*/
|
||||
RequestOptions setQueryParam(String name, String value);
|
||||
/**
|
||||
@@ -149,6 +162,7 @@ public interface RequestOptions {
|
||||
*
|
||||
* @param name Parameter name.
|
||||
* @param value Parameter value.
|
||||
* @since v1.18
|
||||
*/
|
||||
RequestOptions setQueryParam(String name, boolean value);
|
||||
/**
|
||||
@@ -156,12 +170,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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -287,6 +290,27 @@ public class TestBrowserContextFetch extends TestBase {
|
||||
assertEquals("/simple.json", request.get().url);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getShouldSupportPostData() throws ExecutionException, InterruptedException {
|
||||
Future<Server.Request> request = server.futureRequest("/simple.json");
|
||||
APIResponse response = context.request().get(server.PREFIX + "/simple.json",
|
||||
RequestOptions.create().setData("My request"));
|
||||
assertEquals("GET", request.get().method);
|
||||
assertEquals("My request", new String(request.get().postBody));
|
||||
assertEquals(200, response.status());
|
||||
assertEquals("/simple.json", request.get().url);
|
||||
}
|
||||
|
||||
@Test
|
||||
void headShouldSupportPostData() throws ExecutionException, InterruptedException {
|
||||
Future<Server.Request> request = server.futureRequest("/simple.json");
|
||||
APIResponse response = context.request().head(server.PREFIX + "/simple.json",
|
||||
RequestOptions.create().setData("My request"));
|
||||
assertEquals("HEAD", request.get().method);
|
||||
assertEquals("My request", new String(request.get().postBody));
|
||||
assertEquals(200, response.status());
|
||||
assertEquals("/simple.json", request.get().url);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAddDefaultHeaders() throws ExecutionException, InterruptedException {
|
||||
@@ -458,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,7 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.AriaRole;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledIf;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
|
||||
@@ -2,13 +2,19 @@ package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.Geolocation;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledIf;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -22,6 +28,7 @@ public class TestDefaultBrowserContext2 extends TestBase {
|
||||
|
||||
|
||||
private BrowserContext persistentContext;
|
||||
@TempDir Path tempDir;
|
||||
|
||||
@AfterEach
|
||||
private void closePersistentContext() {
|
||||
@@ -36,12 +43,7 @@ public class TestDefaultBrowserContext2 extends TestBase {
|
||||
}
|
||||
|
||||
private Page launchPersistent(BrowserType.LaunchPersistentContextOptions options) {
|
||||
Path userDataDir = null;
|
||||
try {
|
||||
userDataDir = Files.createTempDirectory("user-data-dir-");
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
Path userDataDir = tempDir.resolve("user-data-dir");
|
||||
assertNull(persistentContext);
|
||||
persistentContext = browserType.launchPersistentContext(userDataDir, options);
|
||||
return persistentContext.pages().get(0);
|
||||
@@ -118,7 +120,7 @@ public class TestDefaultBrowserContext2 extends TestBase {
|
||||
@Test
|
||||
void shouldAcceptUserDataDir() throws IOException {
|
||||
// TODO: test.flaky(browserName === "chromium");
|
||||
Path userDataDir = Files.createTempDirectory("user-data-dir-");
|
||||
Path userDataDir = tempDir.resolve("user-data-dir");
|
||||
BrowserContext context = browserType.launchPersistentContext(userDataDir);
|
||||
assertTrue(userDataDir.toFile().listFiles().length > 0);
|
||||
context.close();
|
||||
@@ -128,7 +130,7 @@ public class TestDefaultBrowserContext2 extends TestBase {
|
||||
@Test
|
||||
void shouldRestoreStateFromUserDataDir() throws IOException {
|
||||
// TODO: test.slow();
|
||||
Path userDataDir = Files.createTempDirectory("user-data-dir-");
|
||||
Path userDataDir = tempDir.resolve("user-data-dir");
|
||||
BrowserType.LaunchPersistentContextOptions browserOptions = null;
|
||||
BrowserContext browserContext = browserType.launchPersistentContext(userDataDir, browserOptions);
|
||||
Page page = browserContext.newPage();
|
||||
@@ -142,7 +144,7 @@ public class TestDefaultBrowserContext2 extends TestBase {
|
||||
assertEquals("hello", page2.evaluate("localStorage.hey"));
|
||||
browserContext2.close();
|
||||
|
||||
Path userDataDir2 = Files.createTempDirectory("user-data-dir-");
|
||||
Path userDataDir2 = tempDir.resolve("user-data-dir-2");
|
||||
BrowserContext browserContext3 = browserType.launchPersistentContext(userDataDir2, browserOptions);
|
||||
Page page3 = browserContext3.newPage();
|
||||
page3.navigate(server.EMPTY_PAGE);
|
||||
@@ -153,7 +155,7 @@ public class TestDefaultBrowserContext2 extends TestBase {
|
||||
@Test
|
||||
void shouldRestoreCookiesFromUserDataDir() throws IOException {
|
||||
// TODO: test.flaky(browserName === "chromium");
|
||||
Path userDataDir = Files.createTempDirectory("user-data-dir-");
|
||||
Path userDataDir = tempDir.resolve("user-data-dir");
|
||||
BrowserType.LaunchPersistentContextOptions browserOptions = null;
|
||||
BrowserContext browserContext = browserType.launchPersistentContext(userDataDir, browserOptions);
|
||||
Page page = browserContext.newPage();
|
||||
@@ -171,7 +173,7 @@ public class TestDefaultBrowserContext2 extends TestBase {
|
||||
assertEquals("doSomethingOnlyOnce=true", page2.evaluate("() => document.cookie"));
|
||||
browserContext2.close();
|
||||
|
||||
Path userDataDir2 = Files.createTempDirectory("user-data-dir-");
|
||||
Path userDataDir2 = tempDir.resolve("user-data-dir-2");
|
||||
BrowserContext browserContext3 = browserType.launchPersistentContext(userDataDir2, browserOptions);
|
||||
Page page3 = browserContext3.newPage();
|
||||
page3.navigate(server.EMPTY_PAGE);
|
||||
@@ -191,7 +193,7 @@ public class TestDefaultBrowserContext2 extends TestBase {
|
||||
void shouldThrowIfPageArgumentIsPassed() throws IOException {
|
||||
BrowserType.LaunchPersistentContextOptions options = new BrowserType.LaunchPersistentContextOptions()
|
||||
.setArgs(asList(server.EMPTY_PAGE));
|
||||
Path userDataDir = Files.createTempDirectory("user-data-dir-");
|
||||
Path userDataDir = tempDir.resolve("user-data-dir");
|
||||
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
|
||||
browserType.launchPersistentContext(userDataDir, options);
|
||||
});
|
||||
@@ -254,4 +256,43 @@ public class TestDefaultBrowserContext2 extends TestBase {
|
||||
assertEquals("hello", page.innerHTML("defaultContextCSS=div"));
|
||||
}
|
||||
|
||||
}
|
||||
@Test
|
||||
void shouldUploadLargeFile(@TempDir Path tmpDir) throws IOException, ExecutionException, InterruptedException {
|
||||
Assumptions.assumeTrue(3 <= (Runtime.getRuntime().maxMemory() >> 30), "Fails if max heap size is < 3Gb");
|
||||
Page page = launchPersistent();
|
||||
page.navigate(server.PREFIX + "/input/fileupload.html");
|
||||
Path uploadFile = tmpDir.resolve("200MB.zip");
|
||||
String str = String.join("", Collections.nCopies(4 * 1024, "A"));
|
||||
|
||||
try (Writer stream = new OutputStreamWriter(Files.newOutputStream(uploadFile))) {
|
||||
for (int i = 0; i < 50 * 1024; i++) {
|
||||
stream.write(str);
|
||||
}
|
||||
}
|
||||
Locator input = page.locator("input[type='file']");
|
||||
JSHandle events = input.evaluateHandle("e => {\n" +
|
||||
" const events = [];\n" +
|
||||
" e.addEventListener('input', () => events.push('input'));\n" +
|
||||
" e.addEventListener('change', () => events.push('change'));\n" +
|
||||
" return events;\n" +
|
||||
" }");
|
||||
input.setInputFiles(uploadFile);
|
||||
assertEquals("200MB.zip", input.evaluate("e => e.files[0].name"));
|
||||
assertEquals(asList("input", "change"), events.evaluate("e => e"));
|
||||
CompletableFuture<MultipartFormData> formData = new CompletableFuture<>();
|
||||
server.setRoute("/upload", exchange -> {
|
||||
try {
|
||||
MultipartFormData multipartFormData = MultipartFormData.parseRequest(exchange);
|
||||
formData.complete(multipartFormData);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
formData.completeExceptionally(e);
|
||||
}
|
||||
exchange.sendResponseHeaders(200, -1);
|
||||
});
|
||||
page.click("input[type=submit]", new Page.ClickOptions().setTimeout(90_000));
|
||||
List<MultipartFormData.Field> fields = formData.get().fields;
|
||||
assertEquals(1, fields.size());
|
||||
assertEquals("200MB.zip", fields.get(0).filename);
|
||||
assertEquals(200 * 1024 * 1024, fields.get(0).content.length());
|
||||
}}
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.AriaRole;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
@@ -30,13 +31,14 @@ public class TestLocatorFrame extends TestBase {
|
||||
.setBody("<iframe src='iframe.html'></iframe>").setContentType("text/html")));
|
||||
page.route("**/iframe.html", route -> {
|
||||
route.fulfill(new Route.FulfillOptions().setBody("<html>\n" +
|
||||
" <div>\n" +
|
||||
" <button>Hello iframe</button>\n" +
|
||||
" <iframe src='iframe-2.html'></iframe>\n" +
|
||||
" </div>\n" +
|
||||
" <span>1</span>\n" +
|
||||
" <span>2</span>\n" +
|
||||
" </html>").setContentType("text/html"));
|
||||
" <div>\n" +
|
||||
" <button data-testid=\"buttonId\">Hello iframe</button>\n" +
|
||||
" <iframe src=\"iframe-2.html\"></iframe>\n" +
|
||||
" </div>\n" +
|
||||
" <span>1</span>\n" +
|
||||
" <span>2</span>\n" +
|
||||
" <label for=target>Name</label><input id=target type=text placeholder=Placeholder title=Title alt=Alternative>\n" +
|
||||
"</html>").setContentType("text/html"));
|
||||
});
|
||||
page.route("**/iframe-2.html", route -> {
|
||||
route.fulfill(new Route.FulfillOptions().setBody("<html><button>Hello nested iframe</button></html>").setContentType("text/html"));
|
||||
@@ -102,7 +104,7 @@ public class TestLocatorFrame extends TestBase {
|
||||
PlaywrightException e = assertThrows(PlaywrightException.class, () -> {
|
||||
page.frameLocator("iframe").locator("span").click(new Locator.ClickOptions().setTimeout(300));
|
||||
});
|
||||
assertTrue(e.getMessage().contains("waiting for frame \"iframe\""), e.getMessage());
|
||||
assertTrue(e.getMessage().contains("waiting for frameLocator(\"iframe\")"), e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -226,7 +228,7 @@ public class TestLocatorFrame extends TestBase {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Locator button = page.locator("body").frameLocator("iframe").locator("button");
|
||||
PlaywrightException e = assertThrows(PlaywrightException.class, () -> button.waitFor());
|
||||
assertTrue(e.getMessage().contains("Error: strict mode violation: \"body >> iframe\" resolved to 3 elements"), e.getMessage());
|
||||
assertTrue(e.getMessage().contains("Error: strict mode violation: locator(\"body\").locator(\"iframe\") resolved to 3 elements"), e.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -241,4 +243,24 @@ public class TestLocatorFrame extends TestBase {
|
||||
assertThat(button3).hasText("Hello from iframe-3.html");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getByCoverage() {
|
||||
routeIframe(page);
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Locator button1 = page.frameLocator("iframe").getByRole(AriaRole.BUTTON);
|
||||
Locator button2 = page.frameLocator("iframe").getByText("Hello");
|
||||
Locator button3 = page.frameLocator("iframe").getByTestId("buttonId");
|
||||
assertThat(button1).hasText("Hello iframe");
|
||||
assertThat(button2).hasText("Hello iframe");
|
||||
assertThat(button3).hasText("Hello iframe");
|
||||
Locator input1 = page.frameLocator("iframe").getByLabel("Name");
|
||||
assertThat(input1).hasValue("");
|
||||
Locator input2 = page.frameLocator("iframe").getByPlaceholder("Placeholder");
|
||||
assertThat(input2).hasValue("");
|
||||
Locator input3 = page.frameLocator("iframe").getByAltText("Alternative");
|
||||
assertThat(input3).hasValue("");
|
||||
Locator input4 = page.frameLocator("iframe").getByTitle("Title");
|
||||
assertThat(input4).hasValue("");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -66,4 +66,40 @@ public class TestLocatorMisc extends TestBase{
|
||||
assertTrue(e.getMessage().contains("Драматург"), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldClearInput() {
|
||||
page.navigate(server.PREFIX + "/input/textarea.html");
|
||||
Locator handle = page.locator("input");
|
||||
handle.fill("some value");
|
||||
assertEquals("some value", page.evaluate("() => window['result']"));
|
||||
handle.clear();
|
||||
assertEquals("", page.evaluate("() => window['result']"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFocusAndBlurAButton() {
|
||||
page.navigate(server.PREFIX + "/input/button.html");
|
||||
Locator button = page.locator("button");
|
||||
assertEquals(false, button.evaluate("button => document.activeElement === button"));
|
||||
|
||||
boolean[] focused = {false};
|
||||
boolean[] blurred = {false};
|
||||
page.exposeFunction("focusEvent", e -> focused[0] = true);
|
||||
page.exposeFunction("blurEvent", e -> blurred[0] = true);
|
||||
button.evaluate("button => {\n" +
|
||||
" button.addEventListener('focus', window['focusEvent']);\n" +
|
||||
" button.addEventListener('blur', window['blurEvent']);\n" +
|
||||
" }");
|
||||
|
||||
button.focus();
|
||||
assertTrue(focused[0]);
|
||||
assertFalse(blurred[0]);
|
||||
assertEquals(true, button.evaluate("button => document.activeElement === button"));
|
||||
|
||||
button.blur();
|
||||
assertTrue(focused[0]);
|
||||
assertTrue(blurred[0]);
|
||||
assertEquals(false, button.evaluate("button => document.activeElement === button"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,4 +243,13 @@ public class TestPageFill extends TestBase {
|
||||
page.fill("input", "");
|
||||
assertEquals("", page.inputValue("input"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldBeAbleToClearUsingFill() {
|
||||
page.navigate(server.PREFIX + "/input/textarea.html");
|
||||
page.fill("input", "some value");
|
||||
assertEquals("some value", page.evaluate("() => window['result']"));
|
||||
page.fill("input", "");
|
||||
assertEquals("", page.evaluate("() => window['result']"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,37 @@ 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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -142,8 +142,16 @@ public class TestPopup extends TestBase {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Object[] size = {null};
|
||||
Page popup = page.waitForPopup(() -> {
|
||||
size[0] = page.evaluate("() => {\n" +
|
||||
size[0] = page.evaluate("async () => {\n" +
|
||||
" const win = window.open(window.location.href, 'Title', 'toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=600,height=300,top=0,left=0');\n" +
|
||||
" await new Promise(resolve => {\n" +
|
||||
" const interval = setInterval(() => {\n" +
|
||||
" if (win.innerWidth === 600 && win.innerHeight === 300) {\n" +
|
||||
" clearInterval(interval);\n" +
|
||||
" resolve();\n" +
|
||||
" }\n" +
|
||||
" }, 10);\n" +
|
||||
" });\n" +
|
||||
" return { width: win.innerWidth, height: win.innerHeight };\n" +
|
||||
"}");
|
||||
});
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.AriaRole;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestSelectorsGetBy extends TestBase {
|
||||
@Test
|
||||
void getByTestIdShouldWork() {
|
||||
page.setContent("<div><div data-testid='Hello'>Hello world</div></div>");
|
||||
assertThat(page.getByTestId("Hello")).hasText("Hello world");
|
||||
assertThat(page.mainFrame().getByTestId("Hello")).hasText("Hello world");
|
||||
assertThat(page.locator("div").getByTestId("Hello")).hasText("Hello world");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getByTestIdShouldEscapeId() {
|
||||
page.setContent("<div><div data-testid='He\"llo'>Hello world</div></div>");
|
||||
assertThat(page.getByTestId("He\"llo")).hasText("Hello world");
|
||||
}
|
||||
|
||||
@Test
|
||||
void 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>");
|
||||
assertTrue(((String) page.getByText("ye").evaluate("e => e.outerHTML")).contains(">\nye </div>"));
|
||||
assertTrue(((String) page.getByText(Pattern.compile("ye")).evaluate("e => e.outerHTML")).contains(">\nye </div>"));
|
||||
assertTrue(((String) page.getByText(Pattern.compile("e")).evaluate("e => e.outerHTML")).contains(">\nye </div>"));
|
||||
|
||||
page.setContent("<div> ye </div><div>ye</div>");
|
||||
assertTrue(((String) page.getByText("ye", new Page.GetByTextOptions().setExact(true)).first().evaluate("e => e.outerHTML")).contains("> ye </div>"));
|
||||
|
||||
page.setContent("<div>Hello world</div><div>Hello</div>");
|
||||
assertEquals("<div>Hello</div>", page.getByText("Hello", new Page.GetByTextOptions().setExact(true)).evaluate("e => e.outerHTML"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getByLabelShouldWork() {
|
||||
page.setContent("<div><label for=target>Name</label><input id=target type=text></div>");
|
||||
assertEquals("LABEL", page.getByText("Name").evaluate("e => e.nodeName"));
|
||||
assertEquals("INPUT", page.getByLabel("Name").evaluate("e => e.nodeName"));
|
||||
assertEquals("INPUT", page.mainFrame().getByLabel("Name").evaluate("e => e.nodeName"));
|
||||
assertEquals("INPUT", page.locator("div").getByLabel("Name").evaluate("e => e.nodeName"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getByLabelShouldWorkWithNestedElements() {
|
||||
page.setContent("<label for=target>Last <span>Name</span></label><input id=target type=text>");
|
||||
|
||||
assertThat(page.getByLabel("last name")).hasAttribute("id", "target");
|
||||
assertThat(page.getByLabel("st na")).hasAttribute("id", "target");
|
||||
assertThat(page.getByLabel("Name")).hasAttribute("id", "target");
|
||||
assertThat(page.getByLabel("Last Name", new Page.GetByLabelOptions().setExact(true))).hasAttribute("id", "target");
|
||||
assertThat(page.getByLabel(Pattern.compile("Last\\s+name", Pattern.CASE_INSENSITIVE))).hasAttribute("id", "target");
|
||||
|
||||
assertEquals(Collections.emptyList(), page.getByLabel("Last", new Page.GetByLabelOptions().setExact(true)).elementHandles());
|
||||
assertEquals(Collections.emptyList(), page.getByLabel("last name", new Page.GetByLabelOptions().setExact(true)).elementHandles());
|
||||
assertEquals(Collections.emptyList(), page.getByLabel("Name", new Page.GetByLabelOptions().setExact(true)).elementHandles());
|
||||
assertEquals(Collections.emptyList(), page.getByLabel("what?").elementHandles());
|
||||
assertEquals(Collections.emptyList(), page.getByLabel(Pattern.compile("last name")).elementHandles());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getByPlaceholderShouldWork() {
|
||||
page.setContent("<div>\n" +
|
||||
" <input placeholder='Hello'>\n" +
|
||||
" <input placeholder='Hello World'>\n" +
|
||||
" </div>");
|
||||
assertThat(page.getByPlaceholder("hello")).hasCount(2);
|
||||
assertThat(page.getByPlaceholder("Hello", new Page.GetByPlaceholderOptions().setExact(true))).hasCount(1);
|
||||
assertThat(page.getByPlaceholder(Pattern.compile("wor", Pattern.CASE_INSENSITIVE))).hasCount(1);
|
||||
|
||||
// Coverage
|
||||
assertThat(page.mainFrame().getByPlaceholder("hello")).hasCount(2);
|
||||
assertThat(page.locator("div").getByPlaceholder("hello")).hasCount(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getByAltTextShouldWork() {
|
||||
page.setContent("<div>\n" +
|
||||
" <input alt='Hello'>\n" +
|
||||
" <input alt='Hello World'>\n" +
|
||||
" </div>");
|
||||
assertThat(page.getByAltText("hello")).hasCount(2);
|
||||
assertThat(page.getByAltText("Hello", new Page.GetByAltTextOptions().setExact(true))).hasCount(1);
|
||||
assertThat(page.getByAltText(Pattern.compile("wor", Pattern.CASE_INSENSITIVE))).hasCount(1);
|
||||
|
||||
// Coverage
|
||||
assertThat(page.mainFrame().getByAltText("hello")).hasCount(2);
|
||||
assertThat(page.locator("div").getByAltText("hello")).hasCount(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getByTitleShouldWork() {
|
||||
page.setContent("<div>\n" +
|
||||
" <input title='Hello'>\n" +
|
||||
" <input title='Hello World'>\n" +
|
||||
" </div>");
|
||||
assertThat(page.getByTitle("hello")).hasCount(2);
|
||||
assertThat(page.getByTitle("Hello", new Page.GetByTitleOptions().setExact(true))).hasCount(1);
|
||||
assertThat(page.getByTitle(Pattern.compile("wor", Pattern.CASE_INSENSITIVE))).hasCount(1);
|
||||
|
||||
// Coverage
|
||||
assertThat(page.mainFrame().getByTitle("hello")).hasCount(2);
|
||||
assertThat(page.locator("div").getByTitle("hello")).hasCount(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getByEscaping() {
|
||||
page.setContent("<label id=label for=control>Hello my\n" +
|
||||
"wo\"rld</label><input id=control />");
|
||||
page.evalOnSelector("input", "input => {\n" +
|
||||
" input.setAttribute('placeholder', 'hello my\\nwo\"rld');\n" +
|
||||
" input.setAttribute('title', 'hello my\\nwo\"rld');\n" +
|
||||
" input.setAttribute('alt', 'hello my\\nwo\"rld');\n" +
|
||||
" }");
|
||||
assertThat(page.getByText("hello my\nwo\"rld")).hasAttribute("id", "label");
|
||||
assertThat(page.getByText("hello my wo\"rld")).hasAttribute("id", "label");
|
||||
assertThat(page.getByLabel("hello my\nwo\"rld")).hasAttribute("id", "control");
|
||||
assertThat(page.getByPlaceholder("hello my\nwo\"rld")).hasAttribute("id", "control");
|
||||
assertThat(page.getByAltText("hello my\nwo\"rld")).hasAttribute("id", "control");
|
||||
assertThat(page.getByTitle("hello my\nwo\"rld")).hasAttribute("id", "control");
|
||||
|
||||
page.setContent("<label id=label for=control>Hello my\n" +
|
||||
"world</label><input id=control />");
|
||||
page.evalOnSelector("input", "input => {\n" +
|
||||
" input.setAttribute('placeholder', 'hello my\\nworld');\n" +
|
||||
" input.setAttribute('title', 'hello my\\nworld');\n" +
|
||||
" input.setAttribute('alt', 'hello my\\nworld');\n" +
|
||||
" }");
|
||||
assertThat(page.getByText("hello my\nworld")).hasAttribute("id", "label");
|
||||
assertThat(page.getByText("hello my world")).hasAttribute("id", "label");
|
||||
assertThat(page.getByLabel("hello my\nworld")).hasAttribute("id", "control");
|
||||
assertThat(page.getByPlaceholder("hello my\nworld")).hasAttribute("id", "control");
|
||||
assertThat(page.getByAltText("hello my\nworld")).hasAttribute("id", "control");
|
||||
assertThat(page.getByTitle("hello my\nworld")).hasAttribute("id", "control");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getByRoleEscaping() {
|
||||
page.setContent("<a href=\"https://playwright.dev\">issues 123</a>\n" +
|
||||
" <a href=\"https://playwright.dev\">he llo 56</a>\n" +
|
||||
" <button>Click me</button>");
|
||||
assertEquals(
|
||||
asList("<button>Click me</button>"),
|
||||
page.getByRole(AriaRole.BUTTON).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(
|
||||
asList("<a href=\"https://playwright.dev\">issues 123</a>", "<a href=\"https://playwright.dev\">he llo 56</a>"),
|
||||
page.getByRole(AriaRole.LINK).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(
|
||||
asList("<a href=\"https://playwright.dev\">issues 123</a>"),
|
||||
page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("issues 123")).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(
|
||||
asList("<a href=\"https://playwright.dev\">issues 123</a>"),
|
||||
page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("sues")).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(
|
||||
asList("<a href=\"https://playwright.dev\">he llo 56</a>"),
|
||||
page.getByRole( AriaRole.LINK, new Page.GetByRoleOptions().setName(" he \n llo ")).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(
|
||||
asList(),
|
||||
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("issues")).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(
|
||||
asList(),
|
||||
page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("sues").setExact(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
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)"));
|
||||
}
|
||||
|
||||
@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)"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,404 @@
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.AriaRole;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.emptyList;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestSelectorsRole extends TestBase {
|
||||
@Test
|
||||
void shouldDetectRoles() {
|
||||
page.setContent("<button>Hello</button>\n" +
|
||||
" <select multiple=\"\" size=\"2\"></select>\n" +
|
||||
" <select></select>\n" +
|
||||
" <h3>Heading</h3>\n" +
|
||||
" <details><summary>Hello</summary></details>\n" +
|
||||
" <div role='dialog'>I am a dialog</div>");
|
||||
assertEquals(asList("<button>Hello</button>"), page.locator("role=button").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
|
||||
assertEquals(asList("<select multiple=\"\" size=\"2\"></select>"), page.locator("role=listbox").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
|
||||
assertEquals(asList("<select></select>"), page.locator("role=combobox").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
|
||||
assertEquals(asList("<h3>Heading</h3>"), page.locator("role=heading").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
|
||||
assertEquals(asList("<details><summary>Hello</summary></details>"), page.locator("role=group").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
|
||||
assertEquals(asList("<div role=\"dialog\">I am a dialog</div>"), page.locator("role=dialog").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
|
||||
assertEquals(emptyList(), page.locator("role=menuitem").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
|
||||
assertEquals(emptyList(), page.getByRole(AriaRole.MENUITEM).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSupportSelected() {
|
||||
page.setContent("<select>\n" +
|
||||
" <option>Hi</option>\n" +
|
||||
" <option selected>Hello</option>\n" +
|
||||
" </select>\n" +
|
||||
" <div>\n" +
|
||||
" <div role=\"option\" aria-selected=\"true\">Hi</div>\n" +
|
||||
" <div role=\"option\" aria-selected=\"false\">Hello</div>\n" +
|
||||
" </div>");
|
||||
assertEquals(asList(
|
||||
"<option selected=\"\">Hello</option>",
|
||||
"<div role=\"option\" aria-selected=\"true\">Hi</div>"
|
||||
), page.locator("role=option[selected]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
|
||||
assertEquals(asList(
|
||||
"<option selected=\"\">Hello</option>",
|
||||
"<div role=\"option\" aria-selected=\"true\">Hi</div>"
|
||||
), page.locator("role=option[selected=true]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
|
||||
assertEquals(asList(
|
||||
"<option selected=\"\">Hello</option>",
|
||||
"<div role=\"option\" aria-selected=\"true\">Hi</div>"
|
||||
), page.getByRole(AriaRole.OPTION, new Page.GetByRoleOptions().setSelected(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
|
||||
assertEquals(asList(
|
||||
"<option>Hi</option>",
|
||||
"<div role=\"option\" aria-selected=\"false\">Hello</div>"
|
||||
), page.locator("role=option[selected=false]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<option>Hi</option>",
|
||||
"<div role=\"option\" aria-selected=\"false\">Hello</div>"
|
||||
), page.getByRole(AriaRole.OPTION, new Page.GetByRoleOptions().setSelected(false)).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSupportChecked() {
|
||||
page.setContent("<input type=checkbox>\n" +
|
||||
" <input type=checkbox checked>\n" +
|
||||
" <input type=checkbox indeterminate>\n" +
|
||||
" <div role=checkbox aria-checked=\"true\">Hi</div>\n" +
|
||||
" <div role=checkbox aria-checked=\"false\">Hello</div>\n" +
|
||||
" <div role=checkbox>Unknown</div>");
|
||||
page.evalOnSelector("[indeterminate]", "input => input.indeterminate = true");
|
||||
|
||||
assertEquals(asList(
|
||||
"<input type=\"checkbox\" checked=\"\">",
|
||||
"<div role=\"checkbox\" aria-checked=\"true\">Hi</div>"
|
||||
), page.locator("role=checkbox[checked]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<input type=\"checkbox\" checked=\"\">",
|
||||
"<div role=\"checkbox\" aria-checked=\"true\">Hi</div>"
|
||||
), page.locator("role=checkbox[checked=true]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<input type=\"checkbox\" checked=\"\">",
|
||||
"<div role=\"checkbox\" aria-checked=\"true\">Hi</div>"
|
||||
), page.getByRole(AriaRole.CHECKBOX, new Page.GetByRoleOptions().setChecked(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
|
||||
assertEquals(asList(
|
||||
"<input type=\"checkbox\">",
|
||||
"<div role=\"checkbox\" aria-checked=\"false\">Hello</div>",
|
||||
"<div role=\"checkbox\">Unknown</div>"
|
||||
), page.locator("role=checkbox[checked=false]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<input type=\"checkbox\">",
|
||||
"<div role=\"checkbox\" aria-checked=\"false\">Hello</div>",
|
||||
"<div role=\"checkbox\">Unknown</div>"
|
||||
), page.getByRole(AriaRole.CHECKBOX, new Page.GetByRoleOptions().setChecked(false)).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
|
||||
assertEquals(asList(
|
||||
"<input type=\"checkbox\" indeterminate=\"\">"
|
||||
), page.locator("role=checkbox[checked='mixed']").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<input type=\"checkbox\">",
|
||||
"<input type=\"checkbox\" checked=\"\">",
|
||||
"<input type=\"checkbox\" indeterminate=\"\">",
|
||||
"<div role=\"checkbox\" aria-checked=\"true\">Hi</div>",
|
||||
"<div role=\"checkbox\" aria-checked=\"false\">Hello</div>",
|
||||
"<div role=\"checkbox\">Unknown</div>"
|
||||
), page.locator("role=checkbox").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSupportPressed() {
|
||||
page.setContent("<button>Hi</button>\n" +
|
||||
" <button aria-pressed=\"true\">Hello</button>\n" +
|
||||
" <button aria-pressed=\"false\">Bye</button>\n" +
|
||||
" <button aria-pressed=\"mixed\">Mixed</button>");
|
||||
assertEquals(asList(
|
||||
"<button aria-pressed=\"true\">Hello</button>"
|
||||
), page.locator("role=button[pressed]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<button aria-pressed=\"true\">Hello</button>"
|
||||
), page.locator("role=button[pressed=true]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<button aria-pressed=\"true\">Hello</button>"
|
||||
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setPressed(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<button>Hi</button>",
|
||||
"<button aria-pressed=\"false\">Bye</button>"
|
||||
), page.locator("role=button[pressed=false]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<button>Hi</button>",
|
||||
"<button aria-pressed=\"false\">Bye</button>"
|
||||
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setPressed(false)).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<button aria-pressed=\"mixed\">Mixed</button>"
|
||||
), page.locator("role=button[pressed='mixed']").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<button>Hi</button>",
|
||||
"<button aria-pressed=\"true\">Hello</button>",
|
||||
"<button aria-pressed=\"false\">Bye</button>",
|
||||
"<button aria-pressed=\"mixed\">Mixed</button>"
|
||||
), page.locator("role=button").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSupportExpanded() {
|
||||
page.setContent("<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(
|
||||
"<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(
|
||||
"<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(
|
||||
"<div role=\"treeitem\" aria-expanded=\"true\">Hello</div>"
|
||||
), page.locator("role=treeitem[expanded]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<div role=\"treeitem\" aria-expanded=\"true\">Hello</div>"
|
||||
), page.locator("role=treeitem[expanded=true]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<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
|
||||
void shouldSupportDisabled() {
|
||||
page.setContent("<button>Hi</button>\n" +
|
||||
" <button disabled>Bye</button>\n" +
|
||||
" <button aria-disabled=\"true\">Hello</button>\n" +
|
||||
" <button aria-disabled=\"false\">Oh</button>\n" +
|
||||
" <fieldset disabled>\n" +
|
||||
" <button>Yay</button>\n" +
|
||||
" </fieldset>");
|
||||
assertEquals(asList(
|
||||
"<button disabled=\"\">Bye</button>",
|
||||
"<button aria-disabled=\"true\">Hello</button>",
|
||||
"<button>Yay</button>"
|
||||
), page.locator("role=button[disabled]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<button disabled=\"\">Bye</button>",
|
||||
"<button aria-disabled=\"true\">Hello</button>",
|
||||
"<button>Yay</button>"
|
||||
), page.locator("role=button[disabled=true]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<button disabled=\"\">Bye</button>",
|
||||
"<button aria-disabled=\"true\">Hello</button>",
|
||||
"<button>Yay</button>"
|
||||
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setDisabled(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<button>Hi</button>",
|
||||
"<button aria-disabled=\"false\">Oh</button>"
|
||||
), page.locator("role=button[disabled=false]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<button>Hi</button>",
|
||||
"<button aria-disabled=\"false\">Oh</button>"
|
||||
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setDisabled(false)).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSupportLevel() {
|
||||
page.setContent("<h1>Hello</h1>\n" +
|
||||
" <h3>Hi</h3>\n" +
|
||||
" <div role=\"heading\" aria-level=\"5\">Bye</div>");
|
||||
assertEquals(asList(
|
||||
"<h1>Hello</h1>"
|
||||
), page.locator("role=heading[level=1]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<h1>Hello</h1>"
|
||||
), page.getByRole(AriaRole.HEADING, new Page.GetByRoleOptions().setLevel(1)).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<h3>Hi</h3>"
|
||||
), page.locator("role=heading[level=3]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<h3>Hi</h3>"
|
||||
), page.getByRole(AriaRole.HEADING, new Page.GetByRoleOptions().setLevel(3)).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<div role=\"heading\" aria-level=\"5\">Bye</div>"
|
||||
), page.locator("role=heading[level=5]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFilterHiddenUnlessExplicitlyAskedFor() {
|
||||
page.setContent("<button>Hi</button>\n" +
|
||||
" <button hidden>Hello</button>\n" +
|
||||
" <button aria-hidden=\"true\">Yay</button>\n" +
|
||||
" <button aria-hidden=\"false\">Nay</button>\n" +
|
||||
" <button style=\"visibility:hidden\">Bye</button>\n" +
|
||||
" <div style=\"visibility:hidden\">\n" +
|
||||
" <button>Oh</button>\n" +
|
||||
" </div>\n" +
|
||||
" <div style=\"visibility:hidden\">\n" +
|
||||
" <button style=\"visibility:visible\">Still here</button>\n" +
|
||||
" </div>\n" +
|
||||
" <button style=\"display:none\">Never</button>\n" +
|
||||
" <div id=host1></div>\n" +
|
||||
" <div id=host2 style=\"display:none\"></div>\n" +
|
||||
" <script>\n" +
|
||||
" function addButton(host, text) {\n" +
|
||||
" const root = host.attachShadow({ mode: 'open' });\n" +
|
||||
" const button = document.createElement('button');\n" +
|
||||
" button.textContent = text;\n" +
|
||||
" root.appendChild(button);\n" +
|
||||
" }\n" +
|
||||
" addButton(document.getElementById('host1'), 'Shadow1');\n" +
|
||||
" addButton(document.getElementById('host2'), 'Shadow2');\n" +
|
||||
" </script>");
|
||||
assertEquals(asList(
|
||||
"<button>Hi</button>",
|
||||
"<button aria-hidden=\"false\">Nay</button>",
|
||||
"<button style=\"visibility:visible\">Still here</button>",
|
||||
"<button>Shadow1</button>"
|
||||
), page.locator("role=button").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<button>Hi</button>",
|
||||
"<button hidden=\"\">Hello</button>",
|
||||
"<button aria-hidden=\"true\">Yay</button>",
|
||||
"<button aria-hidden=\"false\">Nay</button>",
|
||||
"<button style=\"visibility:hidden\">Bye</button>",
|
||||
"<button>Oh</button>",
|
||||
"<button style=\"visibility:visible\">Still here</button>",
|
||||
"<button style=\"display:none\">Never</button>",
|
||||
"<button>Shadow1</button>",
|
||||
"<button>Shadow2</button>"
|
||||
), page.locator("role=button[include-hidden]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<button>Hi</button>",
|
||||
"<button hidden=\"\">Hello</button>",
|
||||
"<button aria-hidden=\"true\">Yay</button>",
|
||||
"<button aria-hidden=\"false\">Nay</button>",
|
||||
"<button style=\"visibility:hidden\">Bye</button>",
|
||||
"<button>Oh</button>",
|
||||
"<button style=\"visibility:visible\">Still here</button>",
|
||||
"<button style=\"display:none\">Never</button>",
|
||||
"<button>Shadow1</button>",
|
||||
"<button>Shadow2</button>"
|
||||
), page.locator("role=button[include-hidden=true]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<button>Hi</button>",
|
||||
"<button aria-hidden=\"false\">Nay</button>",
|
||||
"<button style=\"visibility:visible\">Still here</button>",
|
||||
"<button>Shadow1</button>"
|
||||
), page.locator("role=button[include-hidden=false]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSupportName() {
|
||||
page.setContent("<div role=\"button\" aria-label=\" Hello \"></div>\n" +
|
||||
" <div role=\"button\" aria-label=\"Hallo\"></div>\n" +
|
||||
" <div role=\"button\" aria-label=\"Hello\" aria-hidden=\"true\"></div>\n" +
|
||||
" <div role=\"button\" aria-label=\"123\" aria-hidden=\"true\"></div>\n" +
|
||||
" <div role=\"button\" aria-label='foo\"bar' aria-hidden=\"true\"></div>");
|
||||
assertEquals(asList(
|
||||
"<div role=\"button\" aria-label=\" Hello \"></div>"
|
||||
), page.locator("role=button[name='Hello']").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<div role=\"button\" aria-label=\" Hello \"></div>"
|
||||
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName(" \n Hello ")).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<div role=\"button\" aria-label=\" Hello \"></div>"
|
||||
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Hello")).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
|
||||
assertEquals(asList(
|
||||
"<div role=\"button\" aria-label=\"Hallo\"></div>"
|
||||
), page.locator("role=button[name*='all']").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
|
||||
assertEquals(asList(
|
||||
"<div role=\"button\" aria-label=\" Hello \"></div>",
|
||||
"<div role=\"button\" aria-label=\"Hallo\"></div>"
|
||||
), page.locator("role=button[name=/^H[ae]llo$/]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<div role=\"button\" aria-label=\" Hello \"></div>",
|
||||
"<div role=\"button\" aria-label=\"Hallo\"></div>"
|
||||
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName(Pattern.compile("^H[ae]llo$"))).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
|
||||
assertEquals(asList(
|
||||
"<div role=\"button\" aria-label=\" Hello \"></div>",
|
||||
"<div role=\"button\" aria-label=\"Hallo\"></div>"
|
||||
), page.locator("role=button[name=/h.*o/i]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<div role=\"button\" aria-label=\" Hello \"></div>",
|
||||
"<div role=\"button\" aria-label=\"Hallo\"></div>"
|
||||
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName(Pattern.compile("h.*o", Pattern.CASE_INSENSITIVE))).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
|
||||
assertEquals(asList(
|
||||
"<div role=\"button\" aria-label=\" Hello \"></div>",
|
||||
"<div role=\"button\" aria-label=\"Hello\" aria-hidden=\"true\"></div>"
|
||||
), page.locator("role=button[name='Hello'][include-hidden]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<div role=\"button\" aria-label=\" Hello \"></div>",
|
||||
"<div role=\"button\" aria-label=\"Hello\" aria-hidden=\"true\"></div>"
|
||||
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Hello").setIncludeHidden(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<div role=\"button\" aria-label=\" Hello \"></div>",
|
||||
"<div role=\"button\" aria-label=\"Hello\" aria-hidden=\"true\"></div>"
|
||||
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("hello").setIncludeHidden(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
|
||||
assertEquals(asList(
|
||||
"<div role=\"button\" aria-label=\" Hello \"></div>"
|
||||
), page.locator("role=button[name=Hello]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<div role=\"button\" aria-label=\"123\" aria-hidden=\"true\"></div>"
|
||||
), page.locator("role=button[name=123][include-hidden]").evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
assertEquals(asList(
|
||||
"<div role=\"button\" aria-label=\"123\" aria-hidden=\"true\"></div>"
|
||||
), page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("123").setIncludeHidden(true)).evaluateAll("els => els.map(e => e.outerHTML)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void errors() {
|
||||
PlaywrightException e0 = assertThrows(PlaywrightException.class, () -> page.querySelector("role=[bar]"));
|
||||
assertTrue(e0.getMessage().contains("Role must not be empty"), e0.getMessage());
|
||||
|
||||
PlaywrightException e1 = assertThrows(PlaywrightException.class, () -> page.querySelector("role=foo[sElected]"));
|
||||
assertTrue(e1.getMessage().contains("Unknown attribute \"sElected\", must be one of \"checked\", \"disabled\", \"expanded\", \"include-hidden\", \"level\", \"name\", \"pressed\", \"selected\""), e1.getMessage());
|
||||
|
||||
PlaywrightException e2 = assertThrows(PlaywrightException.class, () -> page.querySelector("role=foo[bar . qux=true]"));
|
||||
assertTrue(e2.getMessage().contains("Unknown attribute \"bar.qux\""), e2.getMessage());
|
||||
|
||||
PlaywrightException e3 = assertThrows(PlaywrightException.class, () -> page.querySelector("role=heading[level='bar']"));
|
||||
assertTrue(e3.getMessage().contains("\"level\" attribute must be compared to a number"), e3.getMessage());
|
||||
|
||||
PlaywrightException e4 = assertThrows(PlaywrightException.class, () -> page.querySelector("role=checkbox[checked='bar']"));
|
||||
assertTrue(e4.getMessage().contains("\"checked\" must be one of true, false, \"mixed\""), e4.getMessage());
|
||||
|
||||
PlaywrightException e5 = assertThrows(PlaywrightException.class, () -> page.querySelector("role=checkbox[checked~=true]"));
|
||||
assertTrue(e5.getMessage().contains("cannot use ~= in attribute with non-string matching value"), e5.getMessage());
|
||||
|
||||
PlaywrightException e6 = assertThrows(PlaywrightException.class, () -> page.querySelector("role=button[level=3]"));
|
||||
assertTrue(e6.getMessage().contains("\"level\" attribute is only supported for roles: \"heading\", \"listitem\", \"row\", \"treeitem\""), e6.getMessage());
|
||||
|
||||
PlaywrightException e7 = assertThrows(PlaywrightException.class, () -> page.querySelector("role=button[name]"));
|
||||
assertTrue(e7.getMessage().contains("\"name\" attribute must have a value"), e7.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class TestSelectorsText extends TestBase {
|
||||
@Test
|
||||
void hasTextAndInternalTextShouldMatchFullNodeTextInStrictMode() {
|
||||
page.setContent("<div id=div1>hello<span>world</span></div>\n" +
|
||||
" <div id=div2>hello</div>");
|
||||
assertThat(page.getByText("helloworld", new Page.GetByTextOptions().setExact(true))).hasId("div1");
|
||||
assertThat(page.getByText("hello", new Page.GetByTextOptions().setExact(true))).hasId("div2");
|
||||
assertThat(page.locator("div", new Page.LocatorOptions().setHasText(Pattern.compile("^helloworld$")))).hasId("div1");
|
||||
assertThat(page.locator("div", new Page.LocatorOptions().setHasText(Pattern.compile("^hello$")))).hasId("div2");
|
||||
|
||||
page.setContent("<div id=div1><span id=span1>hello</span>world</div>\n" +
|
||||
" <div id=div2><span id=span2>hello</span></div>");
|
||||
assertThat(page.getByText("helloworld", new Page.GetByTextOptions().setExact(true))).hasId("div1");
|
||||
assertEquals(asList("span1", "span2"), page.getByText("hello", new Page.GetByTextOptions().setExact(true)).evaluateAll("els => els.map(e => e.id)"));
|
||||
assertThat(page.locator("div", new Page.LocatorOptions().setHasText(Pattern.compile("^helloworld$")))).hasId("div1");
|
||||
assertThat(page.locator("div", new Page.LocatorOptions().setHasText(Pattern.compile("^hello$")))).hasId("div2");
|
||||
}
|
||||
}
|
||||
@@ -114,6 +114,9 @@ class Utils {
|
||||
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipPath.toFile()))) {
|
||||
for (ZipEntry zipEntry = zis.getNextEntry(); zipEntry != null; zipEntry = zis.getNextEntry()) {
|
||||
Path toPath = toDir.resolve(zipEntry.getName());
|
||||
if (!toPath.normalize().startsWith(toDir.normalize())) {
|
||||
throw new IOException("Bad zip entry");
|
||||
}
|
||||
if (zipEntry.isDirectory()) {
|
||||
Files.createDirectories(toPath);
|
||||
} else {
|
||||
@@ -146,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");
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.26.0-SNAPSHOT</version>
|
||||
<version>1.29.0</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Playwright Parent Project</name>
|
||||
<description>Java library to automate Chromium, Firefox and WebKit with a single API.
|
||||
@@ -143,6 +143,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,11 +153,6 @@
|
||||
<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>
|
||||
@@ -169,31 +167,8 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</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>
|
||||
</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
@@ -1 +1 @@
|
||||
1.26.0
|
||||
1.29.2
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>api-generator</artifactId>
|
||||
<version>1.26.0-SNAPSHOT</version>
|
||||
<version>1.29.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));
|
||||
}
|
||||
}
|
||||
@@ -939,7 +952,7 @@ class Interface extends TypeDefinition {
|
||||
if (methods.stream().anyMatch(m -> "create".equals(m.jsonName))) {
|
||||
output.add("import com.microsoft.playwright.impl." + jsonName + "Impl;");
|
||||
}
|
||||
if (asList("Page", "Request", "Response", "APIRequestContext", "APIRequest", "APIResponse", "FileChooser", "Frame", "ElementHandle", "Locator", "Browser", "BrowserContext", "BrowserType", "Mouse", "Keyboard").contains(jsonName)) {
|
||||
if (asList("Page", "Request", "Response", "APIRequestContext", "APIRequest", "APIResponse", "FileChooser", "Frame", "FrameLocator", "ElementHandle", "Locator", "Browser", "BrowserContext", "BrowserType", "Mouse", "Keyboard").contains(jsonName)) {
|
||||
output.add("import com.microsoft.playwright.options.*;");
|
||||
}
|
||||
if ("Download".equals(jsonName)) {
|
||||
|
||||
@@ -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.29.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>
|
||||
+28
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+10
@@ -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
|
||||
@@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>test-cli-version</artifactId>
|
||||
<version>1.26.0-SNAPSHOT</version>
|
||||
<version>1.29.0</version>
|
||||
<name>Test Playwright Command Line Version</name>
|
||||
<properties>
|
||||
<compiler.version>1.8</compiler.version>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>test-local-installation</artifactId>
|
||||
<version>1.26.0-SNAPSHOT</version>
|
||||
<version>1.29.0</version>
|
||||
<name>Test local installation</name>
|
||||
<description>Runs Playwright test suite (copied from playwright module) against locally cached Playwright</description>
|
||||
<properties>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
</parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>test-spring-boot-starter</artifactId>
|
||||
<version>1.26.0-SNAPSHOT</version>
|
||||
<version>1.29.0</version>
|
||||
<name>Test Playwright With Spring Boot</name>
|
||||
<properties>
|
||||
<spring.version>2.4.3</spring.version>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>update-version</artifactId>
|
||||
<version>1.26.0-SNAPSHOT</version>
|
||||
<version>1.29.0</version>
|
||||
<name>Playwright - Update Version in Documentation</name>
|
||||
<description>
|
||||
This is an internal module used to update versions in the documentation based on
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
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 ===
|
||||
|
||||
RUN apt-get update && \
|
||||
# Install install jdk 17 in a separate apt-get command so that
|
||||
# installing maven doesn't bring in jdk 11
|
||||
apt-get install -y --no-install-recommends openjdk-17-jdk && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
openjdk-17-jdk maven \
|
||||
# Ubuntu 22.04 and earlier come with Maven 3.6.3 which fails with
|
||||
# Java 17, so we install latest Maven from Apache instead.
|
||||
# maven \
|
||||
# Install utilities required for downloading browsers
|
||||
curl \
|
||||
# Install utilities required for downloading driver
|
||||
@@ -17,8 +24,12 @@ RUN apt-get update && \
|
||||
# Create the pwuser
|
||||
adduser pwuser
|
||||
|
||||
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/
|
||||
|
||||
ARG PW_TARGET_ARCH
|
||||
ENV JAVA_HOME=/usr/lib/jvm/java-11-openjdk-${PW_TARGET_ARCH}
|
||||
ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk-${PW_TARGET_ARCH}
|
||||
|
||||
# === BAKE BROWSERS INTO IMAGE ===
|
||||
|
||||
|
||||
Reference in New Issue
Block a user