Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c1c538c7dc | |||
| bfc7645d20 | |||
| c34a35d6a7 |
@@ -1,62 +0,0 @@
|
||||
trigger:
|
||||
none
|
||||
|
||||
# don't trigger for Pull Requests
|
||||
pr: 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@4
|
||||
inputs:
|
||||
ConnectedServiceName: 'Playwright-ESRP'
|
||||
Intent: 'PackageDistribution'
|
||||
ContentType: 'Maven'
|
||||
ContentSource: 'Folder'
|
||||
FolderLocation: './local-build'
|
||||
WaitForReleaseCompletion: true
|
||||
Owners: 'yurys@microsoft.com'
|
||||
Approvers: 'maxschmitt@microsoft.com'
|
||||
ServiceEndpointUrl: 'https://api.esrp.microsoft.com'
|
||||
MainPublisher: 'Playwright'
|
||||
DomainTenantId: '72f988bf-86f1-41af-91ab-2d7cd011db47'
|
||||
displayName: 'ESRP Release to Maven'
|
||||
@@ -7,34 +7,19 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- ⚠️⚠️ Do not delete this template ⚠️⚠️ -->
|
||||
**Context:**
|
||||
- Playwright Version: [what Playwright version do you use?]
|
||||
- Operating System: [e.g. Windows, Linux or Mac]
|
||||
- Browser: [e.g. All, Chromium, Firefox, WebKit]
|
||||
- Extra: [any specific details about your environment]
|
||||
|
||||
<!-- 🔎 Search existing issues to avoid creating duplicates. -->
|
||||
<!-- 🧪 Test using the latest Playwright release to see if your issue has already been fixed -->
|
||||
<!-- 💡 Provide enough information for us to be able to reproduce your issue locally -->
|
||||
<!-- CLI to auto-capture this info -->
|
||||
<!-- npx envinfo --preset playwright --markdown -->
|
||||
|
||||
### System info
|
||||
- Playwright Version: [v1.XX]
|
||||
- Operating System: [All, Windows 11, Ubuntu 20, macOS 13.2, etc.]
|
||||
- Browser: [All, Chromium, Firefox, WebKit]
|
||||
- Other info:
|
||||
**Code Snippet**
|
||||
|
||||
### Source code
|
||||
|
||||
- [ ] I provided exact source code that allows reproducing the issue locally.
|
||||
|
||||
<!-- For simple cases, please provide a self-contained test file along with the config file -->
|
||||
<!-- For larger cases, you can provide a GitHub repo you created for this issue -->
|
||||
<!-- If we can not reproduce the problem locally, we won't be able to act on it -->
|
||||
<!-- You can still file without the exact code and we will try to help, but if we can't repro, it will be closed -->
|
||||
|
||||
**Link to the GitHub repository with the repro**
|
||||
|
||||
[https://github.com/your_profile/playwright_issue_title]
|
||||
|
||||
or
|
||||
|
||||
**Test file (self-contained)**
|
||||
Help us help you! Put down a short code snippet that illustrates your bug and
|
||||
that we can run and debug locally. For example:
|
||||
|
||||
```java
|
||||
import com.microsoft.playwright.*;
|
||||
@@ -51,14 +36,6 @@ public class ExampleReproducible {
|
||||
}
|
||||
```
|
||||
|
||||
**Steps**
|
||||
- [Run the test]
|
||||
- [...]
|
||||
**Describe the bug**
|
||||
|
||||
**Expected**
|
||||
|
||||
[Describe expected behavior]
|
||||
|
||||
**Actual**
|
||||
|
||||
[Describe actual behavior]
|
||||
Add any other details about the problem here.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
contact_links:
|
||||
- name: Join our Discord Server
|
||||
url: https://aka.ms/playwright/discord
|
||||
about: Ask questions and discuss with other community members
|
||||
- name: Join our Slack community
|
||||
url: https://aka.ms/playwright-slack
|
||||
about: Ask questions and discuss with other community members
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: I have a question
|
||||
about: Feel free to ask us your questions!
|
||||
title: "[Question]"
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
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 }}
|
||||
@@ -31,11 +31,11 @@ jobs:
|
||||
- name: Build & Install
|
||||
run: mvn -B install -D skipTests --no-transfer-progress
|
||||
- name: Run tests
|
||||
run: mvn test --no-transfer-progress --fail-at-end -D org.slf4j.simpleLogger.showDateTime=true -D org.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss
|
||||
run: mvn test --no-transfer-progress --fail-at-end
|
||||
env:
|
||||
BROWSER: ${{ matrix.browser }}
|
||||
- name: Run tracing tests w/ sources
|
||||
run: mvn test --no-transfer-progress --fail-at-end -D test=*TestTracing* -D org.slf4j.simpleLogger.showDateTime=true -D org.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss
|
||||
run: mvn test --no-transfer-progress --fail-at-end -D test=*TestTracing*
|
||||
env:
|
||||
BROWSER: ${{ matrix.browser }}
|
||||
PLAYWRIGHT_JAVA_SRC: src/test/java
|
||||
@@ -79,7 +79,7 @@ jobs:
|
||||
- name: Build & Install
|
||||
run: mvn -B install -D skipTests --no-transfer-progress
|
||||
- name: Run tests
|
||||
run: mvn test --no-transfer-progress --fail-at-end -D org.slf4j.simpleLogger.showDateTime=true -D org.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss
|
||||
run: mvn test --no-transfer-progress --fail-at-end
|
||||
env:
|
||||
BROWSER: chromium
|
||||
BROWSER_CHANNEL: ${{ matrix.browser-channel }}
|
||||
|
||||
@@ -29,6 +29,3 @@ 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Docker
|
||||
name: Test Docker
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
@@ -18,18 +18,13 @@ on:
|
||||
- release-*
|
||||
jobs:
|
||||
test:
|
||||
name: Test
|
||||
timeout-minutes: 120
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
flavor: [focal, jammy]
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build Docker image
|
||||
run: bash utils/docker/build.sh --amd64 ${{ matrix.flavor }} playwright-java:localbuild-${{ matrix.flavor }}
|
||||
run: bash utils/docker/build.sh --amd64 focal playwright-java:localbuild-focal
|
||||
- name: Test
|
||||
run: |
|
||||
CONTAINER_ID="$(docker run --rm --ipc=host -v $(pwd):/root/playwright --name playwright-docker-test -d -t playwright-java:localbuild-${{ matrix.flavor }} /bin/bash)"
|
||||
CONTAINER_ID="$(docker run --rm --ipc=host -v $(pwd):/root/playwright --name playwright-docker-test -d -t playwright-java:localbuild-focal /bin/bash)"
|
||||
docker exec "${CONTAINER_ID}" /root/playwright/tools/test-local-installation/create_project_and_run_tests.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-browsers/dispatches
|
||||
https://api.github.com/repos/microsoft/playwright-internal/dispatches
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.REPOSITORY_DISPATCH_PERSONAL_ACCESS_TOKEN }}
|
||||
|
||||
@@ -11,11 +11,11 @@ Playwright is a Java library to automate [Chromium](https://www.chromium.org/Hom
|
||||
|
||||
| | Linux | macOS | Windows |
|
||||
| :--- | :---: | :---: | :---: |
|
||||
| Chromium <!-- GEN:chromium-version -->121.0.6167.57<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| WebKit <!-- GEN:webkit-version -->17.4<!-- GEN:stop --> | ✅ | ✅ | ✅ |
|
||||
| Firefox <!-- GEN:firefox-version -->121.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| 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: |
|
||||
|
||||
Headless execution is supported for all the browsers on all platforms. Check out [system requirements](https://playwright.dev/java/docs/intro#system-requirements) for details.
|
||||
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.
|
||||
|
||||
* [Usage](#usage)
|
||||
- [Add Maven dependency](#add-maven-dependency)
|
||||
@@ -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.28.1</version>
|
||||
<version>1.17.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
To run Playwright using Gradle add following dependency to your build.gradle file:
|
||||
|
||||
```gradle
|
||||
```json lines
|
||||
dependencies {
|
||||
implementation group: 'com.microsoft.playwright', name: 'playwright', version: '1.28.1'
|
||||
implementation group: 'com.microsoft.playwright', name: 'playwright', version: '1.25.0'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -65,7 +65,7 @@ You can find Maven project with the examples [here](./examples).
|
||||
|
||||
#### Page screenshot
|
||||
|
||||
This code snippet navigates to Playwright homepage in Chromium, Firefox and WebKit, and saves 3 screenshots.
|
||||
This code snippet navigates to whatsmyuseragent.org in Chromium, Firefox and WebKit, and saves 3 screenshots.
|
||||
|
||||
```java
|
||||
import com.microsoft.playwright.*;
|
||||
@@ -86,7 +86,7 @@ public class PageScreenshot {
|
||||
try (Browser browser = browserType.launch()) {
|
||||
BrowserContext context = browser.newContext();
|
||||
Page page = context.newPage();
|
||||
page.navigate("https://playwright.dev/");
|
||||
page.navigate("http://whatsmyuseragent.org/");
|
||||
page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("screenshot-" + browserType.name() + ".png")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,15 +6,8 @@
|
||||
* regenerate API: `./scripts/download_driver_for_all_platforms.sh -f && ./scripts/generate_api.sh && ./scripts/update_readme.sh`
|
||||
* commit & send PR with the roll
|
||||
|
||||
### Finding driver version
|
||||
|
||||
For development versions of Playwright, you can find the latest version by looking at [publish_canary](https://github.com/microsoft/playwright/actions/workflows/publish_canary.yml) workflow -> `publish canary NPM & Publish canary Docker` -> `build & publish driver` step -> `PACKAGE_VERSION`
|
||||
<img width="960" alt="image" src="https://github.com/microsoft/playwright-java/assets/9798949/4f33a7f1-b39a-4179-8ae7-fb1d84094c75">
|
||||
|
||||
|
||||
# Updating Version
|
||||
|
||||
```bash
|
||||
./scripts/set_maven_version.sh 1.15.0
|
||||
```
|
||||
|
||||
|
||||
+20
-1
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.41.2</version>
|
||||
<version>1.26.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>driver-bundle</artifactId>
|
||||
@@ -16,6 +16,25 @@
|
||||
It is intended to be used on the systems where Playwright driver is not preinstalled.
|
||||
</description>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludeResources>true</excludeResources>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
|
||||
+5
-20
@@ -106,25 +106,14 @@ public class DriverJar extends Driver {
|
||||
return name.endsWith(".sh") || name.endsWith(".exe") || !name.contains(".");
|
||||
}
|
||||
|
||||
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();
|
||||
return classloader.getResource("driver/" + platformDir()).toURI();
|
||||
}
|
||||
|
||||
void extractDriverToTempDir() throws URISyntaxException, IOException {
|
||||
URI originalUri = getDriverResourceURI();
|
||||
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
|
||||
URI originalUri = classloader.getResource(
|
||||
"driver/" + platformDir()).toURI();
|
||||
URI uri = maybeExtractNestedJar(originalUri);
|
||||
|
||||
// Create zip filesystem if loading from jar.
|
||||
try (FileSystem fileSystem = "jar".equals(uri.getScheme()) ? initFileSystem(uri) : null) {
|
||||
try (FileSystem fileSystem = "jar".equals(uri.getScheme()) ? FileSystems.newFileSystem(uri, Collections.emptyMap()) : 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
|
||||
@@ -194,11 +183,7 @@ public class DriverJar extends Driver {
|
||||
}
|
||||
}
|
||||
if (name.contains("mac os x")) {
|
||||
if (arch.equals("aarch64")) {
|
||||
return "mac-arm64";
|
||||
} else {
|
||||
return "mac";
|
||||
}
|
||||
return "mac";
|
||||
}
|
||||
throw new RuntimeException("Unexpected os.name value: " + name);
|
||||
}
|
||||
|
||||
@@ -17,11 +17,13 @@
|
||||
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;
|
||||
|
||||
+17
-1
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.41.2</version>
|
||||
<version>1.26.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>driver</artifactId>
|
||||
@@ -15,6 +15,22 @@
|
||||
This module provides API for discovery and launching of Playwright driver.
|
||||
</description>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>org.example</groupId>
|
||||
<artifactId>examples</artifactId>
|
||||
<version>1.41.2</version>
|
||||
<version>1.26.1</version>
|
||||
<name>Playwright Client Examples</name>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
@@ -15,7 +15,7 @@
|
||||
<dependency>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>playwright</artifactId>
|
||||
<version>1.30.0</version>
|
||||
<version>1.22.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
|
||||
@@ -34,7 +34,7 @@ public class PageScreenshot {
|
||||
try (Browser browser = browserType.launch()) {
|
||||
BrowserContext context = browser.newContext();
|
||||
Page page = context.newPage();
|
||||
page.navigate("https://playwright.dev/");
|
||||
page.navigate("http://whatsmyuseragent.org/");
|
||||
page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("screenshot-" + browserType.name() + ".png")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public class WebKitScreenshot {
|
||||
try (Playwright playwright = Playwright.create()) {
|
||||
Browser browser = playwright.webkit().launch();
|
||||
Page page = browser.newPage();
|
||||
page.navigate("https://playwright.dev/");
|
||||
page.navigate("http://whatsmyuseragent.org/");
|
||||
page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("example.png")));
|
||||
}
|
||||
}
|
||||
|
||||
+14
-2
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>1.41.2</version>
|
||||
<version>1.26.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>playwright</artifactId>
|
||||
@@ -21,14 +21,26 @@
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<configuration combine.self="append">
|
||||
<configuration>
|
||||
<subpackages>com.microsoft.playwright</subpackages>
|
||||
<excludePackageNames>com.microsoft.playwright.impl</excludePackageNames>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
|
||||
@@ -21,33 +21,31 @@ 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>
|
||||
*/
|
||||
public String baseURL;
|
||||
/**
|
||||
* An object containing additional HTTP headers to be sent with every request. Defaults to none.
|
||||
* An object containing additional HTTP headers to be sent with every request.
|
||||
*/
|
||||
public Map<String, String> extraHTTPHeaders;
|
||||
/**
|
||||
* Credentials for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication">HTTP authentication</a>. If
|
||||
* no origin is specified, the username and password are sent to any servers upon unauthorized responses.
|
||||
* Credentials for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication">HTTP authentication</a>.
|
||||
*/
|
||||
public HttpCredentials httpCredentials;
|
||||
/**
|
||||
@@ -73,8 +71,7 @@ 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;
|
||||
/**
|
||||
@@ -84,13 +81,12 @@ 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>
|
||||
@@ -100,22 +96,20 @@ public interface APIRequest {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* An object containing additional HTTP headers to be sent with every request. Defaults to none.
|
||||
* An object containing additional HTTP headers to be sent with every request.
|
||||
*/
|
||||
public NewContextOptions setExtraHTTPHeaders(Map<String, String> extraHTTPHeaders) {
|
||||
this.extraHTTPHeaders = extraHTTPHeaders;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Credentials for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication">HTTP authentication</a>. If
|
||||
* no origin is specified, the username and password are sent to any servers upon unauthorized responses.
|
||||
* Credentials for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication">HTTP authentication</a>.
|
||||
*/
|
||||
public NewContextOptions setHttpCredentials(String username, String password) {
|
||||
return setHttpCredentials(new HttpCredentials(username, password));
|
||||
}
|
||||
/**
|
||||
* Credentials for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication">HTTP authentication</a>. If
|
||||
* no origin is specified, the username and password are sent to any servers upon unauthorized responses.
|
||||
* Credentials for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication">HTTP authentication</a>.
|
||||
*/
|
||||
public NewContextOptions setHttpCredentials(HttpCredentials httpCredentials) {
|
||||
this.httpCredentials = httpCredentials;
|
||||
@@ -162,8 +156,7 @@ 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;
|
||||
@@ -179,16 +172,12 @@ 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,7 +63,6 @@ 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);
|
||||
@@ -75,157 +74,46 @@ 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 its resources,
|
||||
* calling any method on disposed {@code APIRequestContext} will throw an exception.
|
||||
*
|
||||
* @since v1.16
|
||||
* 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.
|
||||
*/
|
||||
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. 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>
|
||||
* context cookies from the response. The method will automatically follow redirects.
|
||||
*
|
||||
* @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. 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>
|
||||
* context cookies from the response. The method will automatically follow redirects.
|
||||
*
|
||||
* @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. 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>
|
||||
* context cookies from the response. The method will automatically follow redirects.
|
||||
*
|
||||
* @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. 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>
|
||||
* context cookies from the response. The method will automatically follow redirects.
|
||||
*
|
||||
* @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);
|
||||
/**
|
||||
@@ -233,17 +121,7 @@ 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);
|
||||
@@ -253,18 +131,8 @@ public interface APIRequestContext {
|
||||
* response. The method will populate request cookies from the context and update context cookies from the response. The
|
||||
* method will automatically follow redirects.
|
||||
*
|
||||
* <p> **Usage**
|
||||
*
|
||||
* <p> Request parameters can be configured with {@code params} option, they will be serialized into the URL search parameters:
|
||||
* <pre>{@code
|
||||
* request.get("https://example.com/api/getText", RequestOptions.create()
|
||||
* .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);
|
||||
/**
|
||||
@@ -273,7 +141,6 @@ public interface APIRequestContext {
|
||||
* method will automatically follow redirects.
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @since v1.16
|
||||
*/
|
||||
default APIResponse head(String url) {
|
||||
return head(url, null);
|
||||
@@ -285,7 +152,6 @@ public interface APIRequestContext {
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @param params Optional request parameters.
|
||||
* @since v1.16
|
||||
*/
|
||||
APIResponse head(String url, RequestOptions params);
|
||||
/**
|
||||
@@ -294,7 +160,6 @@ 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);
|
||||
@@ -306,7 +171,6 @@ public interface APIRequestContext {
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @param params Optional request parameters.
|
||||
* @since v1.16
|
||||
*/
|
||||
APIResponse patch(String url, RequestOptions params);
|
||||
/**
|
||||
@@ -314,44 +178,7 @@ 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);
|
||||
@@ -361,45 +188,8 @@ public interface APIRequestContext {
|
||||
* response. The method will populate request cookies from the context and update context cookies from the response. The
|
||||
* method will automatically follow redirects.
|
||||
*
|
||||
* <p> **Usage**
|
||||
*
|
||||
* <p> JSON objects can be passed directly to the request:
|
||||
* <pre>{@code
|
||||
* Map<String, Object> data = new HashMap();
|
||||
* 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);
|
||||
/**
|
||||
@@ -408,7 +198,6 @@ public interface APIRequestContext {
|
||||
* method will automatically follow redirects.
|
||||
*
|
||||
* @param url Target URL.
|
||||
* @since v1.16
|
||||
*/
|
||||
default APIResponse put(String url) {
|
||||
return put(url, null);
|
||||
@@ -420,14 +209,11 @@ 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);
|
||||
@@ -435,8 +221,6 @@ 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,63 +20,45 @@ 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();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,7 +20,6 @@ import com.microsoft.playwright.options.*;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -58,62 +57,17 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*/
|
||||
void offClose(Consumer<BrowserContext> handler);
|
||||
|
||||
/**
|
||||
* Emitted when JavaScript within the page calls one of console API methods, e.g. {@code console.log} or {@code
|
||||
* console.dir}. Also emitted if the page throws an error or a warning.
|
||||
*
|
||||
* <p> The arguments passed into {@code console.log} and the page are available on the {@code ConsoleMessage} event handler
|
||||
* argument.
|
||||
*
|
||||
* <p> **Usage**
|
||||
* <pre>{@code
|
||||
* context.onConsoleMessage(msg -> {
|
||||
* for (int i = 0; i < msg.args().size(); ++i)
|
||||
* System.out.println(i + ": " + msg.args().get(i).jsonValue());
|
||||
* });
|
||||
* page.evaluate("() => console.log('hello', 5, { foo: 'bar' })");
|
||||
* }</pre>
|
||||
*/
|
||||
void onConsoleMessage(Consumer<ConsoleMessage> handler);
|
||||
/**
|
||||
* Removes handler that was previously added with {@link #onConsoleMessage onConsoleMessage(handler)}.
|
||||
*/
|
||||
void offConsoleMessage(Consumer<ConsoleMessage> handler);
|
||||
|
||||
/**
|
||||
* Emitted when a JavaScript dialog appears, such as {@code alert}, {@code prompt}, {@code confirm} or {@code
|
||||
* beforeunload}. Listener **must** either {@link Dialog#accept Dialog.accept()} or {@link Dialog#dismiss Dialog.dismiss()}
|
||||
* the dialog - otherwise the page will <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#never_blocking">freeze</a> waiting for the
|
||||
* dialog, and actions like click will never finish.
|
||||
*
|
||||
* <p> **Usage**
|
||||
* <pre>{@code
|
||||
* context.onDialog(dialog -> {
|
||||
* dialog.accept();
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> When no {@link Page#onDialog Page.onDialog()} or {@link BrowserContext#onDialog BrowserContext.onDialog()} listeners are
|
||||
* present, all dialogs are automatically dismissed.
|
||||
*/
|
||||
void onDialog(Consumer<Dialog> handler);
|
||||
/**
|
||||
* Removes handler that was previously added with {@link #onDialog onDialog(handler)}.
|
||||
*/
|
||||
void offDialog(Consumer<Dialog> handler);
|
||||
|
||||
/**
|
||||
* The event is emitted when a new Page is created in the BrowserContext. The page may still be loading. The event will
|
||||
* also fire for popup pages. See also {@link Page#onPopup Page.onPopup()} to receive events about popups relevant to a
|
||||
* 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.getByText("open new page").click();
|
||||
* page.locator("a[target=_blank]").click();
|
||||
* });
|
||||
* System.out.println(newPage.evaluate("location.href"));
|
||||
* }</pre>
|
||||
@@ -127,16 +81,6 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*/
|
||||
void offPage(Consumer<Page> handler);
|
||||
|
||||
/**
|
||||
* Emitted when exception is unhandled in any of the pages in this context. To listen for errors from a particular page,
|
||||
* use {@link Page#onPageError Page.onPageError()} instead.
|
||||
*/
|
||||
void onWebError(Consumer<WebError> handler);
|
||||
/**
|
||||
* Removes handler that was previously added with {@link #onWebError onWebError(handler)}.
|
||||
*/
|
||||
void offWebError(Consumer<WebError> handler);
|
||||
|
||||
/**
|
||||
* Emitted when a request is issued from any pages created through this context. The [request] object is read-only. To only
|
||||
* listen for requests from a particular page, use {@link Page#onRequest Page.onRequest()}.
|
||||
@@ -166,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);
|
||||
/**
|
||||
@@ -177,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);
|
||||
/**
|
||||
@@ -186,20 +130,6 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*/
|
||||
void offResponse(Consumer<Response> handler);
|
||||
|
||||
class CloseOptions {
|
||||
/**
|
||||
* The reason to be reported to the operations interrupted by the context closure.
|
||||
*/
|
||||
public String reason;
|
||||
|
||||
/**
|
||||
* The reason to be reported to the operations interrupted by the context closure.
|
||||
*/
|
||||
public CloseOptions setReason(String reason) {
|
||||
this.reason = reason;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class ExposeBindingOptions {
|
||||
/**
|
||||
* Whether to pass the argument as a handle, instead of passing by value. When passing a handle, only one argument is
|
||||
@@ -255,21 +185,9 @@ public interface BrowserContext extends AutoCloseable {
|
||||
*/
|
||||
public HarNotFound notFound;
|
||||
/**
|
||||
* 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.
|
||||
* If specified, updates the given HAR with the actual network information instead of serving from file.
|
||||
*/
|
||||
public Boolean update;
|
||||
/**
|
||||
* Optional setting to control resource content management. If {@code attach} is specified, resources are persisted as
|
||||
* separate files or entries in the ZIP archive. If {@code embed} is specified, content is stored inline the HAR file.
|
||||
*/
|
||||
public RouteFromHarUpdateContentPolicy updateContent;
|
||||
/**
|
||||
* 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
|
||||
* minimal}.
|
||||
*/
|
||||
public HarMode updateMode;
|
||||
/**
|
||||
* A glob pattern, regular expression or predicate to match the request URL. Only requests with URL matching the pattern
|
||||
* will be served from the HAR file. If not specified, all requests are served from the HAR file.
|
||||
@@ -289,30 +207,12 @@ public interface BrowserContext extends AutoCloseable {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 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.
|
||||
* If specified, updates the given HAR with the actual network information instead of serving from file.
|
||||
*/
|
||||
public RouteFromHAROptions setUpdate(boolean update) {
|
||||
this.update = update;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Optional setting to control resource content management. If {@code attach} is specified, resources are persisted as
|
||||
* separate files or entries in the ZIP archive. If {@code embed} is specified, content is stored inline the HAR file.
|
||||
*/
|
||||
public RouteFromHAROptions setUpdateContent(RouteFromHarUpdateContentPolicy updateContent) {
|
||||
this.updateContent = updateContent;
|
||||
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
|
||||
* minimal}.
|
||||
*/
|
||||
public RouteFromHAROptions setUpdateMode(HarMode updateMode) {
|
||||
this.updateMode = updateMode;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* A glob pattern, regular expression or predicate to match the request URL. Only requests with URL matching the pattern
|
||||
* will be served from the HAR file. If not specified, all requests are served from the HAR file.
|
||||
@@ -346,59 +246,14 @@ public interface BrowserContext extends AutoCloseable {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class WaitForConditionOptions {
|
||||
/**
|
||||
* 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()} or
|
||||
* {@link Page#setDefaultTimeout Page.setDefaultTimeout()} methods.
|
||||
*/
|
||||
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()} or
|
||||
* {@link Page#setDefaultTimeout Page.setDefaultTimeout()} methods.
|
||||
*/
|
||||
public WaitForConditionOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class WaitForConsoleMessageOptions {
|
||||
/**
|
||||
* Receives the {@code ConsoleMessage} object and resolves to truthy value when the waiting should resolve.
|
||||
*/
|
||||
public Predicate<ConsoleMessage> 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()}.
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* Receives the {@code ConsoleMessage} object and resolves to truthy value when the waiting should resolve.
|
||||
*/
|
||||
public WaitForConsoleMessageOptions setPredicate(Predicate<ConsoleMessage> predicate) {
|
||||
this.predicate = predicate;
|
||||
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()}.
|
||||
*/
|
||||
public WaitForConsoleMessageOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class WaitForPageOptions {
|
||||
/**
|
||||
* Receives the {@code Page} object and resolves to truthy value when the waiting should resolve.
|
||||
*/
|
||||
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;
|
||||
|
||||
@@ -410,8 +265,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;
|
||||
@@ -421,16 +276,9 @@ 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>
|
||||
*
|
||||
* @param cookies Adds cookies to the browser context.
|
||||
*
|
||||
* <p> For the cookie to apply to all subdomains as well, prefix domain with a dot, like this: ".example.com".
|
||||
* @since v1.8
|
||||
*/
|
||||
void addCookies(List<Cookie> cookies);
|
||||
/**
|
||||
@@ -444,8 +292,6 @@ 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.
|
||||
@@ -456,7 +302,6 @@ 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);
|
||||
/**
|
||||
@@ -470,8 +315,6 @@ 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.
|
||||
@@ -482,58 +325,35 @@ 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
|
||||
*/
|
||||
default void close() {
|
||||
close(null);
|
||||
}
|
||||
/**
|
||||
* 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(CloseOptions options);
|
||||
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);
|
||||
@@ -543,7 +363,6 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* are returned.
|
||||
*
|
||||
* @param urls Optional list of URLs.
|
||||
* @since v1.8
|
||||
*/
|
||||
List<Cookie> cookies(String urls);
|
||||
/**
|
||||
@@ -551,24 +370,21 @@ 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.*;
|
||||
@@ -588,7 +404,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* "</script>\n" +
|
||||
* "<button onclick=\"onClick()\">Click me</button>\n" +
|
||||
* "<div></div>");
|
||||
* page.getByRole(AriaRole.BUTTON).click();
|
||||
* page.locator("button").click();
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
@@ -611,26 +427,23 @@ 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.*;
|
||||
@@ -650,7 +463,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* "</script>\n" +
|
||||
* "<button onclick=\"onClick()\">Click me</button>\n" +
|
||||
* "<div></div>");
|
||||
* page.getByRole(AriaRole.BUTTON).click();
|
||||
* page.locator("button").click();
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
@@ -673,12 +486,11 @@ 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}.
|
||||
*
|
||||
@@ -688,8 +500,6 @@ 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.*;
|
||||
@@ -723,7 +533,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* "</script>\n" +
|
||||
* "<button onclick=\"onClick()\">Click me</button>\n" +
|
||||
* "<div></div>\n");
|
||||
* page.getByRole(AriaRole.BUTTON).click();
|
||||
* page.locator("button").click();
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
@@ -731,7 +541,6 @@ 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);
|
||||
/**
|
||||
@@ -756,7 +565,6 @@ 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);
|
||||
@@ -783,45 +591,18 @@ 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);
|
||||
/**
|
||||
* <strong>NOTE:</strong> CDP sessions are only supported on Chromium-based browsers.
|
||||
*
|
||||
* <p> Returns the newly created session.
|
||||
*
|
||||
* @param page Target to create new session for. For backwards-compatibility, this parameter is named {@code page}, but it can be a
|
||||
* {@code Page} or {@code Frame} type.
|
||||
* @since v1.11
|
||||
*/
|
||||
CDPSession newCDPSession(Page page);
|
||||
/**
|
||||
* <strong>NOTE:</strong> CDP sessions are only supported on Chromium-based browsers.
|
||||
*
|
||||
* <p> Returns the newly created session.
|
||||
*
|
||||
* @param page Target to create new session for. For backwards-compatibility, this parameter is named {@code page}, but it can be a
|
||||
* {@code Page} or {@code Frame} type.
|
||||
* @since v1.11
|
||||
*/
|
||||
CDPSession newCDPSession(Frame page);
|
||||
/**
|
||||
* 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();
|
||||
/**
|
||||
@@ -832,8 +613,6 @@ 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();
|
||||
@@ -870,11 +649,10 @@ 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);
|
||||
@@ -887,8 +665,6 @@ 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();
|
||||
@@ -925,11 +701,10 @@ 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);
|
||||
/**
|
||||
@@ -940,8 +715,6 @@ 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();
|
||||
@@ -978,11 +751,10 @@ 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);
|
||||
@@ -995,8 +767,6 @@ 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();
|
||||
@@ -1033,11 +803,10 @@ 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);
|
||||
/**
|
||||
@@ -1048,8 +817,6 @@ 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();
|
||||
@@ -1086,11 +853,10 @@ 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);
|
||||
@@ -1103,8 +869,6 @@ 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();
|
||||
@@ -1141,39 +905,36 @@ 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);
|
||||
/**
|
||||
* If specified the network requests that are made in the context will be served from the HAR file. Read more about <a
|
||||
* href="https://playwright.dev/java/docs/mock#replaying-from-har">Replaying from HAR</a>.
|
||||
* href="https://playwright.dev/java/docs/network#replaying-from-har">Replaying from HAR</a>.
|
||||
*
|
||||
* <p> Playwright will not serve requests intercepted by Service Worker from the HAR file. See <a
|
||||
* 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.
|
||||
* @since v1.23
|
||||
* @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.
|
||||
*/
|
||||
default void routeFromHAR(Path har) {
|
||||
routeFromHAR(har, null);
|
||||
}
|
||||
/**
|
||||
* If specified the network requests that are made in the context will be served from the HAR file. Read more about <a
|
||||
* href="https://playwright.dev/java/docs/mock#replaying-from-har">Replaying from HAR</a>.
|
||||
* href="https://playwright.dev/java/docs/network#replaying-from-har">Replaying from HAR</a>.
|
||||
*
|
||||
* <p> Playwright will not serve requests intercepted by Service Worker from the HAR file. See <a
|
||||
* 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.
|
||||
* @since v1.23
|
||||
* @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.
|
||||
*/
|
||||
void routeFromHAR(Path har, RouteFromHAROptions options);
|
||||
/**
|
||||
@@ -1192,7 +953,6 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* BrowserContext.setDefaultNavigationTimeout()}.
|
||||
*
|
||||
* @param timeout Maximum navigation time in milliseconds
|
||||
* @since v1.8
|
||||
*/
|
||||
void setDefaultNavigationTimeout(double timeout);
|
||||
/**
|
||||
@@ -1204,7 +964,6 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* BrowserContext.setDefaultTimeout()}.
|
||||
*
|
||||
* @param timeout Maximum time in milliseconds
|
||||
* @since v1.8
|
||||
*/
|
||||
void setDefaultTimeout(double timeout);
|
||||
/**
|
||||
@@ -1216,64 +975,41 @@ 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 all routes created with {@link BrowserContext#route BrowserContext.route()} and {@link
|
||||
* BrowserContext#routeFromHAR BrowserContext.routeFromHAR()}.
|
||||
*
|
||||
* @since v1.41
|
||||
*/
|
||||
void unrouteAll();
|
||||
/**
|
||||
* Removes a route created with {@link BrowserContext#route BrowserContext.route()}. When {@code handler} is not specified,
|
||||
* removes all routes for the {@code url}.
|
||||
*
|
||||
* @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);
|
||||
@@ -1285,7 +1021,6 @@ 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);
|
||||
/**
|
||||
@@ -1294,7 +1029,6 @@ 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);
|
||||
@@ -1306,7 +1040,6 @@ 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);
|
||||
/**
|
||||
@@ -1315,7 +1048,6 @@ 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);
|
||||
@@ -1327,97 +1059,24 @@ 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);
|
||||
/**
|
||||
* The method will block until the condition returns true. All Playwright events will be dispatched while the method is
|
||||
* waiting for the condition.
|
||||
*
|
||||
* <p> **Usage**
|
||||
*
|
||||
* <p> Use the method to wait for a condition that depends on page events:
|
||||
* <pre>{@code
|
||||
* List<String> failedUrls = new ArrayList<>();
|
||||
* context.onResponse(response -> {
|
||||
* if (!response.ok()) {
|
||||
* failedUrls.add(response.url());
|
||||
* }
|
||||
* });
|
||||
* page1.getByText("Create user").click();
|
||||
* page2.getByText("Submit button").click();
|
||||
* context.waitForCondition(() -> failedUrls.size() > 3);
|
||||
* }</pre>
|
||||
*
|
||||
* @param condition Condition to wait for.
|
||||
* @since v1.32
|
||||
*/
|
||||
default void waitForCondition(BooleanSupplier condition) {
|
||||
waitForCondition(condition, null);
|
||||
}
|
||||
/**
|
||||
* The method will block until the condition returns true. All Playwright events will be dispatched while the method is
|
||||
* waiting for the condition.
|
||||
*
|
||||
* <p> **Usage**
|
||||
*
|
||||
* <p> Use the method to wait for a condition that depends on page events:
|
||||
* <pre>{@code
|
||||
* List<String> failedUrls = new ArrayList<>();
|
||||
* context.onResponse(response -> {
|
||||
* if (!response.ok()) {
|
||||
* failedUrls.add(response.url());
|
||||
* }
|
||||
* });
|
||||
* page1.getByText("Create user").click();
|
||||
* page2.getByText("Submit button").click();
|
||||
* context.waitForCondition(() -> failedUrls.size() > 3);
|
||||
* }</pre>
|
||||
*
|
||||
* @param condition Condition to wait for.
|
||||
* @since v1.32
|
||||
*/
|
||||
void waitForCondition(BooleanSupplier condition, WaitForConditionOptions options);
|
||||
/**
|
||||
* Performs action and waits for a {@code ConsoleMessage} to be logged by in the pages in the context. If predicate is
|
||||
* provided, it passes {@code ConsoleMessage} value into the {@code predicate} function and waits for {@code
|
||||
* predicate(message)} to return a truthy value. Will throw an error if the page is closed before the {@link
|
||||
* BrowserContext#onConsoleMessage BrowserContext.onConsoleMessage()} event is fired.
|
||||
* 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.34
|
||||
*/
|
||||
default ConsoleMessage waitForConsoleMessage(Runnable callback) {
|
||||
return waitForConsoleMessage(null, callback);
|
||||
}
|
||||
/**
|
||||
* Performs action and waits for a {@code ConsoleMessage} to be logged by in the pages in the context. If predicate is
|
||||
* provided, it passes {@code ConsoleMessage} value into the {@code predicate} function and waits for {@code
|
||||
* predicate(message)} to return a truthy value. Will throw an error if the page is closed before the {@link
|
||||
* BrowserContext#onConsoleMessage BrowserContext.onConsoleMessage()} event is fired.
|
||||
*
|
||||
* @param callback Callback that performs the action triggering the event.
|
||||
* @since v1.34
|
||||
*/
|
||||
ConsoleMessage waitForConsoleMessage(WaitForConsoleMessageOptions options, Runnable 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.
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
||||
@@ -43,26 +43,6 @@ import java.util.regex.Pattern;
|
||||
*/
|
||||
public interface BrowserType {
|
||||
class ConnectOptions {
|
||||
/**
|
||||
* This option exposes network available on the connecting client to the browser being connected to. Consists of a list of
|
||||
* rules separated by comma.
|
||||
*
|
||||
* <p> Available rules:
|
||||
* <ol>
|
||||
* <li> Hostname pattern, for example: {@code example.com}, {@code *.org:99}, {@code x.*.y.com}, {@code *foo.org}.</li>
|
||||
* <li> IP literal, for example: {@code 127.0.0.1}, {@code 0.0.0.0:99}, {@code [::1]}, {@code [0:0::1]:99}.</li>
|
||||
* <li> {@code <loopback>} that matches local loopback interfaces: {@code localhost}, {@code *.localhost}, {@code 127.0.0.1},
|
||||
* {@code [::1]}.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> Some common examples:
|
||||
* <ol>
|
||||
* <li> {@code "*"} to expose all network.</li>
|
||||
* <li> {@code "<loopback>"} to expose localhost network.</li>
|
||||
* <li> {@code "*.test.internal-domain,*.staging.internal-domain,<loopback>"} to expose test/staging deployments and localhost.</li>
|
||||
* </ol>
|
||||
*/
|
||||
public String exposeNetwork;
|
||||
/**
|
||||
* Additional HTTP headers to be sent with web socket connect request. Optional.
|
||||
*/
|
||||
@@ -77,29 +57,6 @@ public interface BrowserType {
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* This option exposes network available on the connecting client to the browser being connected to. Consists of a list of
|
||||
* rules separated by comma.
|
||||
*
|
||||
* <p> Available rules:
|
||||
* <ol>
|
||||
* <li> Hostname pattern, for example: {@code example.com}, {@code *.org:99}, {@code x.*.y.com}, {@code *foo.org}.</li>
|
||||
* <li> IP literal, for example: {@code 127.0.0.1}, {@code 0.0.0.0:99}, {@code [::1]}, {@code [0:0::1]:99}.</li>
|
||||
* <li> {@code <loopback>} that matches local loopback interfaces: {@code localhost}, {@code *.localhost}, {@code 127.0.0.1},
|
||||
* {@code [::1]}.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> Some common examples:
|
||||
* <ol>
|
||||
* <li> {@code "*"} to expose all network.</li>
|
||||
* <li> {@code "<loopback>"} to expose localhost network.</li>
|
||||
* <li> {@code "*.test.internal-domain,*.staging.internal-domain,<loopback>"} to expose test/staging deployments and localhost.</li>
|
||||
* </ol>
|
||||
*/
|
||||
public ConnectOptions setExposeNetwork(String exposeNetwork) {
|
||||
this.exposeNetwork = exposeNetwork;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Additional HTTP headers to be sent with web socket connect request. Optional.
|
||||
*/
|
||||
@@ -134,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;
|
||||
|
||||
@@ -155,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;
|
||||
@@ -165,10 +122,8 @@ public interface BrowserType {
|
||||
}
|
||||
class LaunchOptions {
|
||||
/**
|
||||
* <strong>NOTE:</strong> Use custom browser args at your own risk, as some of them may break Playwright functionality.
|
||||
*
|
||||
* <p> Additional arguments to pass to the browser instance. The list of Chromium flags can be found <a
|
||||
* href="https://peter.sh/experiments/chromium-command-line-switches/">here</a>.
|
||||
* Additional arguments to pass to the browser instance. The list of Chromium flags can be found <a
|
||||
* href="http://peter.sh/experiments/chromium-command-line-switches/">here</a>.
|
||||
*/
|
||||
public List<String> args;
|
||||
/**
|
||||
@@ -182,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;
|
||||
/**
|
||||
@@ -222,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;
|
||||
/**
|
||||
@@ -245,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;
|
||||
/**
|
||||
@@ -255,10 +210,8 @@ public interface BrowserType {
|
||||
public Path tracesDir;
|
||||
|
||||
/**
|
||||
* <strong>NOTE:</strong> Use custom browser args at your own risk, as some of them may break Playwright functionality.
|
||||
*
|
||||
* <p> Additional arguments to pass to the browser instance. The list of Chromium flags can be found <a
|
||||
* href="https://peter.sh/experiments/chromium-command-line-switches/">here</a>.
|
||||
* Additional arguments to pass to the browser instance. The list of Chromium flags can be found <a
|
||||
* href="http://peter.sh/experiments/chromium-command-line-switches/">here</a>.
|
||||
*/
|
||||
public LaunchOptions setArgs(List<String> args) {
|
||||
this.args = args;
|
||||
@@ -291,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;
|
||||
@@ -355,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;
|
||||
@@ -399,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;
|
||||
@@ -420,30 +373,26 @@ public interface BrowserType {
|
||||
*/
|
||||
public Boolean acceptDownloads;
|
||||
/**
|
||||
* <strong>NOTE:</strong> Use custom browser args at your own risk, as some of them may break Playwright functionality.
|
||||
*
|
||||
* <p> Additional arguments to pass to the browser instance. The list of Chromium flags can be found <a
|
||||
* href="https://peter.sh/experiments/chromium-command-line-switches/">here</a>.
|
||||
* Additional arguments to pass to the browser instance. The list of Chromium flags can be found <a
|
||||
* href="http://peter.sh/experiments/chromium-command-line-switches/">here</a>.
|
||||
*/
|
||||
public List<String> args;
|
||||
/**
|
||||
* 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. Unset by default. 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>
|
||||
*/
|
||||
public String baseURL;
|
||||
/**
|
||||
* Toggles bypassing page's Content-Security-Policy. Defaults to {@code false}.
|
||||
* Toggles bypassing page's Content-Security-Policy.
|
||||
*/
|
||||
public Boolean bypassCSP;
|
||||
/**
|
||||
@@ -457,19 +406,17 @@ public interface BrowserType {
|
||||
*/
|
||||
public Boolean chromiumSandbox;
|
||||
/**
|
||||
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code
|
||||
* "no-preference"}. See {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets
|
||||
* emulation to system defaults. Defaults to {@code "light"}.
|
||||
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code "no-preference"}. See
|
||||
* {@link Page#emulateMedia Page.emulateMedia()} for more details. Defaults to {@code "light"}.
|
||||
*/
|
||||
public Optional<ColorScheme> colorScheme;
|
||||
public ColorScheme colorScheme;
|
||||
/**
|
||||
* Specify device scale factor (can be thought of as dpr). Defaults to {@code 1}. Learn more about <a
|
||||
* href="https://playwright.dev/java/docs/emulation#devices">emulating devices with device scale factor</a>.
|
||||
* 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;
|
||||
/**
|
||||
@@ -489,20 +436,14 @@ public interface BrowserType {
|
||||
*/
|
||||
public Path executablePath;
|
||||
/**
|
||||
* An object containing additional HTTP headers to be sent with every request. Defaults to none.
|
||||
* An object containing additional HTTP headers to be sent with every request.
|
||||
*/
|
||||
public Map<String, String> extraHTTPHeaders;
|
||||
/**
|
||||
* Firefox user preferences. Learn more about the Firefox user preferences at <a
|
||||
* href="https://support.mozilla.org/en-US/kb/about-config-editor-firefox">{@code about:config}</a>.
|
||||
* 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"}.
|
||||
*/
|
||||
public Map<String, Object> firefoxUserPrefs;
|
||||
/**
|
||||
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"}, {@code "none"}. See {@link
|
||||
* Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults.
|
||||
* Defaults to {@code "none"}.
|
||||
*/
|
||||
public Optional<ForcedColors> forcedColors;
|
||||
public ForcedColors forcedColors;
|
||||
public Geolocation geolocation;
|
||||
/**
|
||||
* Close the browser process on SIGHUP. Defaults to {@code true}.
|
||||
@@ -517,30 +458,28 @@ public interface BrowserType {
|
||||
*/
|
||||
public Boolean handleSIGTERM;
|
||||
/**
|
||||
* Specifies if viewport supports touch events. Defaults to false. Learn more about <a
|
||||
* href="https://playwright.dev/java/docs/emulation#devices">mobile emulation</a>.
|
||||
* Specifies if viewport supports touch events. Defaults to false.
|
||||
*/
|
||||
public Boolean hasTouch;
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* Credentials for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication">HTTP authentication</a>. If
|
||||
* no origin is specified, the username and password are sent to any servers upon unauthorized responses.
|
||||
* Credentials for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication">HTTP authentication</a>.
|
||||
*/
|
||||
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;
|
||||
/**
|
||||
@@ -548,31 +487,26 @@ public interface BrowserType {
|
||||
*/
|
||||
public Boolean ignoreHTTPSErrors;
|
||||
/**
|
||||
* Whether the {@code meta viewport} tag is taken into account and touch events are enabled. isMobile is a part of device,
|
||||
* so you don't actually need to set it manually. Defaults to {@code false} and is not supported in Firefox. Learn more
|
||||
* about <a href="https://playwright.dev/java/docs/emulation#ismobile">mobile emulation</a>.
|
||||
* 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;
|
||||
/**
|
||||
* Whether or not to enable JavaScript in the context. Defaults to {@code true}. Learn more about <a
|
||||
* href="https://playwright.dev/java/docs/emulation#javascript-enabled">disabling JavaScript</a>.
|
||||
* Whether or not to enable JavaScript in the context. Defaults to {@code true}.
|
||||
*/
|
||||
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. Defaults to the system default
|
||||
* locale. Learn more about emulation in our <a
|
||||
* href="https://playwright.dev/java/docs/emulation#locale--timezone">emulation guide</a>.
|
||||
* 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;
|
||||
/**
|
||||
* Whether to emulate network being offline. Defaults to {@code false}. Learn more about <a
|
||||
* href="https://playwright.dev/java/docs/emulation#offline">network emulation</a>.
|
||||
* Whether to emulate network being offline. Defaults to {@code false}.
|
||||
*/
|
||||
public Boolean offline;
|
||||
/**
|
||||
* A list of permissions to grant to all pages in this context. See {@link BrowserContext#grantPermissions
|
||||
* BrowserContext.grantPermissions()} for more details. Defaults to none.
|
||||
* BrowserContext.grantPermissions()} for more details.
|
||||
*/
|
||||
public List<String> permissions;
|
||||
/**
|
||||
@@ -580,15 +514,14 @@ public interface BrowserType {
|
||||
*/
|
||||
public Proxy proxy;
|
||||
/**
|
||||
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If
|
||||
* {@code attach} is specified, resources are persisted as separate files and all of these files are archived along with
|
||||
* the HAR file. Defaults to {@code embed}, which stores content inline the HAR file as per HAR specification.
|
||||
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If {@code attach}
|
||||
* is specified, resources are 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.
|
||||
*/
|
||||
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;
|
||||
/**
|
||||
@@ -609,26 +542,25 @@ public interface BrowserType {
|
||||
public Path recordVideoDir;
|
||||
/**
|
||||
* Dimensions of the recorded videos. If not specified the size will be equal to {@code viewport} scaled down to fit into
|
||||
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each
|
||||
* page will be scaled down if necessary to fit the specified size.
|
||||
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each page will
|
||||
* be scaled down if necessary to fit the specified size.
|
||||
*/
|
||||
public RecordVideoSize recordVideoSize;
|
||||
/**
|
||||
* Emulates {@code "prefers-reduced-motion"} media feature, supported values are {@code "reduce"}, {@code "no-preference"}.
|
||||
* See {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system
|
||||
* defaults. Defaults to {@code "no-preference"}.
|
||||
* Emulates {@code "prefers-reduced-motion"} media feature, supported values are {@code "reduce"}, {@code "no-preference"}. See {@link
|
||||
* Page#emulateMedia Page.emulateMedia()} for more details. Defaults to {@code "no-preference"}.
|
||||
*/
|
||||
public Optional<ReducedMotion> reducedMotion;
|
||||
public 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>
|
||||
*/
|
||||
@@ -638,21 +570,20 @@ public interface BrowserType {
|
||||
*/
|
||||
public Double slowMo;
|
||||
/**
|
||||
* 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). Defaults to {@code false}. See {@code Locator} to learn more about
|
||||
* the strict mode.
|
||||
* 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.
|
||||
*/
|
||||
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;
|
||||
/**
|
||||
* Changes the timezone of the context. See <a
|
||||
* href="https://cs.chromium.org/chromium/src/third_party/icu/source/data/misc/metaZones.txt?rcl=faee8bc70570192d82d2978a71e2a615788597d1">ICU's
|
||||
* metaZones.txt</a> for a list of supported timezone IDs. Defaults to the system timezone.
|
||||
* metaZones.txt</a> for a list of supported timezone IDs.
|
||||
*/
|
||||
public String timezoneId;
|
||||
/**
|
||||
@@ -664,12 +595,7 @@ public interface BrowserType {
|
||||
*/
|
||||
public String userAgent;
|
||||
/**
|
||||
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. Use {@code null} to disable the consistent
|
||||
* viewport emulation. Learn more about <a href="https://playwright.dev/java/docs/emulation#viewport">viewport
|
||||
* emulation</a>.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> The {@code null} value opts out from the default presets, makes viewport depend on the host window size defined by the
|
||||
* operating system. It makes the execution of the tests non-deterministic.
|
||||
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default viewport.
|
||||
*/
|
||||
public Optional<ViewportSize> viewportSize;
|
||||
|
||||
@@ -681,10 +607,8 @@ public interface BrowserType {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* <strong>NOTE:</strong> Use custom browser args at your own risk, as some of them may break Playwright functionality.
|
||||
*
|
||||
* <p> Additional arguments to pass to the browser instance. The list of Chromium flags can be found <a
|
||||
* href="https://peter.sh/experiments/chromium-command-line-switches/">here</a>.
|
||||
* Additional arguments to pass to the browser instance. The list of Chromium flags can be found <a
|
||||
* href="http://peter.sh/experiments/chromium-command-line-switches/">here</a>.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setArgs(List<String> args) {
|
||||
this.args = args;
|
||||
@@ -694,13 +618,11 @@ 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. Unset by default. 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>
|
||||
@@ -710,7 +632,7 @@ public interface BrowserType {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Toggles bypassing page's Content-Security-Policy. Defaults to {@code false}.
|
||||
* Toggles bypassing page's Content-Security-Policy.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setBypassCSP(boolean bypassCSP) {
|
||||
this.bypassCSP = bypassCSP;
|
||||
@@ -743,25 +665,23 @@ public interface BrowserType {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code
|
||||
* "no-preference"}. See {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets
|
||||
* emulation to system defaults. Defaults to {@code "light"}.
|
||||
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code "no-preference"}. See
|
||||
* {@link Page#emulateMedia Page.emulateMedia()} for more details. Defaults to {@code "light"}.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setColorScheme(ColorScheme colorScheme) {
|
||||
this.colorScheme = Optional.ofNullable(colorScheme);
|
||||
this.colorScheme = colorScheme;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Specify device scale factor (can be thought of as dpr). Defaults to {@code 1}. Learn more about <a
|
||||
* href="https://playwright.dev/java/docs/emulation#devices">emulating devices with device scale factor</a>.
|
||||
* Specify device scale factor (can be thought of as dpr). Defaults to {@code 1}.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setDeviceScaleFactor(double deviceScaleFactor) {
|
||||
this.deviceScaleFactor = deviceScaleFactor;
|
||||
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;
|
||||
@@ -793,27 +713,18 @@ public interface BrowserType {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* An object containing additional HTTP headers to be sent with every request. Defaults to none.
|
||||
* An object containing additional HTTP headers to be sent with every request.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setExtraHTTPHeaders(Map<String, String> extraHTTPHeaders) {
|
||||
this.extraHTTPHeaders = extraHTTPHeaders;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Firefox user preferences. Learn more about the Firefox user preferences at <a
|
||||
* href="https://support.mozilla.org/en-US/kb/about-config-editor-firefox">{@code about:config}</a>.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setFirefoxUserPrefs(Map<String, Object> firefoxUserPrefs) {
|
||||
this.firefoxUserPrefs = firefoxUserPrefs;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"}, {@code "none"}. See {@link
|
||||
* Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system defaults.
|
||||
* Defaults to {@code "none"}.
|
||||
* Emulates {@code "forced-colors"} media feature, supported values are {@code "active"}, {@code "none"}. See {@link Page#emulateMedia
|
||||
* Page.emulateMedia()} for more details. Defaults to {@code "none"}.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setForcedColors(ForcedColors forcedColors) {
|
||||
this.forcedColors = Optional.ofNullable(forcedColors);
|
||||
this.forcedColors = forcedColors;
|
||||
return this;
|
||||
}
|
||||
public LaunchPersistentContextOptions setGeolocation(double latitude, double longitude) {
|
||||
@@ -845,8 +756,7 @@ public interface BrowserType {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Specifies if viewport supports touch events. Defaults to false. Learn more about <a
|
||||
* href="https://playwright.dev/java/docs/emulation#devices">mobile emulation</a>.
|
||||
* Specifies if viewport supports touch events. Defaults to false.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setHasTouch(boolean hasTouch) {
|
||||
this.hasTouch = hasTouch;
|
||||
@@ -855,39 +765,37 @@ 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;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Credentials for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication">HTTP authentication</a>. If
|
||||
* no origin is specified, the username and password are sent to any servers upon unauthorized responses.
|
||||
* Credentials for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication">HTTP authentication</a>.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setHttpCredentials(String username, String password) {
|
||||
return setHttpCredentials(new HttpCredentials(username, password));
|
||||
}
|
||||
/**
|
||||
* Credentials for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication">HTTP authentication</a>. If
|
||||
* no origin is specified, the username and password are sent to any servers upon unauthorized responses.
|
||||
* Credentials for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication">HTTP authentication</a>.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setHttpCredentials(HttpCredentials httpCredentials) {
|
||||
this.httpCredentials = httpCredentials;
|
||||
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;
|
||||
@@ -901,35 +809,30 @@ public interface BrowserType {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Whether the {@code meta viewport} tag is taken into account and touch events are enabled. isMobile is a part of device,
|
||||
* so you don't actually need to set it manually. Defaults to {@code false} and is not supported in Firefox. Learn more
|
||||
* about <a href="https://playwright.dev/java/docs/emulation#ismobile">mobile emulation</a>.
|
||||
* 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;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Whether or not to enable JavaScript in the context. Defaults to {@code true}. Learn more about <a
|
||||
* href="https://playwright.dev/java/docs/emulation#javascript-enabled">disabling JavaScript</a>.
|
||||
* Whether or not to enable JavaScript in the context. Defaults to {@code true}.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setJavaScriptEnabled(boolean javaScriptEnabled) {
|
||||
this.javaScriptEnabled = javaScriptEnabled;
|
||||
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. Defaults to the system default
|
||||
* locale. Learn more about emulation in our <a
|
||||
* href="https://playwright.dev/java/docs/emulation#locale--timezone">emulation guide</a>.
|
||||
* 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;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Whether to emulate network being offline. Defaults to {@code false}. Learn more about <a
|
||||
* href="https://playwright.dev/java/docs/emulation#offline">network emulation</a>.
|
||||
* Whether to emulate network being offline. Defaults to {@code false}.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setOffline(boolean offline) {
|
||||
this.offline = offline;
|
||||
@@ -937,7 +840,7 @@ public interface BrowserType {
|
||||
}
|
||||
/**
|
||||
* A list of permissions to grant to all pages in this context. See {@link BrowserContext#grantPermissions
|
||||
* BrowserContext.grantPermissions()} for more details. Defaults to none.
|
||||
* BrowserContext.grantPermissions()} for more details.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setPermissions(List<String> permissions) {
|
||||
this.permissions = permissions;
|
||||
@@ -957,18 +860,17 @@ public interface BrowserType {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If
|
||||
* {@code attach} is specified, resources are persisted as separate files and all of these files are archived along with
|
||||
* the HAR file. Defaults to {@code embed}, which stores content inline the HAR file as per HAR specification.
|
||||
* Optional setting to control resource content management. If {@code omit} is specified, content is not persisted. If {@code attach}
|
||||
* is specified, resources are 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.
|
||||
*/
|
||||
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;
|
||||
@@ -1008,40 +910,39 @@ public interface BrowserType {
|
||||
}
|
||||
/**
|
||||
* Dimensions of the recorded videos. If not specified the size will be equal to {@code viewport} scaled down to fit into
|
||||
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each
|
||||
* page will be scaled down if necessary to fit the specified size.
|
||||
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each page will
|
||||
* be scaled down if necessary to fit the specified size.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setRecordVideoSize(int width, int height) {
|
||||
return setRecordVideoSize(new RecordVideoSize(width, height));
|
||||
}
|
||||
/**
|
||||
* Dimensions of the recorded videos. If not specified the size will be equal to {@code viewport} scaled down to fit into
|
||||
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each
|
||||
* page will be scaled down if necessary to fit the specified size.
|
||||
* 800x800. If {@code viewport} is not configured explicitly the video size defaults to 800x450. Actual picture of each page will
|
||||
* be scaled down if necessary to fit the specified size.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setRecordVideoSize(RecordVideoSize recordVideoSize) {
|
||||
this.recordVideoSize = recordVideoSize;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Emulates {@code "prefers-reduced-motion"} media feature, supported values are {@code "reduce"}, {@code "no-preference"}.
|
||||
* See {@link Page#emulateMedia Page.emulateMedia()} for more details. Passing {@code null} resets emulation to system
|
||||
* defaults. Defaults to {@code "no-preference"}.
|
||||
* Emulates {@code "prefers-reduced-motion"} media feature, supported values are {@code "reduce"}, {@code "no-preference"}. See {@link
|
||||
* Page#emulateMedia Page.emulateMedia()} for more details. Defaults to {@code "no-preference"}.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setReducedMotion(ReducedMotion reducedMotion) {
|
||||
this.reducedMotion = Optional.ofNullable(reducedMotion);
|
||||
this.reducedMotion = 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;
|
||||
@@ -1050,8 +951,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>
|
||||
*/
|
||||
@@ -1067,18 +968,17 @@ public interface BrowserType {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 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). Defaults to {@code false}. See {@code Locator} to learn more about
|
||||
* the strict mode.
|
||||
* 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.
|
||||
*/
|
||||
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;
|
||||
@@ -1087,7 +987,7 @@ public interface BrowserType {
|
||||
/**
|
||||
* Changes the timezone of the context. See <a
|
||||
* href="https://cs.chromium.org/chromium/src/third_party/icu/source/data/misc/metaZones.txt?rcl=faee8bc70570192d82d2978a71e2a615788597d1">ICU's
|
||||
* metaZones.txt</a> for a list of supported timezone IDs. Defaults to the system timezone.
|
||||
* metaZones.txt</a> for a list of supported timezone IDs.
|
||||
*/
|
||||
public LaunchPersistentContextOptions setTimezoneId(String timezoneId) {
|
||||
this.timezoneId = timezoneId;
|
||||
@@ -1108,23 +1008,13 @@ public interface BrowserType {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. Use {@code null} to disable the consistent
|
||||
* viewport emulation. Learn more about <a href="https://playwright.dev/java/docs/emulation#viewport">viewport
|
||||
* emulation</a>.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> The {@code null} value opts out from the default presets, makes viewport depend on the host window size defined by the
|
||||
* operating system. It makes the execution of the tests non-deterministic.
|
||||
* 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. Use {@code null} to disable the consistent
|
||||
* viewport emulation. Learn more about <a href="https://playwright.dev/java/docs/emulation#viewport">viewport
|
||||
* emulation</a>.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> The {@code null} value opts out from the default presets, makes viewport depend on the host window size defined by the
|
||||
* operating system. It makes the execution of the tests non-deterministic.
|
||||
* 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);
|
||||
@@ -1132,23 +1022,21 @@ 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);
|
||||
/**
|
||||
@@ -1157,17 +1045,14 @@ 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}.
|
||||
* @since v1.9
|
||||
* @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}.
|
||||
*/
|
||||
default Browser connectOverCDP(String endpointURL) {
|
||||
return connectOverCDP(endpointURL, null);
|
||||
@@ -1178,30 +1063,23 @@ 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}.
|
||||
* @since v1.9
|
||||
* @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}.
|
||||
*/
|
||||
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".
|
||||
@@ -1227,8 +1105,6 @@ 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);
|
||||
@@ -1236,8 +1112,6 @@ 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".
|
||||
@@ -1263,8 +1137,6 @@ 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);
|
||||
/**
|
||||
@@ -1276,9 +1148,8 @@ 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.
|
||||
* @since v1.8
|
||||
* 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.
|
||||
*/
|
||||
default BrowserContext launchPersistentContext(Path userDataDir) {
|
||||
return launchPersistentContext(userDataDir, null);
|
||||
@@ -1292,15 +1163,12 @@ 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.
|
||||
* @since v1.8
|
||||
* 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.
|
||||
*/
|
||||
BrowserContext launchPersistentContext(Path userDataDir, LaunchPersistentContextOptions options);
|
||||
/**
|
||||
* Returns browser name. For example: {@code "chromium"}, {@code "webkit"} or {@code "firefox"}.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
String name();
|
||||
}
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* The {@code CDPSession} instances are used to talk raw Chrome Devtools Protocol:
|
||||
* <ul>
|
||||
* <li> protocol methods can be called with {@code session.send} method.</li>
|
||||
* <li> protocol events can be subscribed to with {@code session.on} method.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p> Useful links:
|
||||
* <ul>
|
||||
* <li> Documentation on DevTools Protocol can be found here: <a
|
||||
* href="https://chromedevtools.github.io/devtools-protocol/">DevTools Protocol Viewer</a>.</li>
|
||||
* <li> Getting Started with DevTools Protocol: https://github.com/aslushnikov/getting-started-with-cdp/blob/master/README.md</li>
|
||||
* <pre>{@code
|
||||
* CDPSession client = page.context().newCDPSession(page);
|
||||
* client.send("Runtime.enable");
|
||||
*
|
||||
* client.on("Animation.animationCreated", (event) -> System.out.println("Animation created!"));
|
||||
*
|
||||
* JsonObject response = client.send("Animation.getPlaybackRate");
|
||||
* double playbackRate = response.get("playbackRate").getAsDouble();
|
||||
* System.out.println("playback rate is " + playbackRate);
|
||||
*
|
||||
* JsonObject params = new JsonObject();
|
||||
* params.addProperty("playbackRate", playbackRate / 2);
|
||||
* client.send("Animation.setPlaybackRate", params);
|
||||
* }</pre>
|
||||
* </ul>
|
||||
*/
|
||||
public interface CDPSession {
|
||||
/**
|
||||
* Detaches the CDPSession from the target. Once detached, the CDPSession object won't emit any events and can't be used to
|
||||
* send messages.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
void detach();
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param method Protocol method name.
|
||||
* @since v1.8
|
||||
*/
|
||||
default JsonObject send(String method) {
|
||||
return send(method, null);
|
||||
}
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param method Protocol method name.
|
||||
* @param args Optional method parameters.
|
||||
* @since v1.8
|
||||
*/
|
||||
JsonObject send(String method, JsonObject args);
|
||||
/**
|
||||
* Register an event handler for events with the specified event name. The given handler will be called for every event
|
||||
* with the given name.
|
||||
*
|
||||
* @param eventName CDP event name.
|
||||
* @param handler Event handler.
|
||||
* @since v1.37
|
||||
*/
|
||||
void on(String eventName, Consumer<JsonObject> handler);
|
||||
/**
|
||||
* Unregister an event handler for events with the specified event name. The given handler will not be called anymore for
|
||||
* events with the given name.
|
||||
*
|
||||
* @param eventName CDP event name.
|
||||
* @param handler Event handler.
|
||||
* @since v1.37
|
||||
*/
|
||||
void off(String eventName, Consumer<JsonObject> handler);
|
||||
}
|
||||
|
||||
@@ -19,19 +19,19 @@ package com.microsoft.playwright;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* {@code ConsoleMessage} objects are dispatched by page via the {@link Page#onConsoleMessage Page.onConsoleMessage()}
|
||||
* event. For each console messages logged in the page there will be corresponding event in the Playwright context.
|
||||
* {@code ConsoleMessage} objects are dispatched by page via the {@link Page#onConsoleMessage Page.onConsoleMessage()} event. For
|
||||
* each console messages logged in the page there will be corresponding event in the Playwright context.
|
||||
* <pre>{@code
|
||||
* // Listen for all console messages and print them to the standard output.
|
||||
* // Listen for all System.out.printlns
|
||||
* page.onConsoleMessage(msg -> System.out.println(msg.text()));
|
||||
*
|
||||
* // Listen for all console messages and print errors to the standard output.
|
||||
* // Listen for all console events and handle errors
|
||||
* page.onConsoleMessage(msg -> {
|
||||
* if ("error".equals(msg.type()))
|
||||
* System.out.println("Error text: " + msg.text());
|
||||
* });
|
||||
*
|
||||
* // Get the next console message
|
||||
* // Get the next System.out.println
|
||||
* ConsoleMessage msg = page.waitForConsoleMessage(() -> {
|
||||
* // Issue console.log inside the page
|
||||
* page.evaluate("console.log('hello', 42, { foo: 'bar' });");
|
||||
@@ -44,37 +44,21 @@ import java.util.*;
|
||||
*/
|
||||
public interface ConsoleMessage {
|
||||
/**
|
||||
* List of arguments passed to a {@code console} function call. See also {@link Page#onConsoleMessage
|
||||
* Page.onConsoleMessage()}.
|
||||
*
|
||||
* @since v1.8
|
||||
* List of arguments passed to a {@code console} function call. See also {@link Page#onConsoleMessage Page.onConsoleMessage()}.
|
||||
*/
|
||||
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 page that produced this console message, if any.
|
||||
*
|
||||
* @since v1.34
|
||||
*/
|
||||
Page page();
|
||||
/**
|
||||
* 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"}.
|
||||
*
|
||||
* @since v1.8
|
||||
* 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"}.
|
||||
*/
|
||||
String type();
|
||||
}
|
||||
|
||||
@@ -50,8 +50,6 @@ package com.microsoft.playwright;
|
||||
public interface Dialog {
|
||||
/**
|
||||
* Returns when the dialog has been accepted.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
default void accept() {
|
||||
accept(null);
|
||||
@@ -60,37 +58,22 @@ 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();
|
||||
/**
|
||||
* The page that initiated this dialog, if available.
|
||||
*
|
||||
* @since v1.34
|
||||
*/
|
||||
Page page();
|
||||
/**
|
||||
* Returns dialog's type, can be one of {@code alert}, {@code beforeunload}, {@code confirm} or {@code prompt}.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
String type();
|
||||
}
|
||||
|
||||
@@ -24,87 +24,69 @@ import java.nio.file.Path;
|
||||
*
|
||||
* <p> All the downloaded files belonging to the browser context are deleted when the browser context is closed.
|
||||
*
|
||||
* <p> Download event is emitted once the download starts. Download path becomes available once download completes.
|
||||
* <p> Download event is emitted once the download starts. Download path becomes available once download completes:
|
||||
* <pre>{@code
|
||||
* // Wait for the download to start
|
||||
* // 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(() -> {
|
||||
* // Perform the action that initiates download
|
||||
* page.getByText("Download file").click();
|
||||
* page.locator("a").click();
|
||||
* });
|
||||
*
|
||||
* // Wait for the download process to complete and save the downloaded file somewhere
|
||||
* download.saveAs(Paths.get("/path/to/save/at/", download.suggestedFilename()));
|
||||
* // wait for download to complete
|
||||
* Path path = download.path();
|
||||
* }</pre>
|
||||
*/
|
||||
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"}.
|
||||
*
|
||||
* @since v1.13
|
||||
* 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"}.
|
||||
*/
|
||||
void cancel();
|
||||
/**
|
||||
* Returns a readable stream for a successful download, or throws for a failed/canceled download.
|
||||
*
|
||||
* @since v1.8
|
||||
* Returns readable stream for current download or {@code null} if download failed.
|
||||
*/
|
||||
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();
|
||||
/**
|
||||
* Returns path to the downloaded file for a successful download, or throws for a failed/canceled download. The method will
|
||||
* wait for the download to finish if necessary. The method throws when connected remotely.
|
||||
* Returns path to the downloaded file in case of successful download. The method will wait for the download to finish if
|
||||
* necessary. The method throws when connected remotely.
|
||||
*
|
||||
* <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();
|
||||
/**
|
||||
* Copy the download to a user-specified path. It is safe to call this method while the download is still in progress. Will
|
||||
* wait for the download to finish if necessary.
|
||||
*
|
||||
* <p> **Usage**
|
||||
* <pre>{@code
|
||||
* download.saveAs(Paths.get("/path/to/save/at/", download.suggestedFilename()));
|
||||
* }</pre>
|
||||
*
|
||||
* @param path Path where the download should be copied.
|
||||
* @since v1.8
|
||||
*/
|
||||
void saveAs(Path path);
|
||||
/**
|
||||
* Returns suggested filename for this download. It is typically computed by the browser from the <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition">{@code Content-Disposition}</a>
|
||||
* response header or the {@code download} attribute. See the spec on <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition">{@code Content-Disposition}</a> response
|
||||
* header or the {@code download} attribute. See the spec on <a
|
||||
* href="https://html.spec.whatwg.org/#downloading-resources">whatwg</a>. Different browsers can use different logic for
|
||||
* computing it.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
String suggestedFilename();
|
||||
/**
|
||||
* Returns downloaded url.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
String url();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,7 +22,7 @@ import java.nio.file.Path;
|
||||
/**
|
||||
* {@code FileChooser} objects are dispatched by the page in the {@link Page#onFileChooser Page.onFileChooser()} event.
|
||||
* <pre>{@code
|
||||
* FileChooser fileChooser = page.waitForFileChooser(() -> page.getByText("Upload file").click());
|
||||
* FileChooser fileChooser = page.waitForFileChooser(() -> page.locator("upload").click());
|
||||
* fileChooser.setFiles(Paths.get("myfile.pdf"));
|
||||
* }</pre>
|
||||
*/
|
||||
@@ -35,9 +35,9 @@ public interface FileChooser {
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
* Maximum time in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout. The default
|
||||
* value can be changed by using the {@link 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 {@code 30000} (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,84 +62,62 @@ 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.
|
||||
*
|
||||
* @since v1.8
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @since v1.8
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @since v1.8
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @since v1.8
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @since v1.8
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @since v1.8
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @since v1.8
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @since v1.8
|
||||
* 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.
|
||||
*/
|
||||
void setFiles(FilePayload[] files, SetFilesOptions options);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -36,14 +36,10 @@ 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();
|
||||
/**
|
||||
@@ -52,18 +48,17 @@ 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> **Usage**
|
||||
* <p> Examples:
|
||||
* <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 the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
* @since v1.8
|
||||
* @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.
|
||||
*/
|
||||
default Object evaluate(String expression) {
|
||||
return evaluate(expression, null);
|
||||
@@ -74,19 +69,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> **Usage**
|
||||
* <p> Examples:
|
||||
* <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 the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
* @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 arg Optional argument to pass to {@code expression}.
|
||||
* @since v1.8
|
||||
*/
|
||||
Object evaluate(String expression, Object arg);
|
||||
/**
|
||||
@@ -94,18 +88,17 @@ public interface JSHandle {
|
||||
*
|
||||
* <p> This method passes this handle as the first argument to {@code expression}.
|
||||
*
|
||||
* <p> The only difference between {@code jsHandle.evaluate} and {@code jsHandle.evaluateHandle} is that {@code
|
||||
* jsHandle.evaluateHandle} returns {@code JSHandle}.
|
||||
* <p> The only difference between {@code jsHandle.evaluate} and {@code jsHandle.evaluateHandle} is that {@code jsHandle.evaluateHandle} returns
|
||||
* {@code JSHandle}.
|
||||
*
|
||||
* <p> If the function passed to the {@code jsHandle.evaluateHandle} returns a <a
|
||||
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then {@code
|
||||
* jsHandle.evaluateHandle} would wait for the promise to resolve and return its value.
|
||||
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then
|
||||
* {@code jsHandle.evaluateHandle} would wait for the promise to resolve and return its value.
|
||||
*
|
||||
* <p> See {@link Page#evaluateHandle Page.evaluateHandle()} for more details.
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
* @since v1.8
|
||||
* @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.
|
||||
*/
|
||||
default JSHandle evaluateHandle(String expression) {
|
||||
return evaluateHandle(expression, null);
|
||||
@@ -115,41 +108,35 @@ public interface JSHandle {
|
||||
*
|
||||
* <p> This method passes this handle as the first argument to {@code expression}.
|
||||
*
|
||||
* <p> The only difference between {@code jsHandle.evaluate} and {@code jsHandle.evaluateHandle} is that {@code
|
||||
* jsHandle.evaluateHandle} returns {@code JSHandle}.
|
||||
* <p> The only difference between {@code jsHandle.evaluate} and {@code jsHandle.evaluateHandle} is that {@code jsHandle.evaluateHandle} returns
|
||||
* {@code JSHandle}.
|
||||
*
|
||||
* <p> If the function passed to the {@code jsHandle.evaluateHandle} returns a <a
|
||||
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then {@code
|
||||
* jsHandle.evaluateHandle} would wait for the promise to resolve and return its value.
|
||||
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then
|
||||
* {@code jsHandle.evaluateHandle} would wait for the promise to resolve and return its value.
|
||||
*
|
||||
* <p> See {@link Page#evaluateHandle Page.evaluateHandle()} for more details.
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
* @param 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 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 })");
|
||||
* JSHandle handle = page.evaluateHandle("() => ({window, document}"););
|
||||
* Map<String, JSHandle> properties = handle.getProperties();
|
||||
* JSHandle windowHandle = properties.get("window");
|
||||
* 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);
|
||||
/**
|
||||
@@ -157,8 +144,6 @@ 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,8 +20,7 @@ import com.microsoft.playwright.options.*;
|
||||
|
||||
/**
|
||||
* Keyboard provides an api for managing a virtual keyboard. The high level api is {@link Keyboard#type Keyboard.type()},
|
||||
* which takes raw characters and generates proper {@code keydown}, {@code keypress}/{@code input}, and {@code keyup}
|
||||
* events on your page.
|
||||
* which takes raw characters and generates proper keydown, keypress/input, and 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.
|
||||
@@ -90,21 +89,18 @@ 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,
|
||||
@@ -113,49 +109,37 @@ 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);
|
||||
/**
|
||||
* <strong>NOTE:</strong> In most cases, you should use {@link Locator#press Locator.press()} instead.
|
||||
*
|
||||
* <p> {@code key} can specify the intended <a
|
||||
* {@code key} can specify the intended <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key">keyboardEvent.key</a> value or a single
|
||||
* 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> **Usage**
|
||||
* <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.
|
||||
* <pre>{@code
|
||||
* Page page = browser.newPage();
|
||||
* page.navigate("https://keycode.info");
|
||||
@@ -171,36 +155,28 @@ 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);
|
||||
}
|
||||
/**
|
||||
* <strong>NOTE:</strong> In most cases, you should use {@link Locator#press Locator.press()} instead.
|
||||
*
|
||||
* <p> {@code key} can specify the intended <a
|
||||
* {@code key} can specify the intended <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key">keyboardEvent.key</a> value or a single
|
||||
* 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> **Usage**
|
||||
* <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.
|
||||
* <pre>{@code
|
||||
* Page page = browser.newPage();
|
||||
* page.navigate("https://keycode.info");
|
||||
@@ -216,19 +192,12 @@ 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);
|
||||
/**
|
||||
* <strong>NOTE:</strong> In most cases, you should use {@link Locator#fill Locator.fill()} instead. You only need to press keys one by one if
|
||||
* there is special keyboard handling on the page - in this case use {@link Locator#pressSequentially
|
||||
* Locator.pressSequentially()}.
|
||||
*
|
||||
* <p> Sends a {@code keydown}, {@code keypress}/{@code input}, and {@code keyup} event for each character in the text.
|
||||
* 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");
|
||||
@@ -241,21 +210,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
|
||||
*/
|
||||
default void type(String text) {
|
||||
type(text, null);
|
||||
}
|
||||
/**
|
||||
* <strong>NOTE:</strong> In most cases, you should use {@link Locator#fill Locator.fill()} instead. You only need to press keys one by one if
|
||||
* there is special keyboard handling on the page - in this case use {@link Locator#pressSequentially
|
||||
* Locator.pressSequentially()}.
|
||||
*
|
||||
* <p> Sends a {@code keydown}, {@code keypress}/{@code input}, and {@code keyup} event for each character in the text.
|
||||
* 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");
|
||||
@@ -268,14 +230,12 @@ 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,23 +161,17 @@ 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);
|
||||
@@ -185,50 +179,36 @@ 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);
|
||||
/**
|
||||
@@ -239,7 +219,6 @@ 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,53 +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/extensibility">extensibility</a> for more information.
|
||||
*
|
||||
* @since v1.8
|
||||
* href="https://playwright.dev/java/docs/selectors">Working with selectors</a> for more information.
|
||||
*/
|
||||
Selectors selectors();
|
||||
/**
|
||||
* This object can be used to launch or connect to WebKit, returning instances of {@code Browser}.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
BrowserType webkit();
|
||||
/**
|
||||
* Terminates this instance of Playwright, will also close all created browsers if they are still running.
|
||||
*
|
||||
* @since v1.9
|
||||
*/
|
||||
void close();
|
||||
/**
|
||||
* Launches new Playwright driver process and connects to it. {@link Playwright#close Playwright.close()} should be called
|
||||
* when the instance is no longer needed.
|
||||
* <pre>{@code
|
||||
* Playwright playwright = Playwright.create();
|
||||
* Playwright playwright = Playwright.create()) {
|
||||
* Browser browser = playwright.webkit().launch();
|
||||
* Page page = browser.newPage();
|
||||
* page.navigate("https://www.w3.org/");
|
||||
* playwright.close();
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.10
|
||||
*/
|
||||
static Playwright create(CreateOptions options) {
|
||||
return PlaywrightImpl.create(options);
|
||||
|
||||
@@ -28,117 +28,75 @@ import java.util.*;
|
||||
* complete.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p> If request fails at some point, then instead of {@code "requestfinished"} event (and possibly instead of 'response'
|
||||
* event), the {@link Page#onRequestFailed Page.onRequestFailed()} event is emitted.
|
||||
* <p> If request fails at some point, then instead of {@code "requestfinished"} event (and possibly instead of 'response' event),
|
||||
* the {@link Page#onRequestFailed Page.onRequestFailed()} event is emitted.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> HTTP Error responses, such as 404 or 503, are still successful responses from HTTP standpoint, so request will complete
|
||||
* with {@code "requestfinished"} event.
|
||||
*
|
||||
* <p> If request gets a 'redirect' response, the request is successfully finished with the {@code requestfinished} event, and
|
||||
* a new request is issued to a redirected url.
|
||||
* <p> If request gets a 'redirect' response, the request is successfully finished with the '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.
|
||||
*
|
||||
* <p> **Usage**
|
||||
* <pre>{@code
|
||||
* String frameUrl = request.frame().url();
|
||||
* }</pre>
|
||||
*
|
||||
* <p> **Details**
|
||||
*
|
||||
* <p> Note that in some cases the frame is not available, and this method will throw.
|
||||
* <ul>
|
||||
* <li> When request originates in the Service Worker. You can use {@code request.serviceWorker()} to check that.</li>
|
||||
* <li> When navigation request is issued before the corresponding frame is created. You can use {@link
|
||||
* Request#isNavigationRequest Request.isNavigationRequest()} to check that.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p> Here is an example that handles all the cases:
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @since v1.15
|
||||
* Request.allHeaders()}, header names are NOT lower-cased. Headers with multiple entries, such as {@code Set-Cookie}, appear in
|
||||
* the array multiple times.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* <p> Some navigation requests are issued before the corresponding frame is created, and therefore do not have {@link
|
||||
* Request#frame Request.frame()} available.
|
||||
*
|
||||
* @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> **Usage**
|
||||
* <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> For example, if the website {@code http://example.com} redirects to {@code https://example.com}:
|
||||
* <pre>{@code
|
||||
@@ -151,49 +109,35 @@ 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}.
|
||||
*
|
||||
* @since v1.8
|
||||
* 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}.
|
||||
*/
|
||||
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();
|
||||
@@ -201,14 +145,10 @@ public interface Request {
|
||||
* });
|
||||
* page.navigate("http://example.com");
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
Timing timing();
|
||||
/**
|
||||
* URL of the request.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
String url();
|
||||
}
|
||||
|
||||
@@ -25,113 +25,81 @@ 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.
|
||||
*
|
||||
* @since v1.15
|
||||
* Response.allHeaders()}, header names are NOT lower-cased. Headers with multiple entries, such as {@code Set-Cookie}, appear in
|
||||
* the array multiple times.
|
||||
*/
|
||||
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,84 +136,6 @@ public interface Route {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class FetchOptions {
|
||||
/**
|
||||
* If set changes the request HTTP headers. Header values will be converted to a string.
|
||||
*/
|
||||
public Map<String, String> headers;
|
||||
/**
|
||||
* Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is
|
||||
* exceeded. Defaults to {@code 20}. Pass {@code 0} to not follow redirects.
|
||||
*/
|
||||
public Integer maxRedirects;
|
||||
/**
|
||||
* If set changes the request method (e.g. GET or POST).
|
||||
*/
|
||||
public String method;
|
||||
/**
|
||||
* If set changes the post data of request.
|
||||
*/
|
||||
public Object postData;
|
||||
/**
|
||||
* Request timeout in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout.
|
||||
*/
|
||||
public Double timeout;
|
||||
/**
|
||||
* If set changes the request URL. New URL must have same protocol as original one.
|
||||
*/
|
||||
public String url;
|
||||
|
||||
/**
|
||||
* If set changes the request HTTP headers. Header values will be converted to a string.
|
||||
*/
|
||||
public FetchOptions setHeaders(Map<String, String> headers) {
|
||||
this.headers = headers;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Maximum number of request redirects that will be followed automatically. An error will be thrown if the number is
|
||||
* exceeded. Defaults to {@code 20}. Pass {@code 0} to not follow redirects.
|
||||
*/
|
||||
public FetchOptions setMaxRedirects(int maxRedirects) {
|
||||
this.maxRedirects = maxRedirects;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* If set changes the request method (e.g. GET or POST).
|
||||
*/
|
||||
public FetchOptions setMethod(String method) {
|
||||
this.method = method;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* If set changes the post data of request.
|
||||
*/
|
||||
public FetchOptions setPostData(String postData) {
|
||||
this.postData = postData;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* If set changes the post data of request.
|
||||
*/
|
||||
public FetchOptions setPostData(byte[] postData) {
|
||||
this.postData = postData;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Request timeout in milliseconds. Defaults to {@code 30000} (30 seconds). Pass {@code 0} to disable timeout.
|
||||
*/
|
||||
public FetchOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
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.
|
||||
@@ -232,13 +154,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;
|
||||
/**
|
||||
@@ -275,16 +197,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;
|
||||
@@ -300,8 +222,6 @@ public interface Route {
|
||||
}
|
||||
/**
|
||||
* Aborts the route's request.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
default void abort() {
|
||||
abort(null);
|
||||
@@ -313,11 +233,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>
|
||||
@@ -328,13 +248,10 @@ 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
|
||||
@@ -344,23 +261,12 @@ public interface Route {
|
||||
* route.resume(new Route.ResumeOptions().setHeaders(headers));
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> **Details**
|
||||
*
|
||||
* <p> Note that any overrides such as {@code url} or {@code headers} only apply to the request being routed. If this request
|
||||
* results in a redirect, overrides will not be applied to the new redirected request. If you want to propagate a header
|
||||
* through redirects, use the combination of {@link Route#fetch Route.fetch()} and {@link Route#fulfill Route.fulfill()}
|
||||
* instead.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
default void resume() {
|
||||
resume(null);
|
||||
}
|
||||
/**
|
||||
* Continues route's request with optional overrides.
|
||||
*
|
||||
* <p> **Usage**
|
||||
* <pre>{@code
|
||||
* page.route("**\/*", route -> {
|
||||
* // Override headers
|
||||
@@ -370,15 +276,6 @@ public interface Route {
|
||||
* route.resume(new Route.ResumeOptions().setHeaders(headers));
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> **Details**
|
||||
*
|
||||
* <p> Note that any overrides such as {@code url} or {@code headers} only apply to the request being routed. If this request
|
||||
* results in a redirect, overrides will not be applied to the new redirected request. If you want to propagate a header
|
||||
* through redirects, use the combination of {@link Route#fetch Route.fetch()} and {@link Route#fulfill Route.fulfill()}
|
||||
* instead.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
void resume(ResumeOptions options);
|
||||
/**
|
||||
@@ -386,8 +283,6 @@ 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.
|
||||
@@ -440,8 +335,6 @@ public interface Route {
|
||||
* route.fallback(new Route.ResumeOptions().setHeaders(headers));
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.23
|
||||
*/
|
||||
default void fallback() {
|
||||
fallback(null);
|
||||
@@ -451,8 +344,6 @@ 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.
|
||||
@@ -505,69 +396,11 @@ public interface Route {
|
||||
* route.fallback(new Route.ResumeOptions().setHeaders(headers));
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* @since v1.23
|
||||
*/
|
||||
void fallback(FallbackOptions options);
|
||||
/**
|
||||
* Performs the request and fetches result without fulfilling it, so that the response could be modified and then
|
||||
* fulfilled.
|
||||
*
|
||||
* <p> **Usage**
|
||||
* <pre>{@code
|
||||
* page.route("https://dog.ceo/api/breeds/list/all", route -> {
|
||||
* APIResponse response = route.fetch();
|
||||
* JsonObject json = new Gson().fromJson(response.text(), JsonObject.class);
|
||||
* JsonObject message = itemObj.get("json").getAsJsonObject();
|
||||
* message.set("big_red_dog", new JsonArray());
|
||||
* route.fulfill(new Route.FulfillOptions()
|
||||
* .setResponse(response)
|
||||
* .setBody(json.toString()));
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> **Details**
|
||||
*
|
||||
* <p> Note that {@code headers} option will apply to the fetched request as well as any redirects initiated by it. If you want
|
||||
* to only apply {@code headers} to the original request, but not to redirects, look into {@link Route#resume
|
||||
* Route.resume()} instead.
|
||||
*
|
||||
* @since v1.29
|
||||
*/
|
||||
default APIResponse fetch() {
|
||||
return fetch(null);
|
||||
}
|
||||
/**
|
||||
* Performs the request and fetches result without fulfilling it, so that the response could be modified and then
|
||||
* fulfilled.
|
||||
*
|
||||
* <p> **Usage**
|
||||
* <pre>{@code
|
||||
* page.route("https://dog.ceo/api/breeds/list/all", route -> {
|
||||
* APIResponse response = route.fetch();
|
||||
* JsonObject json = new Gson().fromJson(response.text(), JsonObject.class);
|
||||
* JsonObject message = itemObj.get("json").getAsJsonObject();
|
||||
* message.set("big_red_dog", new JsonArray());
|
||||
* route.fulfill(new Route.FulfillOptions()
|
||||
* .setResponse(response)
|
||||
* .setBody(json.toString()));
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> **Details**
|
||||
*
|
||||
* <p> Note that {@code headers} option will apply to the fetched request as well as any redirects initiated by it. If you want
|
||||
* to only apply {@code headers} to the original request, but not to redirects, look into {@link Route#resume
|
||||
* Route.resume()} instead.
|
||||
*
|
||||
* @since v1.29
|
||||
*/
|
||||
APIResponse fetch(FetchOptions options);
|
||||
/**
|
||||
* Fulfills route's request with given response.
|
||||
*
|
||||
* <p> **Usage**
|
||||
*
|
||||
* <p> An example of fulfilling all requests with 404 responses:
|
||||
* <pre>{@code
|
||||
* page.route("**\/*", route -> {
|
||||
@@ -583,8 +416,6 @@ 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);
|
||||
@@ -592,8 +423,6 @@ 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 -> {
|
||||
@@ -609,14 +438,10 @@ 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/extensibility">extensibility</a> for more information.
|
||||
* href="https://playwright.dev/java/docs/selectors">Working with selectors</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,11 +42,7 @@ public interface Selectors {
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Selectors must be registered before creating the page.
|
||||
*
|
||||
* <p> **Usage**
|
||||
*
|
||||
* <p> An example of registering selector engine that queries elements based on a tag name:
|
||||
* 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" +
|
||||
@@ -66,27 +62,22 @@ public interface Selectors {
|
||||
* page.setContent("<div><button>Click me</button></div>");
|
||||
* // Use the selector prefixed with its name.
|
||||
* Locator button = page.locator("tag=button");
|
||||
* // Combine it with built-in locators.
|
||||
* page.locator("tag=div").getByText("Click me").click();
|
||||
* // Combine it with other selector engines.
|
||||
* page.locator("tag=div >> text=\"Click me\"").click();
|
||||
* // Can use it in any methods supporting selectors.
|
||||
* int buttonCount = (int) page.locator("tag=button").count();
|
||||
* browser.close();
|
||||
* }</pre>
|
||||
*
|
||||
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May
|
||||
* only contain {@code [a-zA-Z0-9_]} characters.
|
||||
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May only
|
||||
* contain {@code [a-zA-Z0-9_]} characters.
|
||||
* @param script Script that evaluates to a selector engine instance. The script is evaluated in the page context.
|
||||
* @since v1.8
|
||||
*/
|
||||
default void register(String name, String script) {
|
||||
register(name, script, null);
|
||||
}
|
||||
/**
|
||||
* Selectors must be registered before creating the page.
|
||||
*
|
||||
* <p> **Usage**
|
||||
*
|
||||
* <p> An example of registering selector engine that queries elements based on a tag name:
|
||||
* 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" +
|
||||
@@ -106,25 +97,20 @@ public interface Selectors {
|
||||
* page.setContent("<div><button>Click me</button></div>");
|
||||
* // Use the selector prefixed with its name.
|
||||
* Locator button = page.locator("tag=button");
|
||||
* // Combine it with built-in locators.
|
||||
* page.locator("tag=div").getByText("Click me").click();
|
||||
* // Combine it with other selector engines.
|
||||
* page.locator("tag=div >> text=\"Click me\"").click();
|
||||
* // Can use it in any methods supporting selectors.
|
||||
* int buttonCount = (int) page.locator("tag=button").count();
|
||||
* browser.close();
|
||||
* }</pre>
|
||||
*
|
||||
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May
|
||||
* only contain {@code [a-zA-Z0-9_]} characters.
|
||||
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May only
|
||||
* contain {@code [a-zA-Z0-9_]} characters.
|
||||
* @param script Script that evaluates to a selector engine instance. The script is evaluated in the page context.
|
||||
* @since v1.8
|
||||
*/
|
||||
void register(String name, String script, RegisterOptions options);
|
||||
/**
|
||||
* Selectors must be registered before creating the page.
|
||||
*
|
||||
* <p> **Usage**
|
||||
*
|
||||
* <p> An example of registering selector engine that queries elements based on a tag name:
|
||||
* 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" +
|
||||
@@ -144,27 +130,22 @@ public interface Selectors {
|
||||
* page.setContent("<div><button>Click me</button></div>");
|
||||
* // Use the selector prefixed with its name.
|
||||
* Locator button = page.locator("tag=button");
|
||||
* // Combine it with built-in locators.
|
||||
* page.locator("tag=div").getByText("Click me").click();
|
||||
* // Combine it with other selector engines.
|
||||
* page.locator("tag=div >> text=\"Click me\"").click();
|
||||
* // Can use it in any methods supporting selectors.
|
||||
* int buttonCount = (int) page.locator("tag=button").count();
|
||||
* browser.close();
|
||||
* }</pre>
|
||||
*
|
||||
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May
|
||||
* only contain {@code [a-zA-Z0-9_]} characters.
|
||||
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May only
|
||||
* contain {@code [a-zA-Z0-9_]} characters.
|
||||
* @param script Script that evaluates to a selector engine instance. The script is evaluated in the page context.
|
||||
* @since v1.8
|
||||
*/
|
||||
default void register(String name, Path script) {
|
||||
register(name, script, null);
|
||||
}
|
||||
/**
|
||||
* Selectors must be registered before creating the page.
|
||||
*
|
||||
* <p> **Usage**
|
||||
*
|
||||
* <p> An example of registering selector engine that queries elements based on a tag name:
|
||||
* 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" +
|
||||
@@ -184,26 +165,17 @@ public interface Selectors {
|
||||
* page.setContent("<div><button>Click me</button></div>");
|
||||
* // Use the selector prefixed with its name.
|
||||
* Locator button = page.locator("tag=button");
|
||||
* // Combine it with built-in locators.
|
||||
* page.locator("tag=div").getByText("Click me").click();
|
||||
* // Combine it with other selector engines.
|
||||
* page.locator("tag=div >> text=\"Click me\"").click();
|
||||
* // Can use it in any methods supporting selectors.
|
||||
* int buttonCount = (int) page.locator("tag=button").count();
|
||||
* browser.close();
|
||||
* }</pre>
|
||||
*
|
||||
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May
|
||||
* only contain {@code [a-zA-Z0-9_]} characters.
|
||||
* @param name Name that is used in selectors as a prefix, e.g. {@code {name: 'foo'}} enables {@code foo=myselectorbody} selectors. May only
|
||||
* contain {@code [a-zA-Z0-9_]} characters.
|
||||
* @param script Script that evaluates to a selector engine instance. The script is evaluated in the page context.
|
||||
* @since v1.8
|
||||
*/
|
||||
void register(String name, Path script, RegisterOptions options);
|
||||
/**
|
||||
* 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,10 +24,6 @@ package com.microsoft.playwright;
|
||||
public interface Touchscreen {
|
||||
/**
|
||||
* Dispatches a {@code touchstart} and {@code touchend} event with a single touch at the position ({@code x},{@code y}).
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> {@link Page#tap Page.tap()} the method will throw if {@code hasTouch} option of the browser context is false.
|
||||
*
|
||||
* @since v1.8
|
||||
*/
|
||||
void tap(double x, double y);
|
||||
}
|
||||
|
||||
@@ -38,9 +38,8 @@ import java.nio.file.Path;
|
||||
public interface Tracing {
|
||||
class StartOptions {
|
||||
/**
|
||||
* If specified, intermediate trace files are going to be saved into the files with the given name prefix inside the {@code
|
||||
* tracesDir} folder specified in {@link BrowserType#launch BrowserType.launch()}. To specify the final trace zip file
|
||||
* name, you need to pass {@code path} option to {@link Tracing#stop Tracing.stop()} instead.
|
||||
* 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;
|
||||
/**
|
||||
@@ -57,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;
|
||||
/**
|
||||
@@ -67,9 +66,8 @@ public interface Tracing {
|
||||
public String title;
|
||||
|
||||
/**
|
||||
* If specified, intermediate trace files are going to be saved into the files with the given name prefix inside the {@code
|
||||
* tracesDir} folder specified in {@link BrowserType#launch BrowserType.launch()}. To specify the final trace zip file
|
||||
* name, you need to pass {@code path} option to {@link Tracing#stop Tracing.stop()} instead.
|
||||
* 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;
|
||||
@@ -95,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;
|
||||
@@ -111,26 +109,11 @@ public interface Tracing {
|
||||
}
|
||||
}
|
||||
class StartChunkOptions {
|
||||
/**
|
||||
* If specified, intermediate trace files are going to be saved into the files with the given name prefix inside the {@code
|
||||
* tracesDir} folder specified in {@link BrowserType#launch BrowserType.launch()}. To specify the final trace zip file
|
||||
* name, you need to pass {@code path} option to {@link Tracing#stopChunk Tracing.stopChunk()} instead.
|
||||
*/
|
||||
public String name;
|
||||
/**
|
||||
* Trace name to be shown in the Trace Viewer.
|
||||
*/
|
||||
public String title;
|
||||
|
||||
/**
|
||||
* If specified, intermediate trace files are going to be saved into the files with the given name prefix inside the {@code
|
||||
* tracesDir} folder specified in {@link BrowserType#launch BrowserType.launch()}. To specify the final trace zip file
|
||||
* name, you need to pass {@code path} option to {@link Tracing#stopChunk Tracing.stopChunk()} instead.
|
||||
*/
|
||||
public StartChunkOptions setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Trace name to be shown in the Trace Viewer.
|
||||
*/
|
||||
@@ -171,8 +154,6 @@ public interface Tracing {
|
||||
}
|
||||
/**
|
||||
* Start tracing.
|
||||
*
|
||||
* <p> **Usage**
|
||||
* <pre>{@code
|
||||
* context.tracing().start(new Tracing.StartOptions()
|
||||
* .setScreenshots(true)
|
||||
@@ -182,16 +163,12 @@ 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)
|
||||
@@ -201,16 +178,12 @@ 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()}.
|
||||
*
|
||||
* <p> **Usage**
|
||||
* 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()}.
|
||||
* <pre>{@code
|
||||
* context.tracing().start(new Tracing.StartOptions()
|
||||
* .setScreenshots(true)
|
||||
@@ -219,7 +192,7 @@ public interface Tracing {
|
||||
* page.navigate("https://playwright.dev");
|
||||
*
|
||||
* context.tracing().startChunk();
|
||||
* page.getByText("Get Started").click();
|
||||
* page.locator("text=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,18 +203,14 @@ 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()}.
|
||||
*
|
||||
* <p> **Usage**
|
||||
* 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()}.
|
||||
* <pre>{@code
|
||||
* context.tracing().start(new Tracing.StartOptions()
|
||||
* .setScreenshots(true)
|
||||
@@ -250,7 +219,7 @@ public interface Tracing {
|
||||
* page.navigate("https://playwright.dev");
|
||||
*
|
||||
* context.tracing().startChunk();
|
||||
* page.getByText("Get Started").click();
|
||||
* page.locator("text=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")));
|
||||
@@ -261,36 +230,26 @@ 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,15 +27,11 @@ 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();
|
||||
/**
|
||||
@@ -43,7 +39,6 @@ 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);
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
|
||||
/**
|
||||
* {@code WebError} class represents an unhandled exception thrown in the page. It is dispatched via the {@link
|
||||
* BrowserContext#onWebError BrowserContext.onWebError()} event.
|
||||
* <pre>{@code
|
||||
* // Log all uncaught errors to the terminal
|
||||
* context.onWebError(webError -> {
|
||||
* System.out.println("Uncaught exception: " + webError.error());
|
||||
* });
|
||||
*
|
||||
* // Navigate to a page with an exception.
|
||||
* page.navigate("data:text/html,<script>throw new Error('Test')</script>");
|
||||
* }</pre>
|
||||
*/
|
||||
public interface WebError {
|
||||
/**
|
||||
* The page that produced this unhandled exception, if any.
|
||||
*
|
||||
* @since v1.38
|
||||
*/
|
||||
Page page();
|
||||
/**
|
||||
* Unhandled error that was thrown.
|
||||
*
|
||||
* @since v1.38
|
||||
*/
|
||||
String error();
|
||||
}
|
||||
|
||||
@@ -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,54 +116,46 @@ 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,21 +18,17 @@ 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,12 +68,11 @@ public interface Worker {
|
||||
* Worker#evaluate Worker.evaluate()} would wait for the promise to resolve and return its value.
|
||||
*
|
||||
* <p> If the function passed to the {@link Worker#evaluate Worker.evaluate()} returns a non-[Serializable] value, then {@link
|
||||
* Worker#evaluate Worker.evaluate()} returns {@code undefined}. Playwright also supports transferring some additional
|
||||
* values that are not serializable by {@code JSON}: {@code -0}, {@code NaN}, {@code Infinity}, {@code -Infinity}.
|
||||
* Worker#evaluate Worker.evaluate()} returns {@code undefined}. Playwright also supports transferring some additional values
|
||||
* that are not serializable by {@code JSON}: {@code -0}, {@code NaN}, {@code Infinity}, {@code -Infinity}.
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
* @since v1.8
|
||||
* @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.
|
||||
*/
|
||||
default Object evaluate(String expression) {
|
||||
return evaluate(expression, null);
|
||||
@@ -86,13 +85,12 @@ public interface Worker {
|
||||
* Worker#evaluate Worker.evaluate()} would wait for the promise to resolve and return its value.
|
||||
*
|
||||
* <p> If the function passed to the {@link Worker#evaluate Worker.evaluate()} returns a non-[Serializable] value, then {@link
|
||||
* Worker#evaluate Worker.evaluate()} returns {@code undefined}. Playwright also supports transferring some additional
|
||||
* values that are not serializable by {@code JSON}: {@code -0}, {@code NaN}, {@code Infinity}, {@code -Infinity}.
|
||||
* Worker#evaluate Worker.evaluate()} returns {@code undefined}. Playwright also supports transferring some additional values
|
||||
* that are not serializable by {@code JSON}: {@code -0}, {@code NaN}, {@code Infinity}, {@code -Infinity}.
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
* @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 arg Optional argument to pass to {@code expression}.
|
||||
* @since v1.8
|
||||
*/
|
||||
Object evaluate(String expression, Object arg);
|
||||
/**
|
||||
@@ -105,9 +103,8 @@ public interface Worker {
|
||||
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then {@link
|
||||
* Worker#evaluateHandle Worker.evaluateHandle()} would wait for the promise to resolve and return its value.
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
* @since v1.8
|
||||
* @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.
|
||||
*/
|
||||
default JSHandle evaluateHandle(String expression) {
|
||||
return evaluateHandle(expression, null);
|
||||
@@ -122,23 +119,16 @@ 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 the expression evaluates to a function, the function is
|
||||
* automatically invoked.
|
||||
* @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 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);
|
||||
@@ -147,7 +137,6 @@ 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);
|
||||
}
|
||||
|
||||
+3
-8
@@ -18,8 +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.
|
||||
* 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;
|
||||
@@ -42,19 +43,13 @@ 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();
|
||||
}
|
||||
|
||||
+138
-586
File diff suppressed because it is too large
Load Diff
@@ -19,8 +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.
|
||||
* 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;
|
||||
@@ -30,7 +31,7 @@ import java.util.regex.Pattern;
|
||||
* @Test
|
||||
* void navigatesToLoginPage() {
|
||||
* ...
|
||||
* page.getByText("Sign in").click();
|
||||
* page.locator("#login").click();
|
||||
* assertThat(page).hasURL(Pattern.compile(".*\/login"));
|
||||
* }
|
||||
* }
|
||||
@@ -39,12 +40,12 @@ import java.util.regex.Pattern;
|
||||
public interface PageAssertions {
|
||||
class HasTitleOptions {
|
||||
/**
|
||||
* Time to retry the assertion for in milliseconds. Defaults to {@code 5000}.
|
||||
* Time to retry the assertion for.
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* Time to retry the assertion for in milliseconds. Defaults to {@code 5000}.
|
||||
* Time to retry the assertion for.
|
||||
*/
|
||||
public HasTitleOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
@@ -53,12 +54,12 @@ public interface PageAssertions {
|
||||
}
|
||||
class HasURLOptions {
|
||||
/**
|
||||
* Time to retry the assertion for in milliseconds. Defaults to {@code 5000}.
|
||||
* Time to retry the assertion for.
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
/**
|
||||
* Time to retry the assertion for in milliseconds. Defaults to {@code 5000}.
|
||||
* Time to retry the assertion for.
|
||||
*/
|
||||
public HasURLOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
@@ -71,112 +72,86 @@ 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);
|
||||
}
|
||||
|
||||
+3
-15
@@ -44,23 +44,20 @@ 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);
|
||||
@@ -68,14 +65,11 @@ 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);
|
||||
@@ -83,14 +77,11 @@ 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);
|
||||
@@ -98,14 +89,11 @@ 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);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.*;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.APIRequestContext;
|
||||
import com.microsoft.playwright.APIResponse;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
@@ -10,7 +11,6 @@ import com.microsoft.playwright.options.FilePayload;
|
||||
import com.microsoft.playwright.options.RequestOptions;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Base64;
|
||||
@@ -85,14 +85,11 @@ class APIRequestContextImpl extends ChannelOwner implements APIRequestContext {
|
||||
byte[] bytes = null;
|
||||
if (options.data instanceof byte[]) {
|
||||
bytes = (byte[]) options.data;
|
||||
} else if (options.data instanceof String) {
|
||||
String stringData = (String) options.data;
|
||||
if (!isJsonContentType(options.headers) || isJsonParsable(stringData)) {
|
||||
bytes = (stringData).getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
} else if (options.data instanceof String && !isJsonContentType(options.headers)) {
|
||||
bytes = ((String) options.data).getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
if (bytes == null) {
|
||||
params.addProperty("jsonData", gson().toJson(options.data));
|
||||
params.add("jsonData", gson().toJsonTree(options.data));
|
||||
} else {
|
||||
String base64 = Base64.getEncoder().encodeToString(bytes);
|
||||
params.addProperty("postData", base64);
|
||||
@@ -196,7 +193,7 @@ class APIRequestContextImpl extends ChannelOwner implements APIRequestContext {
|
||||
}
|
||||
|
||||
private static RequestOptionsImpl ensureOptions(RequestOptions options, String method) {
|
||||
RequestOptionsImpl impl = Utils.clone((RequestOptionsImpl) options);
|
||||
RequestOptionsImpl impl = (RequestOptionsImpl) options;
|
||||
if (impl == null) {
|
||||
impl = new RequestOptionsImpl();
|
||||
}
|
||||
@@ -205,21 +202,4 @@ class APIRequestContextImpl extends ChannelOwner implements APIRequestContext {
|
||||
}
|
||||
return impl;
|
||||
}
|
||||
|
||||
private static boolean isJsonParsable(String value) {
|
||||
try {
|
||||
JsonElement result = JsonParser.parseString(value);
|
||||
if (result != null && result.isJsonPrimitive()) {
|
||||
JsonPrimitive primitive = result.getAsJsonPrimitive();
|
||||
if (primitive.isString() && value.equals(primitive.getAsString())) {
|
||||
// Gson parses unquoted strings too, but we don't want to treat them
|
||||
// as valid JSON.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (JsonSyntaxException error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,6 @@ package com.microsoft.playwright.impl;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Path;
|
||||
@@ -28,30 +26,20 @@ 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);
|
||||
}
|
||||
|
||||
public InputStream createReadStream() {
|
||||
JsonObject result = sendMessage("stream").getAsJsonObject();
|
||||
if (!result.has("stream")) {
|
||||
return null;
|
||||
}
|
||||
Stream stream = connection.getExistingObject(result.getAsJsonObject("stream").get("guid").getAsString());
|
||||
return stream.stream();
|
||||
}
|
||||
|
||||
byte[] readAllBytes() {
|
||||
final int bufLen = 1024 * 1024;
|
||||
byte[] buf = new byte[bufLen];
|
||||
int readLen;
|
||||
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); InputStream stream = createReadStream()) {
|
||||
while ((readLen = stream.read(buf, 0, bufLen)) != -1) {
|
||||
outputStream.write(buf, 0, readLen);
|
||||
}
|
||||
return outputStream.toByteArray();
|
||||
} catch (IOException e) {
|
||||
throw new PlaywrightException("Failed to read artifact", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
sendMessage("cancel");
|
||||
}
|
||||
@@ -69,7 +57,7 @@ class ArtifactImpl extends ChannelOwner {
|
||||
}
|
||||
|
||||
public Path pathAfterFinished() {
|
||||
if (connection.isRemote) {
|
||||
if (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();
|
||||
@@ -77,7 +65,7 @@ class ArtifactImpl extends ChannelOwner {
|
||||
}
|
||||
|
||||
public void saveAs(Path path) {
|
||||
if (connection.isRemote) {
|
||||
if (isRemote) {
|
||||
JsonObject jsonObject = sendMessage("saveAsStream").getAsJsonObject();
|
||||
Stream stream = connection.getExistingObject(jsonObject.getAsJsonObject("stream").get("guid").getAsString());
|
||||
writeToFile(stream.stream(), path);
|
||||
|
||||
@@ -29,7 +29,6 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -47,23 +46,10 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
private final APIRequestContextImpl request;
|
||||
final List<PageImpl> pages = new ArrayList<>();
|
||||
final Router routes = new Router();
|
||||
private boolean closeWasCalled;
|
||||
private final WaitableEvent<EventType, ?> closePromise;
|
||||
private boolean isClosedOrClosing;
|
||||
final Map<String, BindingCallback> bindings = new HashMap<>();
|
||||
PageImpl ownerPage;
|
||||
private String closeReason;
|
||||
|
||||
private static final Map<EventType, String> eventSubscriptions() {
|
||||
Map<EventType, String> result = new HashMap<>();
|
||||
result.put(EventType.CONSOLE, "console");
|
||||
result.put(EventType.DIALOG, "dialog");
|
||||
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);
|
||||
private final ListenerCollection<EventType> listeners = new ListenerCollection<>();
|
||||
final TimeoutSettings timeoutSettings = new TimeoutSettings();
|
||||
Path videosDir;
|
||||
URL baseUrl;
|
||||
@@ -81,10 +67,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
|
||||
enum EventType {
|
||||
CLOSE,
|
||||
CONSOLE,
|
||||
DIALOG,
|
||||
PAGE,
|
||||
WEBERROR,
|
||||
REQUEST,
|
||||
REQUESTFAILED,
|
||||
REQUESTFINISHED,
|
||||
@@ -98,9 +81,9 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
} else {
|
||||
browser = null;
|
||||
}
|
||||
tracing = connection.getExistingObject(initializer.getAsJsonObject("tracing").get("guid").getAsString());
|
||||
request = connection.getExistingObject(initializer.getAsJsonObject("requestContext").get("guid").getAsString());
|
||||
closePromise = new WaitableEvent<>(listeners, EventType.CLOSE);
|
||||
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());
|
||||
}
|
||||
|
||||
void setRecordHar(Path path, HarContentPolicy policy) {
|
||||
@@ -117,16 +100,6 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
}
|
||||
}
|
||||
|
||||
String effectiveCloseReason() {
|
||||
if (closeReason != null) {
|
||||
return closeReason;
|
||||
}
|
||||
if (browser != null) {
|
||||
return browser.closeReason;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(Consumer<BrowserContext> handler) {
|
||||
listeners.add(EventType.CLOSE, handler);
|
||||
@@ -137,26 +110,6 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
listeners.remove(EventType.CLOSE, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConsoleMessage(Consumer<ConsoleMessage> handler) {
|
||||
listeners.add(EventType.CONSOLE, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offConsoleMessage(Consumer<ConsoleMessage> handler) {
|
||||
listeners.remove(EventType.CONSOLE, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDialog(Consumer<Dialog> handler) {
|
||||
listeners.add(EventType.DIALOG, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offDialog(Consumer<Dialog> handler) {
|
||||
listeners.remove(EventType.DIALOG, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPage(Consumer<Page> handler) {
|
||||
listeners.add(EventType.PAGE, handler);
|
||||
@@ -167,16 +120,6 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
listeners.remove(EventType.PAGE, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebError(Consumer<WebError> handler) {
|
||||
listeners.add(EventType.WEBERROR, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offWebError(Consumer<WebError> handler) {
|
||||
listeners.remove(EventType.WEBERROR, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequest(Consumer<Request> handler) {
|
||||
listeners.add(EventType.REQUEST, handler);
|
||||
@@ -238,24 +181,8 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CDPSession newCDPSession(Page page) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.add("page", ((PageImpl) page).toProtocolRef());
|
||||
JsonObject result = sendMessage("newCDPSession", params).getAsJsonObject();
|
||||
return connection.getExistingObject(result.getAsJsonObject("session").get("guid").getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CDPSession newCDPSession(Frame frame) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.add("frame", ((FrameImpl) frame).toProtocolRef());
|
||||
JsonObject result = sendMessage("newCDPSession", params).getAsJsonObject();
|
||||
return connection.getExistingObject(result.getAsJsonObject("session").get("guid").getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(CloseOptions options) {
|
||||
withLogging("BrowserContext.close", () -> closeImpl(options));
|
||||
public void close() {
|
||||
withLogging("BrowserContext.close", () -> closeImpl());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -263,18 +190,23 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
return cookies(url == null ? new ArrayList<>() : Collections.singletonList(url));
|
||||
}
|
||||
|
||||
private void closeImpl(CloseOptions options) {
|
||||
if (!closeWasCalled) {
|
||||
closeWasCalled = true;
|
||||
if (options == null) {
|
||||
options = new CloseOptions();
|
||||
}
|
||||
closeReason = options.reason;
|
||||
private void closeImpl() {
|
||||
if (isClosedOrClosing) {
|
||||
return;
|
||||
}
|
||||
isClosedOrClosing = true;
|
||||
try {
|
||||
for (Map.Entry<String, HarRecorder> entry : harRecorders.entrySet()) {
|
||||
JsonObject params = new JsonObject();
|
||||
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");
|
||||
@@ -291,10 +223,13 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
}
|
||||
artifact.delete();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
sendMessage("close", params);
|
||||
|
||||
sendMessage("close");
|
||||
} catch (PlaywrightException e) {
|
||||
if (!isSafeCloseError(e)) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
runUntil(() -> {}, closePromise);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -463,7 +398,11 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
private void route(UrlMatcher matcher, Consumer<Route> handler, RouteOptions options) {
|
||||
withLogging("BrowserContext.route", () -> {
|
||||
routes.add(matcher, handler, options == null ? null : options.times);
|
||||
updateInterceptionPatterns();
|
||||
if (routes.size() == 1) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("enabled", true);
|
||||
sendMessage("setNetworkInterceptionEnabled", params);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -474,12 +413,8 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
}
|
||||
JsonObject jsonOptions = new JsonObject();
|
||||
jsonOptions.addProperty("path", har.toAbsolutePath().toString());
|
||||
jsonOptions.addProperty("content", options.updateContent == null ?
|
||||
HarContentPolicy.ATTACH.name().toLowerCase() :
|
||||
options.updateContent.name().toLowerCase());
|
||||
jsonOptions.addProperty("mode", options.updateMode == null ?
|
||||
HarMode.MINIMAL.name().toLowerCase() :
|
||||
options.updateMode.name().toLowerCase());
|
||||
jsonOptions.addProperty("content", HarContentPolicy.ATTACH.name().toLowerCase());
|
||||
jsonOptions.addProperty("mode", HarMode.MINIMAL.name().toLowerCase());
|
||||
addHarUrlFilter(jsonOptions, options.url);
|
||||
params.add("options", jsonOptions);
|
||||
JsonObject json = sendMessage("harStart", params).getAsJsonObject();
|
||||
@@ -489,10 +424,6 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
|
||||
@Override
|
||||
public void setDefaultNavigationTimeout(double timeout) {
|
||||
setDefaultNavigationTimeoutImpl(timeout);
|
||||
}
|
||||
|
||||
void setDefaultNavigationTimeoutImpl(Double timeout) {
|
||||
withLogging("BrowserContext.setDefaultNavigationTimeout", () -> {
|
||||
timeoutSettings.setDefaultNavigationTimeout(timeout);
|
||||
JsonObject params = new JsonObject();
|
||||
@@ -503,10 +434,6 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
|
||||
@Override
|
||||
public void setDefaultTimeout(double timeout) {
|
||||
setDefaultTimeoutImpl(timeout);
|
||||
}
|
||||
|
||||
void setDefaultTimeoutImpl(Double timeout) {
|
||||
withLogging("BrowserContext.setDefaultTimeout", () -> {
|
||||
timeoutSettings.setDefaultTimeout(timeout);
|
||||
JsonObject params = new JsonObject();
|
||||
@@ -568,14 +495,6 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
return tracing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unrouteAll() {
|
||||
withLogging("BrowserContext.unrouteAll", () -> {
|
||||
routes.removeAll();
|
||||
updateInterceptionPatterns();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unroute(String url, Consumer<Route> handler) {
|
||||
unroute(new UrlMatcher(this.baseUrl, url), handler);
|
||||
@@ -591,27 +510,6 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
unroute(new UrlMatcher(url), handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitForCondition(BooleanSupplier predicate, WaitForConditionOptions options) {
|
||||
List<Waitable<Void>> waitables = new ArrayList<>();
|
||||
waitables.add(new WaitableContextClose<>());
|
||||
waitables.add(timeoutSettings.createWaitable(options == null ? null : options.timeout));
|
||||
waitables.add(new WaitablePredicate<>(predicate));
|
||||
runUntil(() -> {}, new WaitableRace<>(waitables));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConsoleMessage waitForConsoleMessage(WaitForConsoleMessageOptions options, Runnable code) {
|
||||
return withWaitLogging("BrowserContext.waitForConsoleMessage", logger -> waitForConsoleMessageImpl(options, code));
|
||||
}
|
||||
|
||||
private ConsoleMessage waitForConsoleMessageImpl(WaitForConsoleMessageOptions options, Runnable code) {
|
||||
if (options == null) {
|
||||
options = new WaitForConsoleMessageOptions();
|
||||
}
|
||||
return waitForEventWithTimeout(EventType.CONSOLE, code, options.predicate, options.timeout);
|
||||
}
|
||||
|
||||
private class WaitableContextClose<R> extends WaitableEvent<EventType, R> {
|
||||
WaitableContextClose() {
|
||||
super(BrowserContextImpl.this.listeners, EventType.CLOSE);
|
||||
@@ -619,69 +517,43 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
|
||||
@Override
|
||||
public R get() {
|
||||
throw new TargetClosedError(effectiveCloseReason());
|
||||
throw new PlaywrightException("Context closed");
|
||||
}
|
||||
}
|
||||
|
||||
private void unroute(UrlMatcher matcher, Consumer<Route> handler) {
|
||||
withLogging("BrowserContext.unroute", () -> {
|
||||
routes.remove(matcher, handler);
|
||||
updateInterceptionPatterns();
|
||||
maybeDisableNetworkInterception();
|
||||
});
|
||||
}
|
||||
|
||||
private void updateInterceptionPatterns() {
|
||||
sendMessage("setNetworkInterceptionPatterns", routes.interceptionPatterns());
|
||||
private void maybeDisableNetworkInterception() {
|
||||
if (routes.size() == 0) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("enabled", false);
|
||||
sendMessage("setNetworkInterceptionEnabled", params);
|
||||
}
|
||||
}
|
||||
|
||||
void handleRoute(RouteImpl route) {
|
||||
Router.HandleResult handled = routes.handle(route);
|
||||
if (handled != Router.HandleResult.NoMatchingHandler) {
|
||||
updateInterceptionPatterns();
|
||||
if (handled == Router.HandleResult.FoundMatchingHandler) {
|
||||
maybeDisableNetworkInterception();
|
||||
}
|
||||
if (handled == Router.HandleResult.NoMatchingHandler || handled == Router.HandleResult.Fallback) {
|
||||
route.resume(null, true);
|
||||
if (!route.isHandled()){
|
||||
route.resume();
|
||||
}
|
||||
}
|
||||
|
||||
WaitableResult<JsonElement> pause() {
|
||||
return sendMessageAsync("pause", new JsonObject());
|
||||
void pause() {
|
||||
sendMessage("pause");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleEvent(String event, JsonObject params) {
|
||||
if ("dialog".equals(event)) {
|
||||
String guid = params.getAsJsonObject("dialog").get("guid").getAsString();
|
||||
DialogImpl dialog = connection.getExistingObject(guid);
|
||||
boolean hasListeners = false;
|
||||
if (listeners.hasListeners(EventType.DIALOG)) {
|
||||
hasListeners = true;
|
||||
listeners.notify(EventType.DIALOG, dialog);
|
||||
}
|
||||
PageImpl page = dialog.page();
|
||||
if (page != null) {
|
||||
if (page.listeners.hasListeners(PageImpl.EventType.DIALOG)) {
|
||||
hasListeners = true;
|
||||
page.listeners.notify(PageImpl.EventType.DIALOG, dialog);
|
||||
}
|
||||
}
|
||||
// Although we do similar handling on the server side, we still need this logic
|
||||
// on the client side due to a possible race condition between two async calls:
|
||||
// a) removing "dialog" listener subscription (client->server)
|
||||
// b) actual "dialog" event (server->client)
|
||||
if (!hasListeners) {
|
||||
if ("beforeunload".equals(dialog.type())) {
|
||||
try {
|
||||
dialog.accept();
|
||||
} catch (PlaywrightException e) {
|
||||
}
|
||||
} else {
|
||||
dialog.dismiss();
|
||||
}
|
||||
}
|
||||
} else if ("route".equals(event)) {
|
||||
if ("route".equals(event)) {
|
||||
RouteImpl route = connection.getExistingObject(params.getAsJsonObject("route").get("guid").getAsString());
|
||||
route.browserContext = this;
|
||||
handleRoute(route);
|
||||
} else if ("page".equals(event)) {
|
||||
PageImpl page = connection.getExistingObject(params.getAsJsonObject("page").get("guid").getAsString());
|
||||
@@ -696,13 +568,6 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
if (binding != null) {
|
||||
bindingCall.call(binding);
|
||||
}
|
||||
} else if ("console".equals(event)) {
|
||||
ConsoleMessageImpl message = new ConsoleMessageImpl(connection, params);
|
||||
listeners.notify(BrowserContextImpl.EventType.CONSOLE, message);
|
||||
PageImpl page = message.page();
|
||||
if (page != null) {
|
||||
page.listeners.notify(PageImpl.EventType.CONSOLE, message);
|
||||
}
|
||||
} else if ("request".equals(event)) {
|
||||
String guid = params.getAsJsonObject("request").get("guid").getAsString();
|
||||
RequestImpl request = connection.getExistingObject(guid);
|
||||
@@ -746,41 +611,22 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
PageImpl page = connection.getExistingObject(params.getAsJsonObject("page").get("guid").getAsString());
|
||||
page.listeners.notify(PageImpl.EventType.RESPONSE, response);
|
||||
}
|
||||
} else if ("pageError".equals(event)) {
|
||||
SerializedError error = gson().fromJson(params.getAsJsonObject("error"), SerializedError.class);
|
||||
String errorStr = "";
|
||||
if (error.error != null) {
|
||||
errorStr = error.error.name + ": " + error.error.message;
|
||||
if (error.error.stack != null && !error.error.stack.isEmpty()) {
|
||||
errorStr += "\n" + error.error.stack;
|
||||
}
|
||||
}
|
||||
PageImpl page;
|
||||
try {
|
||||
page = connection.getExistingObject(params.getAsJsonObject("page").get("guid").getAsString());
|
||||
} catch (PlaywrightException e) {
|
||||
page = null;
|
||||
}
|
||||
listeners.notify(BrowserContextImpl.EventType.WEBERROR, new WebErrorImpl(page, errorStr));
|
||||
if (page != null) {
|
||||
page.listeners.notify(PageImpl.EventType.PAGEERROR, errorStr);
|
||||
}
|
||||
} else if ("close".equals(event)) {
|
||||
didClose();
|
||||
}
|
||||
}
|
||||
|
||||
void didClose() {
|
||||
isClosedOrClosing = true;
|
||||
if (browser != null) {
|
||||
browser.contexts.remove(this);
|
||||
}
|
||||
listeners.notify(EventType.CLOSE, this);
|
||||
}
|
||||
|
||||
WritableStream createTempFile(String name, long lastModifiedMs) {
|
||||
WritableStream createTempFile(String name) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("name", name);
|
||||
params.addProperty("lastModifiedMs", lastModifiedMs);
|
||||
JsonObject json = sendMessage("createTempFile", params).getAsJsonObject();
|
||||
return connection.getExistingObject(json.getAsJsonObject("writableStream").get("guid").getAsString());
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.microsoft.playwright.impl.Serialization.addHarUrlFilter;
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
@@ -37,12 +38,10 @@ 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;
|
||||
BrowserType.LaunchOptions launchOptions;
|
||||
private Path tracePath;
|
||||
String closeReason;
|
||||
|
||||
enum EventType {
|
||||
DISCONNECTED,
|
||||
@@ -68,15 +67,11 @@ class BrowserImpl extends ChannelOwner implements Browser {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(CloseOptions options) {
|
||||
withLogging("Browser.close", () -> closeImpl(options));
|
||||
public void close() {
|
||||
withLogging("Browser.close", () -> closeImpl());
|
||||
}
|
||||
|
||||
private void closeImpl(CloseOptions options) {
|
||||
if (options == null) {
|
||||
options = new CloseOptions();
|
||||
}
|
||||
closeReason = options.reason;
|
||||
private void closeImpl() {
|
||||
if (isConnectedOverWebSocket) {
|
||||
try {
|
||||
connection.close();
|
||||
@@ -188,7 +183,7 @@ class BrowserImpl extends ChannelOwner implements Browser {
|
||||
}
|
||||
if (options.recordVideoDir != null) {
|
||||
JsonObject recordVideo = new JsonObject();
|
||||
recordVideo.addProperty("dir", options.recordVideoDir.toAbsolutePath().toString());
|
||||
recordVideo.addProperty("dir", options.recordVideoDir.toString());
|
||||
if (options.recordVideoSize != null) {
|
||||
recordVideo.add("size", gson().toJsonTree(options.recordVideoSize));
|
||||
}
|
||||
@@ -208,10 +203,6 @@ class BrowserImpl extends ChannelOwner implements Browser {
|
||||
params.addProperty("noDefaultViewport", true);
|
||||
}
|
||||
}
|
||||
params.remove("acceptDownloads");
|
||||
if (options.acceptDownloads != null) {
|
||||
params.addProperty("acceptDownloads", options.acceptDownloads ? "accept" : "deny");
|
||||
}
|
||||
JsonElement result = sendMessage("newContext", params);
|
||||
BrowserContextImpl context = connection.getExistingObject(result.getAsJsonObject().getAsJsonObject("context").get("guid").getAsString());
|
||||
context.videosDir = options.recordVideoDir;
|
||||
@@ -219,9 +210,6 @@ class BrowserImpl extends ChannelOwner implements Browser {
|
||||
context.setBaseUrl(options.baseURL);
|
||||
}
|
||||
context.setRecordHar(recordHarPath, harContentPolicy);
|
||||
if (launchOptions != null) {
|
||||
context.tracing().setTracesDir(launchOptions.tracesDir);
|
||||
}
|
||||
contexts.add(context);
|
||||
return context;
|
||||
}
|
||||
@@ -240,7 +228,6 @@ class BrowserImpl extends ChannelOwner implements Browser {
|
||||
if (options == null) {
|
||||
options = new StartTracingOptions();
|
||||
}
|
||||
tracePath = options.path;
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
if (page != null) {
|
||||
params.add("page", ((PageImpl) page).toProtocolRef());
|
||||
@@ -255,20 +242,7 @@ class BrowserImpl extends ChannelOwner implements Browser {
|
||||
|
||||
private byte[] stopTracingImpl() {
|
||||
JsonObject json = sendMessage("stopTracing").getAsJsonObject();
|
||||
ArtifactImpl artifact = connection.getExistingObject(json.getAsJsonObject().getAsJsonObject("artifact").get("guid").getAsString());
|
||||
byte[] data = artifact.readAllBytes();
|
||||
artifact.delete();
|
||||
if (tracePath != null) {
|
||||
try {
|
||||
Files.createDirectories(tracePath.getParent());
|
||||
Files.write(tracePath, data);
|
||||
} catch (IOException e) {
|
||||
throw new PlaywrightException("Failed to write trace file", e);
|
||||
} finally {
|
||||
tracePath = null;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
return Base64.getDecoder().decode(json.get("binary").getAsString());
|
||||
}
|
||||
|
||||
private Page newPageImpl(NewPageOptions options) {
|
||||
@@ -299,13 +273,6 @@ class BrowserImpl extends ChannelOwner implements Browser {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CDPSession newBrowserCDPSession() {
|
||||
JsonObject params = new JsonObject();
|
||||
JsonObject result = sendMessage("newBrowserCDPSession", params).getAsJsonObject();
|
||||
return connection.getExistingObject(result.getAsJsonObject("session").get("guid").getAsString());
|
||||
}
|
||||
|
||||
private void didClose() {
|
||||
isConnected = false;
|
||||
listeners.notify(EventType.DISCONNECTED, this);
|
||||
|
||||
@@ -33,6 +33,8 @@ import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
import static com.microsoft.playwright.impl.Utils.convertType;
|
||||
|
||||
class BrowserTypeImpl extends ChannelOwner implements BrowserType {
|
||||
LocalUtils localUtils;
|
||||
|
||||
BrowserTypeImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
}
|
||||
@@ -50,7 +52,6 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
|
||||
JsonElement result = sendMessage("launch", params);
|
||||
BrowserImpl browser = connection.getExistingObject(result.getAsJsonObject().getAsJsonObject("browser").get("guid").getAsString());
|
||||
browser.browserType = this;
|
||||
browser.launchOptions = options;
|
||||
return browser;
|
||||
}
|
||||
|
||||
@@ -82,9 +83,9 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
|
||||
headers.addProperty("x-playwright-browser", name());
|
||||
}
|
||||
|
||||
JsonObject json = connection.localUtils().sendMessage("connect", params).getAsJsonObject();
|
||||
JsonObject json = sendMessage("connect", params).getAsJsonObject();
|
||||
JsonPipe pipe = connection.getExistingObject(json.getAsJsonObject("pipe").get("guid").getAsString());
|
||||
Connection connection = new Connection(pipe, this.connection.env, this.connection.localUtils);
|
||||
Connection connection = new Connection(pipe, this.connection.env);
|
||||
PlaywrightImpl playwright = connection.initializePlaywright();
|
||||
if (!playwright.initializer.has("preLaunchedBrowser")) {
|
||||
try {
|
||||
@@ -96,6 +97,7 @@ 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();
|
||||
@@ -130,6 +132,7 @@ 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();
|
||||
@@ -201,7 +204,7 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
|
||||
}
|
||||
if (options.recordVideoDir != null) {
|
||||
JsonObject recordVideo = new JsonObject();
|
||||
recordVideo.addProperty("dir", options.recordVideoDir.toAbsolutePath().toString());
|
||||
recordVideo.addProperty("dir", options.recordVideoDir.toString());
|
||||
if (options.recordVideoSize != null) {
|
||||
recordVideo.add("size", gson().toJsonTree(options.recordVideoSize));
|
||||
}
|
||||
@@ -221,10 +224,6 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
|
||||
params.addProperty("noDefaultViewport", true);
|
||||
}
|
||||
}
|
||||
params.remove("acceptDownloads");
|
||||
if (options.acceptDownloads != null) {
|
||||
params.addProperty("acceptDownloads", options.acceptDownloads ? "accept" : "deny");
|
||||
}
|
||||
JsonObject json = sendMessage("launchPersistentContext", params).getAsJsonObject();
|
||||
BrowserContextImpl context = connection.getExistingObject(json.getAsJsonObject("context").get("guid").getAsString());
|
||||
context.videosDir = options.recordVideoDir;
|
||||
@@ -232,7 +231,6 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
|
||||
context.setBaseUrl(options.baseURL);
|
||||
}
|
||||
context.setRecordHar(recordHarPath, harContentPolicy);
|
||||
context.tracing().setTracesDir(options.tracesDir);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.CDPSession;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class CDPSessionImpl extends ChannelOwner implements CDPSession {
|
||||
private final ListenerCollection<String> listeners = new ListenerCollection<>(new HashMap<>(), this);
|
||||
|
||||
protected CDPSessionImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
}
|
||||
|
||||
@Override
|
||||
void handleEvent(String event, JsonObject parameters) {
|
||||
super.handleEvent(event, parameters);
|
||||
if ("event".equals(event)) {
|
||||
String method = parameters.get("method").getAsString();
|
||||
JsonObject params = parameters.get("params").getAsJsonObject();
|
||||
listeners.notify(method, params);
|
||||
}
|
||||
}
|
||||
|
||||
public JsonObject send(String method) {
|
||||
return send(method, null);
|
||||
}
|
||||
|
||||
public JsonObject send(String method, JsonObject params) {
|
||||
JsonObject args = new JsonObject();
|
||||
if (params != null) {
|
||||
args.add("params", params);
|
||||
}
|
||||
args.addProperty("method", method);
|
||||
JsonElement response = connection.sendMessage(guid, "send", args);
|
||||
if (response == null) return null;
|
||||
else return response.getAsJsonObject().get("result").getAsJsonObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void on(String event, Consumer<JsonObject> handler) {
|
||||
listeners.add(event, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void off(String event, Consumer<JsonObject> handler) {
|
||||
listeners.remove(event, handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detach() {
|
||||
sendMessage("detach");
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,11 @@ package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -34,7 +34,6 @@ class ChannelOwner extends LoggingSupport {
|
||||
final String type;
|
||||
final String guid;
|
||||
final JsonObject initializer;
|
||||
private boolean wasCollected;
|
||||
|
||||
protected ChannelOwner(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
this(parent.connection, parent, type, guid, initializer);
|
||||
@@ -58,16 +57,15 @@ class ChannelOwner extends LoggingSupport {
|
||||
}
|
||||
}
|
||||
|
||||
void disposeChannelOwner(boolean wasGarbageCollected) {
|
||||
void disconnect() {
|
||||
// Clean up from parent and connection.
|
||||
if (parent != null) {
|
||||
parent.objects.remove(guid);
|
||||
}
|
||||
connection.unregisterObject(guid);
|
||||
wasCollected = wasGarbageCollected;
|
||||
// Dispose all children.
|
||||
for (ChannelOwner child : new ArrayList<>(objects.values())) {
|
||||
child.disposeChannelOwner(wasGarbageCollected);
|
||||
child.disconnect();
|
||||
}
|
||||
objects.clear();
|
||||
}
|
||||
@@ -93,7 +91,6 @@ class ChannelOwner extends LoggingSupport {
|
||||
}
|
||||
|
||||
WaitableResult<JsonElement> sendMessageAsync(String method, JsonObject params) {
|
||||
checkNotCollected();
|
||||
return connection.sendMessageAsync(guid, method, params);
|
||||
}
|
||||
|
||||
@@ -102,15 +99,9 @@ class ChannelOwner extends LoggingSupport {
|
||||
}
|
||||
|
||||
JsonElement sendMessage(String method, JsonObject params) {
|
||||
checkNotCollected();
|
||||
return connection.sendMessage(guid, method, params);
|
||||
}
|
||||
|
||||
private void checkNotCollected() {
|
||||
if (wasCollected)
|
||||
throw new PlaywrightException("The object has been collected to prevent unbounded heap growth.");
|
||||
}
|
||||
|
||||
<T> T runUntil(Runnable code, Waitable<T> waitable) {
|
||||
try {
|
||||
code.run();
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.Playwright;
|
||||
@@ -25,13 +24,10 @@ import com.microsoft.playwright.TimeoutError;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
import static java.lang.System.currentTimeMillis;
|
||||
|
||||
class Message {
|
||||
int id;
|
||||
@@ -40,7 +36,6 @@ class Message {
|
||||
JsonObject params;
|
||||
JsonElement result;
|
||||
SerializedError error;
|
||||
JsonArray log;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
@@ -60,7 +55,6 @@ 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<>();
|
||||
@@ -72,7 +66,6 @@ public class Connection {
|
||||
}
|
||||
LocalUtils localUtils;
|
||||
final Map<String, String> env;
|
||||
private int tracingCount;
|
||||
|
||||
class Root extends ChannelOwner {
|
||||
Root(Connection connection) {
|
||||
@@ -87,18 +80,8 @@ 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);
|
||||
}
|
||||
@@ -107,12 +90,8 @@ public class Connection {
|
||||
stackTraceCollector = StackTraceCollector.createFromEnv(env);
|
||||
}
|
||||
|
||||
void setIsTracing(boolean tracing) {
|
||||
if (tracing) {
|
||||
++tracingCount;
|
||||
} else {
|
||||
--tracingCount;
|
||||
}
|
||||
boolean isCollectingStacks() {
|
||||
return stackTraceCollector != null;
|
||||
}
|
||||
|
||||
String setApiName(String name) {
|
||||
@@ -130,10 +109,10 @@ public class Connection {
|
||||
}
|
||||
|
||||
public WaitableResult<JsonElement> sendMessageAsync(String guid, String method, JsonObject params) {
|
||||
return internalSendMessage(guid, method, params, true);
|
||||
return internalSendMessage(guid, method, params);
|
||||
}
|
||||
|
||||
private WaitableResult<JsonElement> internalSendMessage(String guid, String method, JsonObject params, boolean sendStack) {
|
||||
private WaitableResult<JsonElement> internalSendMessage(String guid, String method, JsonObject params) {
|
||||
int id = ++lastId;
|
||||
WaitableResult<JsonElement> result = new WaitableResult<>();
|
||||
callbacks.put(id, result);
|
||||
@@ -143,8 +122,6 @@ public class Connection {
|
||||
message.addProperty("method", method);
|
||||
message.add("params", params);
|
||||
JsonObject metadata = new JsonObject();
|
||||
metadata.addProperty("wallTime", currentTimeMillis());
|
||||
JsonArray stack = null;
|
||||
if (apiName == null) {
|
||||
metadata.addProperty("internal", true);
|
||||
} else {
|
||||
@@ -152,27 +129,11 @@ public class Connection {
|
||||
// All but first message in an API call are considered internal and will be hidden from the inspector.
|
||||
apiName = null;
|
||||
if (stackTraceCollector != null) {
|
||||
stack = stackTraceCollector.currentStackTrace();
|
||||
if (!stack.isEmpty()) {
|
||||
JsonObject location = new JsonObject();
|
||||
JsonObject frame = stack.get(0).getAsJsonObject();
|
||||
location.addProperty("file", frame.get("file").getAsString());
|
||||
location.addProperty("line", frame.get("line").getAsInt());
|
||||
location.addProperty("column", frame.get("column").getAsInt());
|
||||
metadata.add("location", location);
|
||||
}
|
||||
metadata.add("stack", stackTraceCollector.currentStackTrace());
|
||||
}
|
||||
}
|
||||
message.add("metadata", metadata);
|
||||
transport.send(message);
|
||||
if (sendStack && tracingCount > 0 && stack != null && !method.startsWith("LocalUtils")) {
|
||||
JsonObject callData = new JsonObject();
|
||||
callData.addProperty("id", id);
|
||||
callData.add("stack", stack);
|
||||
JsonObject stackParams = new JsonObject();
|
||||
stackParams.add("callData", callData);
|
||||
internalSendMessage(localUtils.guid,"addStackToTracingNoReply", stackParams, false);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -209,30 +170,6 @@ public class Connection {
|
||||
dispatch(messageObj);
|
||||
}
|
||||
|
||||
private static String formatCallLog(JsonArray log) {
|
||||
if (log == null) {
|
||||
return "";
|
||||
}
|
||||
boolean allEmpty = true;
|
||||
for (JsonElement e: log) {
|
||||
if (!e.getAsString().isEmpty()) {
|
||||
allEmpty = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allEmpty) {
|
||||
return "";
|
||||
}
|
||||
List<String> lines = new ArrayList<>();
|
||||
lines.add("");
|
||||
lines.add("Call log:");
|
||||
for (JsonElement e: log) {
|
||||
lines.add("- " + e.getAsString());
|
||||
}
|
||||
lines.add("");
|
||||
return String.join("\n", lines);
|
||||
}
|
||||
|
||||
private void dispatch(Message message) {
|
||||
// System.out.println("Message: " + message.method + " " + message.id);
|
||||
if (message.id != 0) {
|
||||
@@ -245,18 +182,12 @@ public class Connection {
|
||||
if (message.error == null) {
|
||||
callback.complete(message.result);
|
||||
} else {
|
||||
String callLog = formatCallLog(message.log);
|
||||
if (message.error.error == null) {
|
||||
callback.completeExceptionally(new PlaywrightException(message.error + callLog));
|
||||
} else if ("Expect".equals(message.error.error.name)) {
|
||||
callback.complete(message.result);
|
||||
callback.completeExceptionally(new PlaywrightException(message.error.toString()));
|
||||
} else if ("TimeoutError".equals(message.error.error.name)) {
|
||||
callback.completeExceptionally(new TimeoutError(message.error.error + callLog));
|
||||
} else if ("TargetClosedError".equals(message.error.error.name)) {
|
||||
callback.completeExceptionally(new TargetClosedError(message.error.error + callLog));
|
||||
|
||||
callback.completeExceptionally(new TimeoutError(message.error.error.toString()));
|
||||
} else {
|
||||
callback.completeExceptionally(new DriverException(message.error.error + callLog));
|
||||
callback.completeExceptionally(new DriverException(message.error.error));
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -285,8 +216,7 @@ public class Connection {
|
||||
return;
|
||||
}
|
||||
if (message.method.equals("__dispose__")) {
|
||||
boolean wasCollected = message.params.has("reason") && "gc".equals(message.params.get("reason").getAsString());
|
||||
object.disposeChannelOwner(wasCollected);
|
||||
object.disconnect();
|
||||
return;
|
||||
}
|
||||
object.handleEvent(message.method, message.params);
|
||||
@@ -327,6 +257,9 @@ public class Connection {
|
||||
case "BrowserContext":
|
||||
result = new BrowserContextImpl(parent, type, guid, initializer);
|
||||
break;
|
||||
case "ConsoleMessage":
|
||||
result = new ConsoleMessageImpl(parent, type, guid, initializer);
|
||||
break;
|
||||
case "Dialog":
|
||||
result = new DialogImpl(parent, type, guid, initializer);
|
||||
break;
|
||||
@@ -350,10 +283,8 @@ public class Connection {
|
||||
result = new JsonPipe(parent, type, guid, initializer);
|
||||
break;
|
||||
case "LocalUtils":
|
||||
result = new LocalUtils(parent, type, guid, initializer);
|
||||
if (localUtils == null) {
|
||||
localUtils = (LocalUtils) result;
|
||||
}
|
||||
localUtils = new LocalUtils(parent, type, guid, initializer);
|
||||
result = localUtils;
|
||||
break;
|
||||
case "Page":
|
||||
result = new PageImpl(parent, type, guid, initializer);
|
||||
@@ -376,8 +307,6 @@ 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;
|
||||
@@ -390,9 +319,6 @@ public class Connection {
|
||||
case "WritableStream":
|
||||
result = new WritableStream(parent, type, guid, initializer);
|
||||
break;
|
||||
case "CDPSession":
|
||||
result = new CDPSessionImpl(parent, type, guid, initializer);
|
||||
break;
|
||||
default:
|
||||
throw new PlaywrightException("Unknown type " + type);
|
||||
}
|
||||
|
||||
@@ -20,27 +20,15 @@ import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.ConsoleMessage;
|
||||
import com.microsoft.playwright.JSHandle;
|
||||
import com.microsoft.playwright.Page;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
|
||||
public class ConsoleMessageImpl implements ConsoleMessage {
|
||||
private final Connection connection;
|
||||
private PageImpl page;
|
||||
private final JsonObject initializer;
|
||||
|
||||
public ConsoleMessageImpl(Connection connection, JsonObject initializer) {
|
||||
this.connection = connection;
|
||||
// Note: currently, we only report console messages for pages and they always have a page.
|
||||
// However, in the future we might report console messages for service workers or something else,
|
||||
// where page() would be null.
|
||||
if (initializer.has("page")) {
|
||||
page = connection.getExistingObject(initializer.getAsJsonObject("page").get("guid").getAsString());
|
||||
}
|
||||
this.initializer = initializer;
|
||||
public class ConsoleMessageImpl extends ChannelOwner implements ConsoleMessage {
|
||||
public ConsoleMessageImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
}
|
||||
|
||||
public String type() {
|
||||
@@ -67,9 +55,4 @@ public class ConsoleMessageImpl implements ConsoleMessage {
|
||||
location.get("lineNumber").getAsNumber() + ":" +
|
||||
location.get("columnNumber").getAsNumber();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageImpl page() {
|
||||
return page;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,18 +18,10 @@ package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.Dialog;
|
||||
import com.microsoft.playwright.Page;
|
||||
|
||||
class DialogImpl extends ChannelOwner implements Dialog {
|
||||
private PageImpl page;
|
||||
|
||||
DialogImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
// Note: dialogs that open early during page initialization block it.
|
||||
// Therefore, we must report the dialog without a page to be able to handle it.
|
||||
if (initializer.has("page")) {
|
||||
page = connection.getExistingObject(initializer.getAsJsonObject("page").get("guid").getAsString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -58,11 +50,6 @@ class DialogImpl extends ChannelOwner implements Dialog {
|
||||
return initializer.get("message").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageImpl page() {
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return initializer.get("type").getAsString();
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
class DriverException extends PlaywrightException {
|
||||
DriverException(String error) {
|
||||
super(error);
|
||||
DriverException(SerializedError.Error error) {
|
||||
super(error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,12 +28,13 @@ import com.microsoft.playwright.options.SelectOption;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
|
||||
import static com.microsoft.playwright.impl.Serialization.*;
|
||||
import static com.microsoft.playwright.impl.Utils.*;
|
||||
import static com.microsoft.playwright.impl.Utils.addFilePathUploadParams;
|
||||
import static com.microsoft.playwright.impl.Utils.addLargeFileUploadParams;
|
||||
import static com.microsoft.playwright.options.ScreenshotType.JPEG;
|
||||
import static com.microsoft.playwright.options.ScreenshotType.PNG;
|
||||
|
||||
@@ -374,14 +375,11 @@ public class ElementHandleImpl extends JSHandleImpl implements ElementHandle {
|
||||
|
||||
@Override
|
||||
public List<String> selectOption(String[] values, SelectOptionOptions options) {
|
||||
if (options == null) {
|
||||
options = new SelectOptionOptions();
|
||||
if (values == null) {
|
||||
return selectOption(new SelectOption[0], options);
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
if (values != null) {
|
||||
params.add("options", toSelectValueOrLabel(values));
|
||||
}
|
||||
return selectOption(params);
|
||||
return selectOption(Arrays.asList(values).stream().map(
|
||||
v -> new SelectOption().setValue(v)).toArray(SelectOption[]::new), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -466,12 +464,16 @@ public class ElementHandleImpl extends JSHandleImpl implements ElementHandle {
|
||||
if (frame == null) {
|
||||
throw new Error("Cannot set input files to detached element");
|
||||
}
|
||||
if (options == null) {
|
||||
options = new SetInputFilesOptions();
|
||||
if (hasLargeFile(files)) {
|
||||
if (options == null) {
|
||||
options = new SetInputFilesOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
addLargeFileUploadParams(files, params, frame.page().context());
|
||||
sendMessage("setInputFilePaths", params);
|
||||
} else {
|
||||
setInputFilesImpl(Utils.toFilePayloads(files), options);
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
addFilePathUploadParams(files, params, frame.page().context());
|
||||
sendMessage("setInputFiles", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -490,7 +492,7 @@ public class ElementHandleImpl extends JSHandleImpl implements ElementHandle {
|
||||
options = new SetInputFilesOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.add("payloads", Serialization.toJsonArray(files));
|
||||
params.add("files", Serialization.toJsonArray(files));
|
||||
sendMessage("setInputFiles", params);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ 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.*;
|
||||
@@ -110,7 +109,11 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
@Override
|
||||
public List<String> selectOption(String selector, String[] values, SelectOptionOptions options) {
|
||||
return withLogging("Frame.selectOption", () -> selectOptionImpl(selector, values, 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -370,71 +373,6 @@ 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();
|
||||
@@ -689,18 +627,6 @@ 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));
|
||||
@@ -761,13 +687,17 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
|
||||
void setInputFilesImpl(String selector, Path[] files, SetInputFilesOptions options) {
|
||||
if (options == null) {
|
||||
options = new SetInputFilesOptions();
|
||||
if (hasLargeFile(files)) {
|
||||
if (options == null) {
|
||||
options = new SetInputFilesOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
addLargeFileUploadParams(files, params, page.context());
|
||||
params.addProperty("selector", selector);
|
||||
sendMessage("setInputFilePaths", params);
|
||||
} else {
|
||||
setInputFilesImpl(selector, Utils.toFilePayloads(files), options);
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
addFilePathUploadParams(files, params, page.context());
|
||||
params.addProperty("selector", selector);
|
||||
sendMessage("setInputFiles", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -787,7 +717,7 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("selector", selector);
|
||||
params.add("payloads", toJsonArray(files));
|
||||
params.add("files", toJsonArray(files));
|
||||
sendMessage("setInputFiles", params);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,7 @@ package com.microsoft.playwright.impl;
|
||||
|
||||
import com.microsoft.playwright.FrameLocator;
|
||||
import com.microsoft.playwright.Locator;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
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 {
|
||||
@@ -42,72 +37,7 @@ class FrameLocatorImpl implements FrameLocator {
|
||||
|
||||
@Override
|
||||
public FrameLocatorImpl frameLocator(String 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)));
|
||||
return new FrameLocatorImpl(frame, frameSelector + " >> control=enter-frame >> " + selector);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -117,16 +47,7 @@ class FrameLocatorImpl implements FrameLocator {
|
||||
|
||||
@Override
|
||||
public Locator locator(String selector, LocatorOptions options) {
|
||||
return new LocatorImpl(frame, frameSelector + " >> internal:control=enter-frame >> " + selector, convertType(options, Locator.LocatorOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator locator(Locator selectorOrLocator, LocatorOptions options) {
|
||||
LocatorImpl other = (LocatorImpl) selectorOrLocator;
|
||||
if (other.frame != frame) {
|
||||
throw new PlaywrightException("Locators must belong to the same frame.");
|
||||
}
|
||||
return locator(other.selector, options);
|
||||
return new LocatorImpl(frame, frameSelector + " >> control=enter-frame >> " + selector, convertType(options, Locator.LocatorOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,23 +16,14 @@
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
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);
|
||||
@@ -50,7 +41,6 @@ class ListenerCollection <EventType> {
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
listeners.put(type, list);
|
||||
updateSubscription(type, true);
|
||||
}
|
||||
list.add(listener);
|
||||
}
|
||||
@@ -62,7 +52,6 @@ class ListenerCollection <EventType> {
|
||||
}
|
||||
list.removeAll(Collections.singleton(listener));
|
||||
if (list.isEmpty()) {
|
||||
updateSubscription(type, false);
|
||||
listeners.remove(type);
|
||||
}
|
||||
}
|
||||
@@ -70,18 +59,4 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,38 +20,16 @@ import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
|
||||
class LocalUtils extends ChannelOwner {
|
||||
LocalUtils(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
}
|
||||
|
||||
void zip(Path zipFile, JsonArray entries, String stacksId, boolean appendMode, boolean includeSources) {
|
||||
void zip(Path zipFile, JsonArray entries) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("zipFile", zipFile.toString());
|
||||
params.add("entries", entries);
|
||||
params.addProperty("mode", appendMode ? "append" : "write");
|
||||
params.addProperty("stacksId", stacksId);
|
||||
params.addProperty("includeSources", includeSources);
|
||||
sendMessage("zip", params);
|
||||
}
|
||||
|
||||
void traceDiscarded(String stacksId) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("stacksId", stacksId);
|
||||
sendMessage("traceDiscarded", params);
|
||||
}
|
||||
|
||||
String tracingStarted(String tracesDir, String traceName) {
|
||||
JsonObject params = new JsonObject();
|
||||
if (tracesDir != null) {
|
||||
params.addProperty("tracesDir", "");
|
||||
}
|
||||
params.addProperty("traceName", traceName);
|
||||
JsonObject json = connection.localUtils().sendMessage("tracingStarted", params).getAsJsonObject();
|
||||
return json.get("stacksId").getAsString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,14 +86,12 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
public void hasAttribute(String name, String text, HasAttributeOptions options) {
|
||||
ExpectedTextValue expected = new ExpectedTextValue();
|
||||
expected.string = text;
|
||||
expected.ignoreCase = shouldIgnoreCase(options);
|
||||
hasAttribute(name, expected, text, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasAttribute(String name, Pattern pattern, HasAttributeOptions options) {
|
||||
ExpectedTextValue expected = expectedRegex(pattern);
|
||||
expected.ignoreCase = shouldIgnoreCase(options);
|
||||
hasAttribute(name, expected, pattern, options);
|
||||
}
|
||||
|
||||
@@ -107,7 +105,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
if (expectedValue instanceof Pattern) {
|
||||
message += " matching regex";
|
||||
}
|
||||
expectImpl("to.have.attribute.value", expectedText, expectedValue, message, commonOptions);
|
||||
expectImpl("to.have.attribute", expectedText, expectedValue, message, commonOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -150,7 +148,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
options = new HasCountOptions();
|
||||
}
|
||||
FrameExpectOptions commonOptions = convertType(options, FrameExpectOptions.class);
|
||||
commonOptions.expectedNumber = (double) count;
|
||||
commonOptions.expectedNumber = count;
|
||||
List<ExpectedTextValue> expectedText = null;
|
||||
expectImpl("to.have.count", expectedText, count, "Locator expected to have count", commonOptions);
|
||||
}
|
||||
@@ -290,10 +288,8 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
|
||||
@Override
|
||||
public void isChecked(IsCheckedOptions options) {
|
||||
boolean unchecked = options != null && options.checked != null && !options.checked;
|
||||
String expression = unchecked ? "to.be.unchecked" : "to.be.checked";
|
||||
String message = "Locator expected to be " + (unchecked ? "un" : "") + "checked";
|
||||
expectTrue(expression, message, convertType(options, FrameExpectOptions.class));
|
||||
String expression = (options != null && options.checked != null && !options.checked) ? "to.be.unchecked" : "to.be.checked";
|
||||
expectTrue(expression, "Locator expected to be checked", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -305,8 +301,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
public void isEditable(IsEditableOptions options) {
|
||||
FrameExpectOptions frameOptions = convertType(options, FrameExpectOptions.class);
|
||||
boolean editable = options == null || options.editable == null || options.editable == true;
|
||||
String message = "Locator expected to be " + (editable ? "editable" : "readonly");
|
||||
expectTrue(editable ? "to.be.editable" : "to.be.readonly", message, frameOptions);
|
||||
expectTrue(editable ? "to.be.editable" : "to.be.readonly", "Locator expected to be editable", frameOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -318,8 +313,7 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
public void isEnabled(IsEnabledOptions options) {
|
||||
FrameExpectOptions frameOptions = convertType(options, FrameExpectOptions.class);
|
||||
boolean enabled = options == null || options.enabled == null || options.enabled == true;
|
||||
String message = "Locator expected to be " + (enabled ? "enabled" : "disabled");
|
||||
expectTrue(enabled ? "to.be.enabled" : "to.be.disabled", message, frameOptions);
|
||||
expectTrue(enabled ? "to.be.enabled" : "to.be.disabled", "Locator expected to be enabled", frameOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -332,21 +326,11 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
expectTrue("to.be.hidden", "Locator expected to be hidden", convertType(options, FrameExpectOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isInViewport(IsInViewportOptions options) {
|
||||
FrameExpectOptions expectOptions = convertType(options, FrameExpectOptions.class);
|
||||
if (options != null && options.ratio != null) {
|
||||
expectOptions.expectedNumber = options.ratio;
|
||||
}
|
||||
expectTrue("to.be.in.viewport", "Locator expected to be in viewport", expectOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isVisible(IsVisibleOptions options) {
|
||||
FrameExpectOptions frameOptions = convertType(options, FrameExpectOptions.class);
|
||||
boolean visible = options == null || options.visible == null || options.visible == true;
|
||||
String message = "Locator expected to be " + (visible ? "visible" : "hidden");
|
||||
expectTrue(visible ? "to.be.visible" : "to.be.hidden", message, frameOptions);
|
||||
expectTrue(visible ? "to.be.visible" : "to.be.hidden", "Locator expected to be visible", frameOptions);
|
||||
}
|
||||
|
||||
private void expectTrue(String expression, String message, FrameExpectOptions options) {
|
||||
@@ -359,14 +343,6 @@ public class LocatorAssertionsImpl extends AssertionsBase implements LocatorAsse
|
||||
return new LocatorAssertionsImpl(actualLocator, !isNot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void isAttached(IsAttachedOptions options) {
|
||||
FrameExpectOptions frameOptions = convertType(options, FrameExpectOptions.class);
|
||||
boolean attached = options == null || options.attached == null || options.attached == true;
|
||||
String message = "Locator expected to be " + (attached ? "attached" : "detached");
|
||||
expectTrue(attached ? "to.be.attached" : "to.be.detached", message, frameOptions);
|
||||
}
|
||||
|
||||
private static Boolean shouldIgnoreCase(Object options) {
|
||||
if (options == null) {
|
||||
return null;
|
||||
|
||||
@@ -3,47 +3,78 @@ package com.microsoft.playwright.impl;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.*;
|
||||
import com.microsoft.playwright.options.*;
|
||||
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 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;
|
||||
|
||||
class LocatorImpl implements Locator {
|
||||
final FrameImpl frame;
|
||||
final String selector;
|
||||
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) {
|
||||
selector += " >> internal:has-text=" + escapeForTextSelector(options.hasText, false);
|
||||
}
|
||||
if (options.hasNotText != null) {
|
||||
selector += " >> internal:has-not-text=" + escapeForTextSelector(options.hasNotText, 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);
|
||||
}
|
||||
if (options.hasNot != null) {
|
||||
LocatorImpl locator = (LocatorImpl) options.hasNot;
|
||||
if (locator.frame != frame)
|
||||
throw new Error("Inner 'hasNot' locator must belong to the same frame.");
|
||||
selector += " >> internal:has-not=" + gson().toJson(locator.selector);
|
||||
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 = filters.addFiltersToSelector(selector, options, frame);
|
||||
}
|
||||
this.selector = selector;
|
||||
}
|
||||
@@ -71,16 +102,6 @@ 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)");
|
||||
@@ -91,29 +112,6 @@ class LocatorImpl implements Locator {
|
||||
return (List<String>) frame.evalOnSelectorAll(selector, "ee => ee.map(e => e.textContent || '')");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator and(Locator locator) {
|
||||
LocatorImpl other = (LocatorImpl) locator;
|
||||
if (other.frame != frame)
|
||||
throw new Error("Locators must belong to the same frame.");
|
||||
return new LocatorImpl(frame, selector + " >> internal:and=" + gson().toJson(other.selector), null);
|
||||
}
|
||||
|
||||
@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);
|
||||
@@ -127,11 +125,6 @@ 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) {
|
||||
@@ -241,71 +234,6 @@ 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);
|
||||
@@ -401,28 +329,11 @@ class LocatorImpl implements Locator {
|
||||
return new LocatorImpl(frame, this.selector + " >> " + selector, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator locator(Locator selectorOrLocator, LocatorOptions options) {
|
||||
LocatorImpl other = (LocatorImpl) selectorOrLocator;
|
||||
if (other.frame != frame) {
|
||||
throw new PlaywrightException("Locators must belong to the same frame.");
|
||||
}
|
||||
return new LocatorImpl(frame, this.selector + " >> internal:chain=" + gson().toJson(other.selector), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator nth(int index) {
|
||||
return new LocatorImpl(frame, selector + " >> nth=" + index, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locator or(Locator locator) {
|
||||
LocatorImpl other = (LocatorImpl) locator;
|
||||
if (other.frame != frame)
|
||||
throw new Error("Locators must belong to the same frame.");
|
||||
return new LocatorImpl(frame, selector + " >> internal:or=" + gson().toJson(other.selector), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page page() {
|
||||
return frame.page();
|
||||
@@ -436,11 +347,6 @@ class LocatorImpl implements Locator {
|
||||
frame.press(selector, key, convertType(options, Frame.PressOptions.class).setStrict(true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pressSequentially(String text, PressSequentiallyOptions options) {
|
||||
type(text, convertType(options, TypeOptions.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] screenshot(ScreenshotOptions options) {
|
||||
return withElement((h, o) -> h.screenshot(o), convertType(options, ElementHandle.ScreenshotOptions.class));
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
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.Serialization.gson;
|
||||
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) {
|
||||
return "internal:attr=[" + attrName + "=" + escapeForAttributeSelector(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 = escapeForAttributeSelector(options.name, options.exact != null && options.exact);
|
||||
addAttr(result, "name", name);
|
||||
}
|
||||
if (options.pressed != null)
|
||||
addAttr(result, "pressed", options.pressed.toString());
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private static String escapeRegexForSelector(Pattern re) {
|
||||
// Even number of backslashes followed by the quote -> insert a backslash.
|
||||
return toJsRegExp(re).replaceAll("(^|[^\\\\])(\\\\\\\\)*([\"'`])", "$1$2\\\\$3").replaceAll(">>", "\\\\>\\\\>");
|
||||
}
|
||||
|
||||
static String escapeForTextSelector(Object value, boolean exact) {
|
||||
if (value instanceof Pattern) {
|
||||
return escapeRegexForSelector((Pattern) value);
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return gson().toJson(value) + (exact ? "s" : "i");
|
||||
}
|
||||
throw new IllegalArgumentException("text parameter must be Pattern or String: " + value);
|
||||
}
|
||||
|
||||
private static String escapeForAttributeSelector(Object value, boolean exact) {
|
||||
if (value instanceof Pattern) {
|
||||
return escapeRegexForSelector((Pattern) value);
|
||||
}
|
||||
if (value instanceof String) {
|
||||
// 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 '"' + ((String) value).replaceAll("\\\\", "\\\\\\\\").replaceAll("\"", "\\\\\"") + '"' + (exact ? "" : "i");
|
||||
}
|
||||
throw new IllegalArgumentException("Attribute can be String or Pattern, found: " + value);
|
||||
}
|
||||
|
||||
private static String toJsRegExp(Pattern pattern) {
|
||||
return "/" + pattern.pattern() + "/" + toJsRegexFlags(pattern);
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.*;
|
||||
import com.microsoft.playwright.options.*;
|
||||
@@ -25,13 +24,13 @@ import com.microsoft.playwright.options.*;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Consumer;
|
||||
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.*;
|
||||
import static com.microsoft.playwright.impl.Utils.convertType;
|
||||
import static com.microsoft.playwright.impl.Utils.isSafeCloseError;
|
||||
import static com.microsoft.playwright.options.ScreenshotType.JPEG;
|
||||
import static com.microsoft.playwright.options.ScreenshotType.PNG;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
@@ -49,18 +48,23 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
private ViewportSize viewport;
|
||||
private final Router routes = new Router();
|
||||
private final Set<FrameImpl> frames = new LinkedHashSet<>();
|
||||
private static final Map<EventType, String> eventSubscriptions() {
|
||||
Map<EventType, String> result = new HashMap<>();
|
||||
result.put(EventType.CONSOLE, "console");
|
||||
result.put(EventType.DIALOG, "dialog");
|
||||
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 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();
|
||||
}
|
||||
}
|
||||
};
|
||||
final Map<String, BindingCallback> bindings = new HashMap<>();
|
||||
BrowserContextImpl ownedContext;
|
||||
private boolean isClosed;
|
||||
@@ -68,7 +72,6 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
private final TimeoutSettings timeoutSettings;
|
||||
private VideoImpl video;
|
||||
private final PageImpl opener;
|
||||
private String closeReason;
|
||||
|
||||
enum EventType {
|
||||
CLOSE,
|
||||
@@ -116,7 +119,22 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
protected void handleEvent(String event, JsonObject params) {
|
||||
if ("worker".equals(event)) {
|
||||
if ("dialog".equals(event)) {
|
||||
String guid = params.getAsJsonObject("dialog").get("guid").getAsString();
|
||||
DialogImpl dialog = connection.getExistingObject(guid);
|
||||
if (listeners.hasListeners(EventType.DIALOG)) {
|
||||
listeners.notify(EventType.DIALOG, dialog);
|
||||
} else {
|
||||
if ("beforeunload".equals(dialog.type())) {
|
||||
try {
|
||||
dialog.accept();
|
||||
} catch (PlaywrightException e) {
|
||||
}
|
||||
} else {
|
||||
dialog.dismiss();
|
||||
}
|
||||
}
|
||||
} else if ("worker".equals(event)) {
|
||||
String guid = params.getAsJsonObject("worker").get("guid").getAsString();
|
||||
WorkerImpl worker = connection.getExistingObject(guid);
|
||||
worker.page = this;
|
||||
@@ -126,9 +144,14 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
String guid = params.getAsJsonObject("webSocket").get("guid").getAsString();
|
||||
WebSocketImpl webSocket = connection.getExistingObject(guid);
|
||||
listeners.notify(EventType.WEBSOCKET, webSocket);
|
||||
} else if ("console".equals(event)) {
|
||||
String guid = params.getAsJsonObject("message").get("guid").getAsString();
|
||||
ConsoleMessageImpl message = connection.getExistingObject(guid);
|
||||
listeners.notify(EventType.CONSOLE, message);
|
||||
} 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)) {
|
||||
@@ -172,18 +195,27 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
listeners.notify(EventType.FRAMEDETACHED, frame);
|
||||
} else if ("route".equals(event)) {
|
||||
RouteImpl route = connection.getExistingObject(params.getAsJsonObject("route").get("guid").getAsString());
|
||||
route.browserContext = browserContext;
|
||||
Router.HandleResult handled = routes.handle(route);
|
||||
if (handled != Router.HandleResult.NoMatchingHandler) {
|
||||
updateInterceptionPatterns();
|
||||
if (handled == Router.HandleResult.FoundMatchingHandler) {
|
||||
maybeDisableNetworkInterception();
|
||||
}
|
||||
if (handled == Router.HandleResult.NoMatchingHandler || handled == Router.HandleResult.Fallback) {
|
||||
if (!route.isHandled()) {
|
||||
browserContext.handleRoute(route);
|
||||
}
|
||||
} else if ("video".equals(event)) {
|
||||
String artifactGuid = params.getAsJsonObject("artifact").get("guid").getAsString();
|
||||
ArtifactImpl artifact = connection.getExistingObject(artifactGuid);
|
||||
forceVideo().setArtifact(artifact);
|
||||
} else if ("pageError".equals(event)) {
|
||||
SerializedError error = gson().fromJson(params.getAsJsonObject("error"), SerializedError.class);
|
||||
String errorStr = "";
|
||||
if (error.error != null) {
|
||||
errorStr = error.error.name + ": " + error.error.message;
|
||||
if (error.error.stack != null && !error.error.stack.isEmpty()) {
|
||||
errorStr += "\n" + error.error.stack;
|
||||
}
|
||||
}
|
||||
listeners.notify(EventType.PAGEERROR, errorStr);
|
||||
} else if ("crash".equals(event)) {
|
||||
listeners.notify(EventType.CRASH, this);
|
||||
} else if ("close".equals(event)) {
|
||||
@@ -201,11 +233,22 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
listeners.notify(EventType.CLOSE, this);
|
||||
}
|
||||
|
||||
private String effectiveCloseReason() {
|
||||
if (closeReason != null) {
|
||||
return closeReason;
|
||||
private void willAddFileChooserListener() {
|
||||
if (!listeners.hasListeners(EventType.FILECHOOSER)) {
|
||||
updateFileChooserInterception(true);
|
||||
}
|
||||
return browserContext.effectiveCloseReason();
|
||||
}
|
||||
|
||||
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
|
||||
@@ -493,22 +536,19 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public void close(CloseOptions options) {
|
||||
if (options == null) {
|
||||
options = new CloseOptions();
|
||||
if (isClosed) {
|
||||
return;
|
||||
}
|
||||
closeReason = options.reason;
|
||||
JsonObject params = options == null ? new JsonObject() : gson().toJsonTree(options).getAsJsonObject();
|
||||
try {
|
||||
if (ownedContext != null) {
|
||||
ownedContext.close();
|
||||
} else {
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
sendMessage("close", params);
|
||||
}
|
||||
sendMessage("close", params);
|
||||
} catch (PlaywrightException exception) {
|
||||
if (isSafeCloseError(exception) && (options.runBeforeUnload == null || !options.runBeforeUnload)) {
|
||||
return;
|
||||
if (!isSafeCloseError(exception)) {
|
||||
throw exception;
|
||||
}
|
||||
throw exception;
|
||||
}
|
||||
if (ownedContext != null) {
|
||||
ownedContext.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -721,82 +761,6 @@ 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));
|
||||
@@ -935,17 +899,8 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public void pause() {
|
||||
withLogging("Page.pause", () -> {
|
||||
Double defaultNavigationTimeout = browserContext.timeoutSettings.defaultNavigationTimeout();
|
||||
Double defaultTimeout = browserContext.timeoutSettings.defaultTimeout();
|
||||
browserContext.setDefaultNavigationTimeoutImpl(0.0);
|
||||
browserContext.setDefaultTimeoutImpl(0.0);
|
||||
try {
|
||||
runUntil(() -> {}, new WaitableRace<>(asList(context().pause(), (Waitable<JsonElement>) waitableClosedOrCrashed)));
|
||||
} finally {
|
||||
browserContext.setDefaultNavigationTimeoutImpl(defaultNavigationTimeout);
|
||||
browserContext.setDefaultTimeoutImpl(defaultTimeout);
|
||||
}
|
||||
withLogging("BrowserContext.pause", () -> {
|
||||
context().pause();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -955,6 +910,9 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
}
|
||||
|
||||
private byte[] pdfImpl(PdfOptions options) {
|
||||
if (!browserContext.browser().isChromium()) {
|
||||
throw new PlaywrightException("Page.pdf only supported in headless Chromium");
|
||||
}
|
||||
if (options == null) {
|
||||
options = new PdfOptions();
|
||||
}
|
||||
@@ -1029,7 +987,11 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
private void route(UrlMatcher matcher, Consumer<Route> handler, RouteOptions options) {
|
||||
withLogging("Page.route", () -> {
|
||||
routes.add(matcher, handler, options == null ? null : options.times);
|
||||
updateInterceptionPatterns();
|
||||
if (routes.size() == 1) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("enabled", true);
|
||||
sendMessage("setNetworkInterceptionEnabled", params);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1038,6 +1000,8 @@ 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 };
|
||||
@@ -1052,8 +1016,11 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public List<String> selectOption(String selector, String[] values, SelectOptionOptions options) {
|
||||
return withLogging("Page.selectOption",
|
||||
() -> mainFrame.selectOptionImpl(selector, values, convertType(options, Frame.SelectOptionOptions.class)));
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1226,14 +1193,6 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
() -> mainFrame.uncheckImpl(selector, convertType(options, Frame.UncheckOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unrouteAll() {
|
||||
withLogging("Page.unrouteAll", () -> {
|
||||
routes.removeAll();
|
||||
updateInterceptionPatterns();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unroute(String url, Consumer<Route> handler) {
|
||||
unroute(new UrlMatcher(browserContext.baseUrl, url), handler);
|
||||
@@ -1252,12 +1211,16 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
private void unroute(UrlMatcher matcher, Consumer<Route> handler) {
|
||||
withLogging("Page.unroute", () -> {
|
||||
routes.remove(matcher, handler);
|
||||
updateInterceptionPatterns();
|
||||
maybeDisableNetworkInterception();
|
||||
});
|
||||
}
|
||||
|
||||
private void updateInterceptionPatterns() {
|
||||
sendMessage("setNetworkInterceptionPatterns", routes.interceptionPatterns());
|
||||
private void maybeDisableNetworkInterception() {
|
||||
if (routes.size() == 0) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("enabled", false);
|
||||
sendMessage("setNetworkInterceptionEnabled", params);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1358,7 +1321,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
throw new TargetClosedError(effectiveCloseReason());
|
||||
throw new PlaywrightException("Page closed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1369,7 +1332,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
throw new TargetClosedError("Page crashed");
|
||||
throw new PlaywrightException("Page crashed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1457,15 +1420,6 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
() -> mainFrame.waitForSelectorImpl(selector, convertType(options, Frame.WaitForSelectorOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitForCondition(BooleanSupplier predicate, WaitForConditionOptions options) {
|
||||
List<Waitable<Void>> waitables = new ArrayList<>();
|
||||
waitables.add(createWaitForCloseHelper());
|
||||
waitables.add(createWaitableTimeout(options == null ? null : options.timeout));
|
||||
waitables.add(new WaitablePredicate<>(predicate));
|
||||
runUntil(() -> {}, new WaitableRace<>(waitables));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitForTimeout(double timeout) {
|
||||
withLogging("Page.waitForTimeout", () -> mainFrame.waitForTimeoutImpl(timeout));
|
||||
|
||||
@@ -63,6 +63,7 @@ public class PlaywrightImpl extends ChannelOwner implements Playwright {
|
||||
private final BrowserTypeImpl webkit;
|
||||
private final SelectorsImpl selectors;
|
||||
private final APIRequestImpl apiRequest;
|
||||
private final LocalUtils localUtils;
|
||||
private SharedSelectors sharedSelectors;
|
||||
|
||||
PlaywrightImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
@@ -73,6 +74,10 @@ public class PlaywrightImpl extends ChannelOwner implements Playwright {
|
||||
|
||||
selectors = connection.getExistingObject(initializer.getAsJsonObject("selectors").get("guid").getAsString());
|
||||
apiRequest = new APIRequestImpl(this);
|
||||
localUtils = connection.getExistingObject(initializer.getAsJsonObject("utils").get("guid").getAsString());
|
||||
chromium.localUtils = localUtils;
|
||||
firefox.localUtils = localUtils;
|
||||
webkit.localUtils = localUtils;
|
||||
}
|
||||
|
||||
void initSharedSelectors(PlaywrightImpl parent) {
|
||||
|
||||
@@ -32,7 +32,6 @@ class SerializedValue{
|
||||
String v;
|
||||
String d;
|
||||
String u;
|
||||
String bi;
|
||||
public static class R {
|
||||
String p;
|
||||
String f;
|
||||
@@ -47,10 +46,6 @@ class SerializedValue{
|
||||
Number h;
|
||||
Integer id;
|
||||
Integer ref;
|
||||
// JS representation of Map: [[key1, value1], [key2, value2], ...].
|
||||
SerializedValue m;
|
||||
// JS representation of Set: [item1, item2, ...].
|
||||
SerializedValue se;
|
||||
}
|
||||
|
||||
class SerializedArgument{
|
||||
@@ -99,7 +94,7 @@ class ExpectedTextValue {
|
||||
class FrameExpectOptions {
|
||||
Object expressionArg;
|
||||
List<ExpectedTextValue> expectedText;
|
||||
Double expectedNumber;
|
||||
Integer expectedNumber;
|
||||
SerializedArgument expectedValue;
|
||||
Boolean useInnerText;
|
||||
boolean isNot;
|
||||
|
||||
@@ -78,13 +78,7 @@ public class RequestImpl extends ChannelOwner implements Request {
|
||||
|
||||
@Override
|
||||
public FrameImpl frame() {
|
||||
FrameImpl frame = connection.getExistingObject(initializer.getAsJsonObject("frame").get("guid").getAsString());
|
||||
if (frame.page == null) {
|
||||
throw new PlaywrightException("Frame for this navigation request is not available, because the request\n" +
|
||||
"was issued before the frame is created. You can check whether the request\n" +
|
||||
"is a navigation request by calling isNavigationRequest() method.");
|
||||
}
|
||||
return frame;
|
||||
return connection.getExistingObject(initializer.getAsJsonObject("frame").get("guid").getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.*;
|
||||
import com.microsoft.playwright.options.RequestOptions;
|
||||
import com.microsoft.playwright.Frame;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
import com.microsoft.playwright.Route;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -32,9 +33,6 @@ import static com.microsoft.playwright.impl.Utils.convertType;
|
||||
public class RouteImpl extends ChannelOwner implements Route {
|
||||
private final RequestImpl request;
|
||||
private boolean handled;
|
||||
BrowserContextImpl browserContext;
|
||||
boolean fallbackCalled;
|
||||
boolean shouldResumeIfFallbackIsCalled;
|
||||
|
||||
public RouteImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
@@ -47,7 +45,6 @@ public class RouteImpl extends ChannelOwner implements Route {
|
||||
withLogging("Route.abort", () -> {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("errorCode", errorCode);
|
||||
params.addProperty("requestUrl", request.initializer.get("url").getAsString());
|
||||
sendMessageAsync("abort", params);
|
||||
});
|
||||
}
|
||||
@@ -58,50 +55,17 @@ public class RouteImpl extends ChannelOwner implements Route {
|
||||
|
||||
@Override
|
||||
public void resume(ResumeOptions options) {
|
||||
resume(options, false);
|
||||
}
|
||||
|
||||
void resume(ResumeOptions options, boolean isFallback) {
|
||||
startHandling();
|
||||
applyOverrides(convertType(options, FallbackOptions.class));
|
||||
withLogging("Route.resume", () -> resumeImpl(request().fallbackOverridesForResume(), isFallback));
|
||||
withLogging("Route.resume", () -> resumeImpl(request().fallbackOverridesForResume()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fallback(FallbackOptions options) {
|
||||
fallbackCalled = true;
|
||||
if (handled) {
|
||||
throw new PlaywrightException("Route is already handled!");
|
||||
}
|
||||
applyOverrides(options);
|
||||
if (shouldResumeIfFallbackIsCalled) {
|
||||
resume(null, true);
|
||||
}
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
if (fetchOptions != null && fetchOptions.timeout != null) {
|
||||
options.timeout = fetchOptions.timeout;
|
||||
}
|
||||
APIRequestContextImpl apiRequest = browserContext.request();
|
||||
String url = (fetchOptions == null || fetchOptions.url == null) ? request().url() : fetchOptions.url;
|
||||
return apiRequest.fetch(url, options);
|
||||
}
|
||||
|
||||
private void applyOverrides(FallbackOptions options) {
|
||||
@@ -118,7 +82,7 @@ public class RouteImpl extends ChannelOwner implements Route {
|
||||
request().applyFallbackOverrides(overrides);
|
||||
}
|
||||
|
||||
private void resumeImpl(RequestImpl.FallbackOverrides options, boolean isFallback) {
|
||||
private void resumeImpl(RequestImpl.FallbackOverrides options) {
|
||||
JsonObject params = new JsonObject();
|
||||
if (options != null) {
|
||||
if (options.url != null) {
|
||||
@@ -135,8 +99,6 @@ public class RouteImpl extends ChannelOwner implements Route {
|
||||
params.addProperty("postData", base64);
|
||||
}
|
||||
}
|
||||
params.addProperty("requestUrl", request.initializer.get("url").getAsString());
|
||||
params.addProperty("isFallback", isFallback);
|
||||
sendMessageAsync("continue", params);
|
||||
}
|
||||
|
||||
@@ -231,7 +193,6 @@ public class RouteImpl extends ChannelOwner implements Route {
|
||||
if (fetchResponseUid != null) {
|
||||
params.addProperty("fetchResponseUid", fetchResponseUid);
|
||||
}
|
||||
params.addProperty("requestUrl", request.initializer.get("url").getAsString());
|
||||
sendMessageAsync("fulfill", params);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,19 +16,14 @@
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.Route;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.microsoft.playwright.impl.Utils.toJsRegexFlags;
|
||||
|
||||
class Router {
|
||||
private List<RouteInfo> routes = new ArrayList<>();
|
||||
|
||||
@@ -66,11 +61,11 @@ class Router {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
void removeAll() {
|
||||
routes.clear();
|
||||
int size() {
|
||||
return routes.size();
|
||||
}
|
||||
|
||||
enum HandleResult { NoMatchingHandler, Handled, Fallback, PendingHandler }
|
||||
enum HandleResult { NoMatchingHandler, FoundMatchingHandler}
|
||||
HandleResult handle(RouteImpl route) {
|
||||
HandleResult result = HandleResult.NoMatchingHandler;
|
||||
for (Iterator<RouteInfo> it = routes.iterator(); it.hasNext();) {
|
||||
@@ -81,45 +76,12 @@ class Router {
|
||||
if (info.decrementRemainingCallCount()) {
|
||||
it.remove();
|
||||
}
|
||||
route.fallbackCalled = false;
|
||||
result = HandleResult.FoundMatchingHandler;
|
||||
info.handle(route);
|
||||
if (route.isHandled()) {
|
||||
return HandleResult.Handled;
|
||||
}
|
||||
// Not immediately handled and fallback() was not called => the route
|
||||
// must be handled asynchronously.
|
||||
if (!route.fallbackCalled) {
|
||||
route.shouldResumeIfFallbackIsCalled = true;
|
||||
return HandleResult.PendingHandler;
|
||||
}
|
||||
// Fallback was called, continue to the remaining handlers.
|
||||
result = HandleResult.Fallback;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
JsonObject interceptionPatterns() {
|
||||
JsonArray jsonPatterns = new JsonArray();
|
||||
for (RouteInfo route : routes) {
|
||||
JsonObject jsonPattern = new JsonObject();
|
||||
Object urlFilter = route.matcher.rawSource;
|
||||
if (urlFilter instanceof String) {
|
||||
jsonPattern.addProperty("glob", (String) urlFilter);
|
||||
} else if (urlFilter instanceof Pattern) {
|
||||
Pattern pattern = (Pattern) urlFilter;
|
||||
jsonPattern.addProperty("regexSource", pattern.pattern());
|
||||
jsonPattern.addProperty("regexFlags", toJsRegexFlags(pattern));
|
||||
} else {
|
||||
// Match all requests.
|
||||
jsonPattern.addProperty("glob", "**/*");
|
||||
jsonPatterns = new JsonArray();
|
||||
jsonPatterns.add(jsonPattern);
|
||||
break;
|
||||
}
|
||||
jsonPatterns.add(jsonPattern);
|
||||
}
|
||||
JsonObject result = new JsonObject();
|
||||
result.add("patterns", jsonPatterns);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,18 +28,13 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigInteger;
|
||||
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;
|
||||
|
||||
@@ -48,8 +43,6 @@ 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>())
|
||||
@@ -163,8 +156,6 @@ class Serialization {
|
||||
result.d = ((LocalDateTime)value).atZone(ZoneId.systemDefault()).toInstant().toString();
|
||||
} else if (value instanceof URL) {
|
||||
result.u = ((URL)value).toString();
|
||||
} else if (value instanceof BigInteger) {
|
||||
result.bi = ((BigInteger)value).toString();
|
||||
} else if (value instanceof Pattern) {
|
||||
result.r = new SerializedValue.R();
|
||||
result.r.p = ((Pattern)value).pattern();
|
||||
@@ -239,9 +230,6 @@ class Serialization {
|
||||
throw new PlaywrightException("Unexpected value: " + value.u, e);
|
||||
}
|
||||
}
|
||||
if (value.bi != null) {
|
||||
return (T) new BigInteger(value.bi);
|
||||
}
|
||||
if (value.d != null)
|
||||
return (T)(Date.from(Instant.parse(value.d)));
|
||||
if (value.r != null)
|
||||
@@ -280,16 +268,6 @@ class Serialization {
|
||||
}
|
||||
return (T) map;
|
||||
}
|
||||
if (value.m != null) {
|
||||
Map<?, ?> map = new LinkedHashMap<>();
|
||||
idToValue.put(value.id, map);
|
||||
return (T) map;
|
||||
}
|
||||
if (value.se != null) {
|
||||
Map<?, ?> map = new LinkedHashMap<>();
|
||||
idToValue.put(value.id, map);
|
||||
return (T) map;
|
||||
}
|
||||
throw new PlaywrightException("Unexpected result: " + gson().toJson(value));
|
||||
}
|
||||
|
||||
@@ -346,11 +324,6 @@ class Serialization {
|
||||
}
|
||||
|
||||
static JsonArray toProtocol(Map<String, String> map) {
|
||||
for (String value : map.values()) {
|
||||
if (value == null) {
|
||||
throw new PlaywrightException("Value cannot be null");
|
||||
}
|
||||
}
|
||||
return toNameValueArray(map);
|
||||
}
|
||||
|
||||
@@ -369,26 +342,12 @@ class Serialization {
|
||||
for (Map.Entry<String, ?> e : map.entrySet()) {
|
||||
JsonObject item = new JsonObject();
|
||||
item.addProperty("name", e.getKey());
|
||||
if (e.getValue() instanceof FilePayload) {
|
||||
item.add("value", gson().toJsonTree(e.getValue()));
|
||||
} else {
|
||||
item.addProperty("value", "" + e.getValue());
|
||||
}
|
||||
item.add("value", gson().toJsonTree(e.getValue()));
|
||||
array.add(item);
|
||||
}
|
||||
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) {
|
||||
@@ -419,7 +378,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("no-override");
|
||||
return new JsonPrimitive("null");
|
||||
}
|
||||
return context.serialize(src.get());
|
||||
}
|
||||
@@ -452,6 +411,12 @@ 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) {
|
||||
@@ -499,29 +464,5 @@ 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,7 +25,6 @@ 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 {
|
||||
@@ -62,12 +61,6 @@ 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,13 +69,7 @@ class StackTraceCollector {
|
||||
if (file == null) {
|
||||
return "";
|
||||
}
|
||||
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 "";
|
||||
}
|
||||
return resolveSourcePath(Paths.get(pkg).resolve(file));
|
||||
}
|
||||
|
||||
private String resolveSourcePath(Path relativePath) {
|
||||
@@ -118,7 +112,6 @@ class StackTraceCollector {
|
||||
JsonObject jsonFrame = new JsonObject();
|
||||
jsonFrame.addProperty("file", sourceFile(frame));
|
||||
jsonFrame.addProperty("line", frame.getLineNumber());
|
||||
jsonFrame.addProperty("column", 0);
|
||||
jsonFrame.addProperty("function", frame.getClassName() + "." + frame.getMethodName());
|
||||
jsonStack.add(jsonFrame);
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* 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.impl;
|
||||
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
|
||||
public class TargetClosedError extends PlaywrightException {
|
||||
public TargetClosedError() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
public TargetClosedError(String message) {
|
||||
super(message != null ? message : "Target page, context or browser has been closed");
|
||||
}
|
||||
}
|
||||
@@ -30,18 +30,11 @@ class TimeoutSettings {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
Double defaultTimeout() {
|
||||
return defaultTimeout;
|
||||
}
|
||||
Double defaultNavigationTimeout() {
|
||||
return defaultNavigationTimeout;
|
||||
}
|
||||
|
||||
void setDefaultTimeout(Double timeout) {
|
||||
void setDefaultTimeout(double timeout) {
|
||||
defaultTimeout = timeout;
|
||||
}
|
||||
|
||||
void setDefaultNavigationTimeout(Double timeout) {
|
||||
void setDefaultNavigationTimeout(double timeout) {
|
||||
defaultNavigationTimeout = timeout;
|
||||
}
|
||||
|
||||
@@ -80,4 +73,5 @@ class TimeoutSettings {
|
||||
}
|
||||
return new WaitableTimeout<>(timeout(timeout));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
import com.microsoft.playwright.Tracing;
|
||||
|
||||
import java.nio.file.Path;
|
||||
@@ -25,112 +26,91 @@ import java.nio.file.Path;
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
|
||||
class TracingImpl extends ChannelOwner implements Tracing {
|
||||
private boolean includeSources;
|
||||
private Path tracesDir;
|
||||
private boolean isTracing;
|
||||
private String stacksId;
|
||||
|
||||
boolean isRemote;
|
||||
|
||||
TracingImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
}
|
||||
|
||||
private void stopChunkImpl(Path path) {
|
||||
if (isTracing) {
|
||||
isTracing = false;
|
||||
connection.setIsTracing(false);
|
||||
}
|
||||
JsonObject params = new JsonObject();
|
||||
|
||||
// Not interested in artifacts.
|
||||
if (path == null) {
|
||||
params.addProperty("mode", "discard");
|
||||
sendMessage("tracingStopChunk", params);
|
||||
if (stacksId != null) {
|
||||
connection.localUtils().traceDiscarded(stacksId);
|
||||
String mode = "doNotSave";
|
||||
if (path != null) {
|
||||
if (isRemote) {
|
||||
mode = "compressTrace";
|
||||
} else {
|
||||
mode = "compressTraceAndSources";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isLocal = !connection.isRemote;
|
||||
if (isLocal) {
|
||||
params.addProperty("mode", "entries");
|
||||
JsonObject json = sendMessage("tracingStopChunk", params).getAsJsonObject();
|
||||
JsonArray entries = json.getAsJsonArray("entries");
|
||||
connection.localUtils.zip(path, entries, stacksId, false, includeSources);
|
||||
return;
|
||||
}
|
||||
|
||||
params.addProperty("mode", "archive");
|
||||
params.addProperty("mode", mode);
|
||||
JsonObject json = sendMessage("tracingStopChunk", params).getAsJsonObject();
|
||||
// The artifact may be missing if the browser closed while stopping tracing.
|
||||
if (!json.has("artifact")) {
|
||||
if (stacksId != null) {
|
||||
connection.localUtils().traceDiscarded(stacksId);
|
||||
}
|
||||
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();
|
||||
|
||||
connection.localUtils.zip(path, new JsonArray(), stacksId, true, includeSources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startChunk(StartChunkOptions options) {
|
||||
if (options == null) {
|
||||
options = new StartChunkOptions();
|
||||
// Add local sources to the remote trace if necessary.
|
||||
if (isRemote && json.has("sourceEntries")) {
|
||||
JsonArray entries = json.getAsJsonArray("sourceEntries");
|
||||
connection.localUtils.zip(path, entries);
|
||||
}
|
||||
tracingStartChunk(options.name, options.title);
|
||||
}
|
||||
|
||||
private void tracingStartChunk(String name, String title) {
|
||||
JsonObject params = new JsonObject();
|
||||
if (name != null) {
|
||||
params.addProperty("name", name);
|
||||
}
|
||||
if (title != null) {
|
||||
params.addProperty("title", title);
|
||||
}
|
||||
JsonObject result = sendMessage("tracingStartChunk", params).getAsJsonObject();
|
||||
startCollectingStacks(result.get("traceName").getAsString());
|
||||
}
|
||||
|
||||
private void startCollectingStacks(String traceName) {
|
||||
if (!isTracing) {
|
||||
isTracing = true;
|
||||
connection.setIsTracing(true);
|
||||
}
|
||||
stacksId = connection.localUtils().tracingStarted(tracesDir == null ? null : tracesDir.toString(), traceName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(StartOptions options) {
|
||||
withLogging("Tracing.start", () -> startImpl(options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startChunk(StartChunkOptions options) {
|
||||
withLogging("Tracing.startChunk", () -> {
|
||||
startChunkImpl(options);
|
||||
});
|
||||
}
|
||||
|
||||
private void startChunkImpl(StartChunkOptions options) {
|
||||
if (options == null) {
|
||||
options = new StartChunkOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
sendMessage("tracingStartChunk", params);
|
||||
}
|
||||
|
||||
private void startImpl(StartOptions options) {
|
||||
if (options == null) {
|
||||
options = new StartOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
includeSources = options.sources != null && options.sources;
|
||||
boolean includeSources = options.sources != null && options.sources;
|
||||
if (includeSources) {
|
||||
if (!connection.isCollectingStacks()) {
|
||||
throw new PlaywrightException("Source root directory must be specified via PLAYWRIGHT_JAVA_SRC environment variable when source collection is enabled");
|
||||
}
|
||||
params.addProperty("sources", true);
|
||||
}
|
||||
sendMessage("tracingStart", params);
|
||||
tracingStartChunk(options.name, options.title);
|
||||
sendMessage("tracingStartChunk");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(StopOptions options) {
|
||||
stopChunkImpl(options == null ? null : options.path);
|
||||
sendMessage("tracingStop");
|
||||
withLogging("Tracing.stop", () -> {
|
||||
stopChunkImpl(options == null ? null : options.path);
|
||||
sendMessage("tracingStop");
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopChunk(StopChunkOptions options) {
|
||||
stopChunkImpl(options == null ? null : options.path);
|
||||
}
|
||||
|
||||
void setTracesDir(Path tracesDir) {
|
||||
this.tracesDir = tracesDir;
|
||||
withLogging("Tracing.stopChunk", () -> {
|
||||
stopChunkImpl(options == null ? null : options.path);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ import java.util.regex.Pattern;
|
||||
import static com.microsoft.playwright.impl.Utils.globToRegex;
|
||||
|
||||
class UrlMatcher {
|
||||
final Object rawSource;
|
||||
private final Object rawSource;
|
||||
private final Predicate<String> predicate;
|
||||
|
||||
private static Predicate<String> toPredicate(Pattern pattern) {
|
||||
@@ -90,11 +90,6 @@ class UrlMatcher {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
UrlMatcher that = (UrlMatcher) o;
|
||||
if (rawSource instanceof Pattern && that.rawSource instanceof Pattern) {
|
||||
Pattern a = (Pattern) rawSource;
|
||||
Pattern b = (Pattern) that.rawSource;
|
||||
return a.pattern().equals(b.pattern()) && a.flags() == b.flags();
|
||||
}
|
||||
return Objects.equals(rawSource, that.rawSource);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -80,16 +79,7 @@ class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
static <T> T clone(T f) {
|
||||
if (f == null) {
|
||||
return f;
|
||||
}
|
||||
return convertType(f, (Class<T>) f.getClass());
|
||||
}
|
||||
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions#escaping
|
||||
static Set<Character> escapeGlobChars = new HashSet<>(Arrays.asList('$', '^', '+', '.', '*', '(', ')', '|', '\\', '?', '{', '}', '[', ']'));
|
||||
static Set<Character> escapeGlobChars = new HashSet<>(Arrays.asList('/', '$', '^', '+', '.', '(', ')', '=', '!', '|'));
|
||||
|
||||
static String globToRegex(String glob) {
|
||||
StringBuilder tokens = new StringBuilder();
|
||||
@@ -97,12 +87,8 @@ class Utils {
|
||||
boolean inGroup = false;
|
||||
for (int i = 0; i < glob.length(); ++i) {
|
||||
char c = glob.charAt(i);
|
||||
if (c == '\\' && i + 1 < glob.length()) {
|
||||
char nextChar = glob.charAt(++i);
|
||||
if (escapeGlobChars.contains(nextChar)) {
|
||||
tokens.append('\\');
|
||||
}
|
||||
tokens.append(nextChar);
|
||||
if (escapeGlobChars.contains(c)) {
|
||||
tokens.append("\\").append(c);
|
||||
continue;
|
||||
}
|
||||
if (c == '*') {
|
||||
@@ -127,12 +113,6 @@ class Utils {
|
||||
case '?':
|
||||
tokens.append('.');
|
||||
break;
|
||||
case '[':
|
||||
tokens.append('[');
|
||||
break;
|
||||
case ']':
|
||||
tokens.append(']');
|
||||
break;
|
||||
case '{':
|
||||
inGroup = true;
|
||||
tokens.append('(');
|
||||
@@ -149,11 +129,7 @@ class Utils {
|
||||
tokens.append("\\").append(c);
|
||||
break;
|
||||
default:
|
||||
if (escapeGlobChars.contains(c)) {
|
||||
tokens.append('\\');
|
||||
}
|
||||
tokens.append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
tokens.append('$');
|
||||
@@ -173,21 +149,27 @@ class Utils {
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
static void addFilePathUploadParams(Path[] files, JsonObject params, BrowserContextImpl context) {
|
||||
if (files.length == 0) {
|
||||
// FIXME: shouldBeAbleToResetSelectedFilesWithEmptyFileList tesst hangs in Chromium if we pass empty paths list.
|
||||
params.add("payloads", new JsonArray());
|
||||
} else if (context.connection.isRemote) {
|
||||
static final int maxUplodBufferSize = 50 * 1024 * 1024;
|
||||
|
||||
static boolean hasLargeFile(Path[] files) {
|
||||
for (Path file: files) {
|
||||
try {
|
||||
if (Files.size(file)> maxUplodBufferSize) {
|
||||
return true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new PlaywrightException("Cannot get file size.", e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void addLargeFileUploadParams(Path[] files, JsonObject params, BrowserContextImpl context) {
|
||||
if (context.browser().isRemote) {
|
||||
List<WritableStream> streams = new ArrayList<>();
|
||||
JsonArray jsonStreams = new JsonArray();
|
||||
for (Path path : files) {
|
||||
long lastModifiedMs;
|
||||
try {
|
||||
lastModifiedMs = Files.getLastModifiedTime(path).toMillis();
|
||||
} catch (IOException e) {
|
||||
throw new PlaywrightException("Cannot read file timestamp: " + path, e);
|
||||
}
|
||||
WritableStream temp = context.createTempFile(path.getFileName().toString(), lastModifiedMs);
|
||||
WritableStream temp = context.createTempFile(path.getFileName().toString());
|
||||
streams.add(temp);
|
||||
try (OutputStream out = temp.stream()) {
|
||||
Files.copy(path, out);
|
||||
@@ -210,12 +192,10 @@ class Utils {
|
||||
}
|
||||
|
||||
static void checkFilePayloadSize(FilePayload[] files) {
|
||||
long totalSize = 0;
|
||||
for (FilePayload file: files) {
|
||||
totalSize += file.buffer.length;
|
||||
}
|
||||
if (totalSize > 50 * 1024 * 1024) {
|
||||
throw new PlaywrightException("Cannot set buffer larger than 50Mb, please write it to a file and pass its path instead.");
|
||||
if (file.buffer.length > maxUplodBufferSize) {
|
||||
throw new PlaywrightException("Cannot set buffer larger than 50Mb, please write it to a file and pass its path instead.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,7 +242,7 @@ class Utils {
|
||||
static void writeToFile(InputStream inputStream, Path path) {
|
||||
mkParentDirs(path);
|
||||
try (FileOutputStream out = new FileOutputStream(path.toFile())) {
|
||||
byte[] buf = new byte[1024 * 1024];
|
||||
byte[] buf = new byte[8192];
|
||||
int length;
|
||||
while ((length = inputStream.read(buf)) > 0) {
|
||||
out.write(buf, 0, length);
|
||||
|
||||
@@ -27,13 +27,16 @@ 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);
|
||||
}
|
||||
|
||||
@@ -55,7 +58,7 @@ class VideoImpl implements Video {
|
||||
@Override
|
||||
public Path path() {
|
||||
return page.withLogging("Video.path", () -> {
|
||||
if (page.connection.isRemote) {
|
||||
if (isRemote) {
|
||||
throw new PlaywrightException("Path is not available when using browserType.connect(). Use saveAs() to save a local copy.");
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
class WaitablePredicate<T> implements Waitable<T> {
|
||||
private final BooleanSupplier predicate;
|
||||
|
||||
WaitablePredicate(BooleanSupplier predicate) {
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return predicate.getAsBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.microsoft.playwright.WebError;
|
||||
|
||||
public class WebErrorImpl implements WebError {
|
||||
private final PageImpl page;
|
||||
private final String error;
|
||||
|
||||
WebErrorImpl(PageImpl page, String error) {
|
||||
this.page = page;
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageImpl page() {
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String error() {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
@@ -28,12 +28,6 @@ class WritableStream extends ChannelOwner {
|
||||
params.addProperty("binary", new String(encoded.array(), StandardCharsets.UTF_8));
|
||||
sendMessage("write", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
sendMessage("close");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* 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,115 +34,43 @@ import java.nio.file.Path;
|
||||
public interface FormData {
|
||||
/**
|
||||
* Creates new instance of {@code FormData}.
|
||||
*
|
||||
* @since v1.18
|
||||
*/
|
||||
static FormData create() {
|
||||
return new FormDataImpl();
|
||||
}
|
||||
/**
|
||||
* Sets a field on the form. File values can be passed either as {@code Path} or as {@code FilePayload}.
|
||||
* <pre>{@code
|
||||
* import com.microsoft.playwright.options.FormData;
|
||||
* ...
|
||||
* FormData form = FormData.create()
|
||||
* // Only name and value are set.
|
||||
* .set("firstName", "John")
|
||||
* // Name and value are set, filename and Content-Type are inferred from the file path.
|
||||
* .set("profilePicture1", Paths.get("john.jpg"))
|
||||
* // Name, value, filename and Content-Type are set.
|
||||
* .set("profilePicture2", new FilePayload("john.jpg", "image/jpeg", Files.readAllBytes(Paths.get("john.jpg"))));
|
||||
* .set("age", 30);
|
||||
* page.request().post("http://localhost/submit", RequestOptions.create().setForm(form));
|
||||
* }</pre>
|
||||
*
|
||||
* @param name Field name.
|
||||
* @param value Field value.
|
||||
* @since v1.18
|
||||
*/
|
||||
FormData set(String name, String value);
|
||||
/**
|
||||
* Sets a field on the form. File values can be passed either as {@code Path} or as {@code FilePayload}.
|
||||
* <pre>{@code
|
||||
* import com.microsoft.playwright.options.FormData;
|
||||
* ...
|
||||
* FormData form = FormData.create()
|
||||
* // Only name and value are set.
|
||||
* .set("firstName", "John")
|
||||
* // Name and value are set, filename and Content-Type are inferred from the file path.
|
||||
* .set("profilePicture1", Paths.get("john.jpg"))
|
||||
* // Name, value, filename and Content-Type are set.
|
||||
* .set("profilePicture2", new FilePayload("john.jpg", "image/jpeg", Files.readAllBytes(Paths.get("john.jpg"))));
|
||||
* .set("age", 30);
|
||||
* page.request().post("http://localhost/submit", RequestOptions.create().setForm(form));
|
||||
* }</pre>
|
||||
*
|
||||
* @param name Field name.
|
||||
* @param value Field value.
|
||||
* @since v1.18
|
||||
*/
|
||||
FormData set(String name, boolean value);
|
||||
/**
|
||||
* Sets a field on the form. File values can be passed either as {@code Path} or as {@code FilePayload}.
|
||||
* <pre>{@code
|
||||
* import com.microsoft.playwright.options.FormData;
|
||||
* ...
|
||||
* FormData form = FormData.create()
|
||||
* // Only name and value are set.
|
||||
* .set("firstName", "John")
|
||||
* // Name and value are set, filename and Content-Type are inferred from the file path.
|
||||
* .set("profilePicture1", Paths.get("john.jpg"))
|
||||
* // Name, value, filename and Content-Type are set.
|
||||
* .set("profilePicture2", new FilePayload("john.jpg", "image/jpeg", Files.readAllBytes(Paths.get("john.jpg"))));
|
||||
* .set("age", 30);
|
||||
* page.request().post("http://localhost/submit", RequestOptions.create().setForm(form));
|
||||
* }</pre>
|
||||
*
|
||||
* @param name Field name.
|
||||
* @param value Field value.
|
||||
* @since v1.18
|
||||
*/
|
||||
FormData set(String name, int value);
|
||||
/**
|
||||
* Sets a field on the form. File values can be passed either as {@code Path} or as {@code FilePayload}.
|
||||
* <pre>{@code
|
||||
* import com.microsoft.playwright.options.FormData;
|
||||
* ...
|
||||
* FormData form = FormData.create()
|
||||
* // Only name and value are set.
|
||||
* .set("firstName", "John")
|
||||
* // Name and value are set, filename and Content-Type are inferred from the file path.
|
||||
* .set("profilePicture1", Paths.get("john.jpg"))
|
||||
* // Name, value, filename and Content-Type are set.
|
||||
* .set("profilePicture2", new FilePayload("john.jpg", "image/jpeg", Files.readAllBytes(Paths.get("john.jpg"))));
|
||||
* .set("age", 30);
|
||||
* page.request().post("http://localhost/submit", RequestOptions.create().setForm(form));
|
||||
* }</pre>
|
||||
*
|
||||
* @param name Field name.
|
||||
* @param value Field value.
|
||||
* @since v1.18
|
||||
*/
|
||||
FormData set(String name, Path value);
|
||||
/**
|
||||
* Sets a field on the form. File values can be passed either as {@code Path} or as {@code FilePayload}.
|
||||
* <pre>{@code
|
||||
* import com.microsoft.playwright.options.FormData;
|
||||
* ...
|
||||
* FormData form = FormData.create()
|
||||
* // Only name and value are set.
|
||||
* .set("firstName", "John")
|
||||
* // Name and value are set, filename and Content-Type are inferred from the file path.
|
||||
* .set("profilePicture1", Paths.get("john.jpg"))
|
||||
* // Name, value, filename and Content-Type are set.
|
||||
* .set("profilePicture2", new FilePayload("john.jpg", "image/jpeg", Files.readAllBytes(Paths.get("john.jpg"))));
|
||||
* .set("age", 30);
|
||||
* page.request().post("http://localhost/submit", RequestOptions.create().setForm(form));
|
||||
* }</pre>
|
||||
*
|
||||
* @param name Field name.
|
||||
* @param value Field value.
|
||||
* @since v1.18
|
||||
*/
|
||||
FormData set(String name, FilePayload value);
|
||||
}
|
||||
|
||||
@@ -19,20 +19,9 @@ package com.microsoft.playwright.options;
|
||||
public class HttpCredentials {
|
||||
public String username;
|
||||
public String password;
|
||||
/**
|
||||
* Restrain sending http credentials on specific origin (scheme://host:port).
|
||||
*/
|
||||
public String origin;
|
||||
|
||||
public HttpCredentials(String username, String password) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
/**
|
||||
* Restrain sending http credentials on specific origin (scheme://host:port).
|
||||
*/
|
||||
public HttpCredentials setOrigin(String origin) {
|
||||
this.origin = origin;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -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,8 +59,6 @@ import com.microsoft.playwright.impl.RequestOptionsImpl;
|
||||
public interface RequestOptions {
|
||||
/**
|
||||
* Creates new instance of {@code RequestOptions}.
|
||||
*
|
||||
* @since v1.18
|
||||
*/
|
||||
static RequestOptions create() {
|
||||
return new RequestOptionsImpl();
|
||||
@@ -69,60 +67,52 @@ 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.
|
||||
* @since v1.18
|
||||
* {@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.
|
||||
*/
|
||||
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.
|
||||
* @since v1.18
|
||||
* {@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.
|
||||
*/
|
||||
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.
|
||||
* @since v1.18
|
||||
* {@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.
|
||||
*/
|
||||
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.
|
||||
* @since v1.18
|
||||
* @param form Form data to be serialized as html form using {@code application/x-www-form-urlencoded} encoding and sent as this request
|
||||
* body.
|
||||
*/
|
||||
RequestOptions setForm(FormData form);
|
||||
/**
|
||||
* Sets an HTTP header to the request. This header will apply to the fetched request as well as any redirects initiated by
|
||||
* it.
|
||||
* Sets an HTTP header to the request.
|
||||
*
|
||||
* @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);
|
||||
/**
|
||||
@@ -130,7 +120,6 @@ 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);
|
||||
/**
|
||||
@@ -138,16 +127,14 @@ 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);
|
||||
/**
|
||||
@@ -155,7 +142,6 @@ public interface RequestOptions {
|
||||
*
|
||||
* @param name Parameter name.
|
||||
* @param value Parameter value.
|
||||
* @since v1.18
|
||||
*/
|
||||
RequestOptions setQueryParam(String name, String value);
|
||||
/**
|
||||
@@ -163,7 +149,6 @@ public interface RequestOptions {
|
||||
*
|
||||
* @param name Parameter name.
|
||||
* @param value Parameter value.
|
||||
* @since v1.18
|
||||
*/
|
||||
RequestOptions setQueryParam(String name, boolean value);
|
||||
/**
|
||||
@@ -171,14 +156,12 @@ 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);
|
||||
}
|
||||
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* 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 RouteFromHarUpdateContentPolicy {
|
||||
EMBED,
|
||||
ATTACH
|
||||
}
|
||||
@@ -52,8 +52,8 @@ public class Timing {
|
||||
*/
|
||||
public double requestStart;
|
||||
/**
|
||||
* Time immediately after the browser receives the first byte of the response from the server, cache, or local resource.
|
||||
* The value is given in milliseconds relative to {@code startTime}, -1 if not available.
|
||||
* Time immediately after the browser starts requesting the resource from the server, cache, or local resource. The value
|
||||
* is given in milliseconds relative to {@code startTime}, -1 if not available.
|
||||
*/
|
||||
public double responseStart;
|
||||
/**
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.assertions.LocatorAssertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.opentest4j.AssertionFailedError;
|
||||
|
||||
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
// Copied from expect-misc.spec.ts > toBeInViewport
|
||||
public class TestAssertThatIsInViewport extends TestBase {
|
||||
@Test
|
||||
void shouldWork() {
|
||||
page.setContent("<div id=big style=\"height: 10000px;\"></div>\n" +
|
||||
" <div id=small>foo</div>");
|
||||
assertThat(page.locator("#big")).isInViewport();
|
||||
assertThat(page.locator("#small")).not().isInViewport();
|
||||
page.locator("#small").scrollIntoViewIfNeeded();
|
||||
assertThat(page.locator("#small")).isInViewport();
|
||||
assertThat(page.locator("#small")).isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRespectRatioOption() {
|
||||
page.setContent("<style>body, div, html { padding: 0; margin: 0; }</style>\n" +
|
||||
" <div id=big style=\"height: 400vh;\"></div>");
|
||||
assertThat(page.locator("div")).isInViewport();
|
||||
assertThat(page.locator("div")).isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.1));
|
||||
assertThat(page.locator("div")).isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.2));
|
||||
|
||||
assertThat(page.locator("div")).isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.24));
|
||||
// In this test, element's ratio is 0.25.
|
||||
assertThat(page.locator("div")).isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.25));
|
||||
assertThat(page.locator("div")).not().isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.26));
|
||||
|
||||
assertThat(page.locator("div")).not().isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.3));
|
||||
assertThat(page.locator("div")).not().isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.7));
|
||||
assertThat(page.locator("div")).not().isInViewport(new LocatorAssertions.IsInViewportOptions().setRatio(0.8));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHaveGoodStack() {
|
||||
AssertionFailedError error = assertThrows(AssertionFailedError.class, () -> assertThat(page.locator("body")).not().isInViewport(new LocatorAssertions.IsInViewportOptions().setTimeout(100)));
|
||||
assertNotNull(error);
|
||||
assertTrue(error.getMessage().contains("Locator expected not to be in viewport"), error.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReportIntersectionEvenIfFullyCoveredByOtherElement() {
|
||||
page.setContent("<h1>hello</h1>\n" +
|
||||
" <div style=\"position: relative; height: 10000px; top: -5000px;></div>");
|
||||
assertThat(page.locator("h1")).isInViewport();
|
||||
}
|
||||
}
|
||||
@@ -20,17 +20,10 @@ import org.junit.jupiter.api.*;
|
||||
|
||||
import com.microsoft.playwright.options.SameSiteAttribute;
|
||||
|
||||
import javax.sql.rowset.Predicate;
|
||||
import java.io.IOException;
|
||||
import java.security.Provider;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static com.microsoft.playwright.Utils.getBrowserNameFromEnv;
|
||||
import static com.microsoft.playwright.Utils.nextFreePort;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
public class TestBase {
|
||||
@@ -157,13 +150,6 @@ public class TestBase {
|
||||
}
|
||||
}
|
||||
|
||||
void waitForCondition(BooleanSupplier predicate) {
|
||||
waitForCondition(predicate, 5_000);
|
||||
}
|
||||
void waitForCondition(BooleanSupplier predicate, int timeoutMs) {
|
||||
page.waitForCondition(predicate, new Page.WaitForConditionOptions().setTimeout(timeoutMs));
|
||||
}
|
||||
|
||||
private static SameSiteAttribute initSameSiteAttribute() {
|
||||
if (isChromium()) return SameSiteAttribute.LAX;
|
||||
if (isWebKit()) return SameSiteAttribute.NONE;
|
||||
|
||||
@@ -16,14 +16,10 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.options.BrowserChannel;
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
@@ -102,40 +98,4 @@ public class TestBrowser extends TestBase {
|
||||
void shouldReturnBrowserType() {
|
||||
assertEquals(browserType, browser.browserType());
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledIf(value = "com.microsoft.playwright.TestBase#isChromium", disabledReason = "Chrome Devtools Protocol supported by chromium only")
|
||||
void shouldWorkWithNewBrowserCDPSession() {
|
||||
CDPSession session = browser.newBrowserCDPSession();
|
||||
|
||||
JsonElement response = session.send("Browser.getVersion");
|
||||
assertNotNull(response.getAsJsonObject().get("userAgent").toString());
|
||||
|
||||
AtomicReference<Boolean> gotEvent = new AtomicReference<>(false);
|
||||
|
||||
session.on("Target.targetCreated", jsonElement -> {
|
||||
gotEvent.set(true);
|
||||
});
|
||||
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("discover", true);
|
||||
session.send("Target.setDiscoverTargets", params);
|
||||
|
||||
Page page = browser.newPage();
|
||||
assertTrue(gotEvent.get());
|
||||
page.close();
|
||||
|
||||
session.detach();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldPropagateCloseReasonToPendingActions() {
|
||||
Browser browser = browserType.launch();
|
||||
BrowserContext context = browser.newContext();
|
||||
PlaywrightException e = assertThrows(PlaywrightException.class, () -> context.waitForPage(() -> {
|
||||
browser.close(new Browser.CloseOptions().setReason("The reason."));
|
||||
}));
|
||||
assertTrue(e.getMessage().contains("The reason."), e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user