Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dfd62f06b5 | |||
| 7fb2ff34c0 | |||
| 0585e0d108 | |||
| 48d95a6543 | |||
| 74bf6637f3 | |||
| 7f3ecd83b9 | |||
| f143ebd053 | |||
| 6c3c47a9f1 | |||
| 4049952751 | |||
| d24eba79dc | |||
| 0fa416b459 | |||
| a95f8f3887 | |||
| 779d50ca53 | |||
| 627a940bcd | |||
| c30e105e36 | |||
| 8ee5b8b436 | |||
| 21a7f4da02 | |||
| e995996e4f | |||
| c23afbf9cf | |||
| 2e57a7a101 | |||
| 20322470b5 | |||
| ed25d1877d | |||
| 8e27ec6bc3 | |||
| 2d956e4a8d | |||
| 40c663ccce | |||
| 7f52faf400 | |||
| 5cd00cc4c7 | |||
| 1ff5671b12 | |||
| f332a536b1 | |||
| 5d5e85502e | |||
| f8b4e93f25 | |||
| 38aa88d59f | |||
| 91282d3401 | |||
| 1904087722 | |||
| db810d1117 | |||
| 2ffca6a0b4 | |||
| af1bf963dc | |||
| abada21f3a | |||
| 34f34d869f | |||
| 1e4763c80d | |||
| ac7b1e4a7a | |||
| 41735ff8ca | |||
| 866bf3587c | |||
| d75a7d76a9 | |||
| d2b6e1c2b4 | |||
| a334baab49 | |||
| 31c029a50a | |||
| b1b5b43948 | |||
| bddd52e360 | |||
| cbc671dd16 | |||
| a9a2eba2f6 | |||
| 4bcb7afeda | |||
| 7ca9b33f46 | |||
| ae15e3050d | |||
| ed68a789ef | |||
| 93a54d0a52 |
@@ -0,0 +1,26 @@
|
||||
name: "devrelease:docker"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
jobs:
|
||||
publish-canary-docker:
|
||||
name: "publish to DockerHub"
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.repository == 'microsoft/playwright-java'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: azure/docker-login@v1
|
||||
with:
|
||||
login-server: playwright.azurecr.io
|
||||
username: playwright
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build Docker image
|
||||
run: docker build -t playwright-java:localbuild-focal -f Dockerfile.focal .
|
||||
- name: tag & publish
|
||||
run: |
|
||||
./scripts/tag_image_and_push.sh playwright-java:localbuild-focal playwright.azurecr.io/public/playwright/java:next
|
||||
./scripts/tag_image_and_push.sh playwright-java:localbuild-focal playwright.azurecr.io/public/playwright/java:next-focal
|
||||
./scripts/tag_image_and_push.sh playwright-java:localbuild-focal playwright.azurecr.io/public/playwright/java:sha-${{ github.sha }}
|
||||
@@ -0,0 +1,36 @@
|
||||
name: Publish Release Docker
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
branches:
|
||||
- release-*
|
||||
jobs:
|
||||
publish-canary-docker:
|
||||
name: publish to DockerHub
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.repository == 'microsoft/playwright-java'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: azure/docker-login@v1
|
||||
with:
|
||||
login-server: playwright.azurecr.io
|
||||
username: playwright
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build Docker image
|
||||
run: docker build -t playwright-java:localbuild-focal -f Dockerfile.focal .
|
||||
- name: tag & publish
|
||||
run: |
|
||||
# GITHUB_REF has a form of `refs/tags/v1.3.0`.
|
||||
# TAG_NAME would be `v1.3.0`
|
||||
TAG_NAME=${GITHUB_REF#refs/tags/}
|
||||
if [[ ! "$TAG_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]];
|
||||
then
|
||||
echo "Wrong TAG_NAME format: $TAG_NAME"
|
||||
exit 1
|
||||
fi
|
||||
./scripts/tag_image_and_push.sh playwright-java:localbuild-focal playwright.azurecr.io/public/playwright/java:latest
|
||||
./scripts/tag_image_and_push.sh playwright-java:localbuild-focal playwright.azurecr.io/public/playwright/java:focal
|
||||
./scripts/tag_image_and_push.sh playwright-java:localbuild-focal playwright.azurecr.io/public/playwright/java:${TAG_NAME}
|
||||
./scripts/tag_image_and_push.sh playwright-java:localbuild-focal playwright.azurecr.io/public/playwright/java:${TAG_NAME}-focal
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Test
|
||||
name: Build & Test
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
@@ -9,7 +9,7 @@ on:
|
||||
- master
|
||||
- release-*
|
||||
jobs:
|
||||
build:
|
||||
dev:
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -39,3 +39,53 @@ jobs:
|
||||
run: mvn test --no-transfer-progress
|
||||
env:
|
||||
BROWSER: ${{ matrix.browser }}
|
||||
- name: Test Spring Boot Starter
|
||||
shell: bash
|
||||
env:
|
||||
BROWSER: ${{ matrix.browser }}
|
||||
run: |
|
||||
mvn -B install -D skipTests --no-transfer-progress
|
||||
cd tools/test-spring-boot-starter
|
||||
mvn package -D skipTests --no-transfer-progress
|
||||
java -jar target/test-spring-boot*.jar
|
||||
|
||||
stable:
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
browser-channel: [chrome]
|
||||
include:
|
||||
- os: windows-latest
|
||||
browser-channel: msedge
|
||||
- os: macos-latest
|
||||
browser-channel: msedge
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: microsoft/playwright-github-action@v1
|
||||
- name: Install Media Pack
|
||||
if: matrix.os == 'windows-latest'
|
||||
shell: powershell
|
||||
run: Install-WindowsFeature Server-Media-Foundation
|
||||
- name: Set up JDK 1.8
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
- name: Cache Maven packages
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.m2
|
||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: ${{ runner.os }}-m2
|
||||
- name: Download drivers
|
||||
shell: bash
|
||||
run: scripts/download_driver_for_all_platforms.sh
|
||||
- name: Build with Maven
|
||||
run: mvn -B package -D skipTests --no-transfer-progress
|
||||
- name: Run tests
|
||||
run: mvn test --no-transfer-progress
|
||||
env:
|
||||
BROWSER: chromium
|
||||
BROWSER_CHANNEL: ${{ matrix.browser-channel }}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
name: Test Docker
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.github/workflows/test_docker.yml'
|
||||
- 'Dockerfile*'
|
||||
branches:
|
||||
- master
|
||||
- release-*
|
||||
pull_request:
|
||||
paths:
|
||||
- .github/workflows/test_docker.yml
|
||||
- Dockerfile.*
|
||||
- scripts/CLI_VERSION
|
||||
- '**/pom.xml'
|
||||
branches:
|
||||
- master
|
||||
- release-*
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build Docker image
|
||||
run: docker build -t playwright-java:localbuild-focal -f Dockerfile.focal .
|
||||
- name: Test
|
||||
run: |
|
||||
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
|
||||
+11
-2
@@ -2,7 +2,16 @@
|
||||
|
||||
## How to Contribute
|
||||
|
||||
### Getting Code
|
||||
### Installing Developer Tools
|
||||
|
||||
Install git, Java JDK (version >= 8), Maven (tested with version 3.6.3), on Ubuntu 20.04
|
||||
just run the following command:
|
||||
|
||||
```sh
|
||||
sudo apt-get install git openjdk-11-jdk maven
|
||||
```
|
||||
|
||||
### Getting the Code
|
||||
|
||||
1. Clone this repository
|
||||
|
||||
@@ -19,7 +28,7 @@ scripts/download_driver_for_all_platforms.sh
|
||||
|
||||
Names of published driver archives can be found at https://github.com/microsoft/playwright-cli/actions
|
||||
|
||||
### Compiling and running the tests with Maven
|
||||
### Building and running the tests with Maven
|
||||
|
||||
```bash
|
||||
mvn compile
|
||||
|
||||
+17
-56
@@ -1,71 +1,32 @@
|
||||
FROM ubuntu:focal
|
||||
|
||||
# === INSTALL BROWSER DEPENDENCIES ===
|
||||
|
||||
# Install WebKit dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libwoff1 \
|
||||
libopus0 \
|
||||
libwebp6 \
|
||||
libwebpdemux2 \
|
||||
libenchant1c2a \
|
||||
libgudev-1.0-0 \
|
||||
libsecret-1-0 \
|
||||
libhyphen0 \
|
||||
libgdk-pixbuf2.0-0 \
|
||||
libegl1 \
|
||||
libnotify4 \
|
||||
libxslt1.1 \
|
||||
libevent-2.1-7 \
|
||||
libgles2 \
|
||||
libxcomposite1 \
|
||||
libatk1.0-0 \
|
||||
libatk-bridge2.0-0 \
|
||||
libepoxy0 \
|
||||
libgtk-3-0 \
|
||||
libharfbuzz-icu0
|
||||
|
||||
# Install gstreamer and plugins to support video playback in WebKit.
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libgstreamer-gl1.0-0 \
|
||||
libgstreamer-plugins-bad1.0-0 \
|
||||
gstreamer1.0-plugins-good \
|
||||
gstreamer1.0-libav
|
||||
|
||||
# Install Chromium dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libnss3 \
|
||||
libxss1 \
|
||||
libasound2 \
|
||||
fonts-noto-color-emoji \
|
||||
libxtst6
|
||||
|
||||
# Install Firefox dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libdbus-glib-1-2 \
|
||||
libxt6
|
||||
|
||||
# Install ffmpeg to bring in audio and video codecs necessary for playing videos in Firefox.
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
ffmpeg
|
||||
|
||||
# (Optional) Install XVFB if there's a need to run browsers in headful mode
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
xvfb
|
||||
|
||||
# === INSTALL JDK and Maven ===
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
openjdk-8-jdk maven
|
||||
openjdk-11-jdk maven
|
||||
|
||||
ENV JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
|
||||
|
||||
# Install utilities required for downloading driver
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
curl unzip
|
||||
|
||||
# === INSTALL Playwright-java ===
|
||||
# === INSTALL playwright maven modules & browsers ===
|
||||
|
||||
# Browsers will remain downloaded in `/ms-playwright`.
|
||||
# Note: make sure to set 777 to the registry so that any user can access
|
||||
# registry.
|
||||
ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
|
||||
|
||||
RUN mkdir /ms-playwright && chmod -R 777 $PLAYWRIGHT_BROWSERS_PATH
|
||||
|
||||
RUN mkdir /tmp/pw-java
|
||||
COPY . /tmp/pw-java
|
||||
RUN cd /tmp/pw-java && ./scripts/download_driver_for_all_platforms.sh && \
|
||||
RUN cd /tmp/pw-java && \
|
||||
./scripts/download_driver_for_all_platforms.sh && \
|
||||
mvn install -D skipTests --no-transfer-progress && \
|
||||
DEBIAN_FRONTEND=noninteractive mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
|
||||
-D exec.args="install-deps" -f playwright/pom.xml --no-transfer-progress && \
|
||||
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI \
|
||||
-D exec.args="install" -f playwright/pom.xml --no-transfer-progress && \
|
||||
rm -rf /tmp/pw-java
|
||||
|
||||
@@ -5,17 +5,17 @@
|
||||
[](https://oss.sonatype.org/content/repositories/snapshots/com/microsoft/playwright/playwright/)
|
||||
[](https://aka.ms/playwright-slack)
|
||||
|
||||
#### [Website](https://playwright.dev/) | [API reference](https://www.javadoc.io/doc/com.microsoft.playwright/playwright/latest/index.html)
|
||||
#### [Website](https://playwright.dev/java/) | [API reference](https://www.javadoc.io/doc/com.microsoft.playwright/playwright/latest/index.html)
|
||||
|
||||
Playwright is a Java library to automate [Chromium](https://www.chromium.org/Home), [Firefox](https://www.mozilla.org/en-US/firefox/new/) and [WebKit](https://webkit.org/) with a single API. Playwright is built to enable cross-browser web automation that is **ever-green**, **capable**, **reliable** and **fast**.
|
||||
|
||||
| | Linux | macOS | Windows |
|
||||
| :--- | :---: | :---: | :---: |
|
||||
| Chromium <!-- GEN:chromium-version -->90.0.4392.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| WebKit <!-- GEN:webkit-version -->14.1<!-- GEN:stop --> | ✅ | ✅ | ✅ |
|
||||
| Firefox <!-- GEN:firefox-version -->85.0b5<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| Chromium <!-- GEN:chromium-version -->92.0.4498.0<!-- GEN:stop --> | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| WebKit <!-- GEN:webkit-version -->14.2<!-- GEN:stop --> | ✅ | ✅ | ✅ |
|
||||
| Firefox <!-- GEN:firefox-version -->89.0b6<!-- 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/#?path=docs/intro.md&q=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)
|
||||
@@ -35,7 +35,7 @@ Playwright requires **Java 8** or newer.
|
||||
|
||||
#### Add Maven dependency
|
||||
|
||||
Playwright is distributed as a set of [Maven](https://maven.apache.org/what-is-maven.html) modules. The easiest way to use it is to add a couple of dependencies to your Maven `pom.xml` file as described below. If you're not familiar with Maven please refer to its [documentation](https://maven.apache.org/guides/getting-started/maven-in-five-minutes.html).
|
||||
Playwright is distributed as a set of [Maven](https://maven.apache.org/what-is-maven.html) modules. The easiest way to use it is to add one dependency to your Maven `pom.xml` file as described below. If you're not familiar with Maven please refer to its [documentation](https://maven.apache.org/guides/getting-started/maven-in-five-minutes.html).
|
||||
|
||||
To run Playwright simply add following dependency to your Maven project:
|
||||
|
||||
@@ -43,13 +43,13 @@ To run Playwright simply add following dependency to your Maven project:
|
||||
<dependency>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>playwright</artifactId>
|
||||
<version>0.180.0</version>
|
||||
<version>1.10.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
#### Is Playwright thread-safe?
|
||||
|
||||
No, Playwright is not thread safe, i.e. all its methods as well as methods on all objects created by it (such as BrowserContext, Browser, Page etc.) are expected to be called on the same thread where Playwright object was created or proper synchronization should be implemented to ensure only one thread calls Playwright methods at any given time. Having said that it's okay to create new many Playwright instances each on its own thread.
|
||||
No, Playwright is not thread safe, i.e. all its methods as well as methods on all objects created by it (such as BrowserContext, Browser, Page etc.) are expected to be called on the same thread where Playwright object was created or proper synchronization should be implemented to ensure only one thread calls Playwright methods at any given time. Having said that it's okay to create multiple Playwright instances each on its own thread.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -173,7 +173,9 @@ public class InterceptNetworkRequests {
|
||||
|
||||
## Documentation
|
||||
|
||||
We are in the process of converting our documentation from the Node.js form to [Javadocs](https://www.javadoc.io/doc/com.microsoft.playwright/playwright/latest/index.html). You can go ahead and use the Node.js [documentation](https://playwright.dev/) since the API is pretty much the same.
|
||||
Check out our [new documentation site](https://playwright.dev/java)!.
|
||||
|
||||
You can also browse [javadoc online](https://www.javadoc.io/doc/com.microsoft.playwright/playwright/latest/index.html).
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -181,6 +183,4 @@ Follow [the instructions](https://github.com/microsoft/playwright-java/blob/mast
|
||||
|
||||
## Is Playwright for Java ready?
|
||||
|
||||
Yes, Playwright for Java is ready. We are still not at the version v1.0, so breaking API changes could potentially happen. But a) this is unlikely and b) we will only do that if we know it improves your experience with the new library. We'd like to collect your feedback before we freeze the API for v1.0.
|
||||
|
||||
> Note: We don't yet support some of the edge-cases of the vendor-specific APIs such as collecting Chromium trace, coverage report, etc.
|
||||
Yes, Playwright for Java is ready. v1.10.0 is the first stable release. Going forward we will adhere to [semantic versioning](https://semver.org/) of the API.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>0.190.0-SNAPSHOT</version>
|
||||
<version>1.11.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>driver-bundle</artifactId>
|
||||
@@ -44,7 +44,9 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0-M5</version>
|
||||
<configuration>
|
||||
<redirectTestOutputToFile>true</redirectTestOutputToFile>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
@@ -48,6 +48,9 @@ public class DriverJar extends Driver {
|
||||
p.destroy();
|
||||
throw new RuntimeException("Timed out waiting for browsers to install");
|
||||
}
|
||||
if (p.exitValue() != 0) {
|
||||
throw new RuntimeException("Failed to install browsers, exit code: " + p.exitValue());
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isExecutable(Path filePath) {
|
||||
@@ -57,7 +60,9 @@ public class DriverJar extends Driver {
|
||||
|
||||
private void extractDriverToTempDir() throws URISyntaxException, IOException {
|
||||
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
|
||||
URI uri = classloader.getResource("driver/" + platformDir()).toURI();
|
||||
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()) ? FileSystems.newFileSystem(uri, Collections.emptyMap()) : null) {
|
||||
Path srcRoot = Paths.get(uri);
|
||||
@@ -80,12 +85,34 @@ public class DriverJar extends Driver {
|
||||
}
|
||||
toPath.toFile().deleteOnExit();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to extract driver from " + uri, e);
|
||||
throw new RuntimeException("Failed to extract driver from " + uri + ", full uri: " + originalUri, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private URI maybeExtractNestedJar(final URI uri) throws URISyntaxException {
|
||||
if (!"jar".equals(uri.getScheme())) {
|
||||
return uri;
|
||||
}
|
||||
final String JAR_URL_SEPARATOR = "!/";
|
||||
String[] parts = uri.toString().split("!/");
|
||||
if (parts.length != 3) {
|
||||
return uri;
|
||||
}
|
||||
String innerJar = String.join(JAR_URL_SEPARATOR, parts[0], parts[1]);
|
||||
URI jarUri = new URI(innerJar);
|
||||
try (FileSystem fs = FileSystems.newFileSystem(jarUri, Collections.emptyMap())) {
|
||||
Path fromPath = Paths.get(jarUri);
|
||||
Path toPath = driverTempDir.resolve(fromPath.getFileName().toString());
|
||||
Files.copy(fromPath, toPath);
|
||||
toPath.toFile().deleteOnExit();
|
||||
return new URI("jar:" + toPath.toUri() + JAR_URL_SEPARATOR + parts[2]);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to extract driver's nested .jar from " + jarUri + "; full uri: " + uri, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String platformDir() {
|
||||
String name = System.getProperty("os.name").toLowerCase();
|
||||
if (name.contains("windows")) {
|
||||
|
||||
+4
-1
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>0.190.0-SNAPSHOT</version>
|
||||
<version>1.11.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>driver</artifactId>
|
||||
@@ -40,6 +40,9 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<redirectTestOutputToFile>true</redirectTestOutputToFile>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>org.example</groupId>
|
||||
<artifactId>examples</artifactId>
|
||||
<version>0.1-SNAPSHOT</version>
|
||||
<version>1.11.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>0.190.0-SNAPSHOT</version>
|
||||
<version>1.9.1-alpha-0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>0.190.0-SNAPSHOT</version>
|
||||
<version>1.11.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>playwright</artifactId>
|
||||
|
||||
@@ -66,7 +66,7 @@ public interface Browser extends AutoCloseable {
|
||||
public Boolean bypassCSP;
|
||||
/**
|
||||
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code "no-preference"}. See
|
||||
* {@link Page#emulateMedia Page.emulateMedia()} for more details. Defaults to '{@code light}'.
|
||||
* {@link Page#emulateMedia Page.emulateMedia()} for more details. Defaults to {@code "light"}.
|
||||
*/
|
||||
public ColorScheme colorScheme;
|
||||
/**
|
||||
@@ -114,9 +114,11 @@ public interface Browser extends AutoCloseable {
|
||||
*/
|
||||
public List<String> permissions;
|
||||
/**
|
||||
* Network proxy settings to use with this context. Note that browser needs to be launched with the global proxy for this
|
||||
* option to work. If all contexts override the proxy, global proxy will be never used and can be any string, for example
|
||||
* {@code launch({ proxy: { server: 'per-context' } })}.
|
||||
* Network proxy settings to use with this context.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> For Chromium on Windows the browser needs to be launched with the global proxy for this option to work. If all contexts
|
||||
* override the proxy, global proxy will be never used and can be any string, for example {@code launch({ proxy: { server:
|
||||
* 'http://per-context' } })}.
|
||||
*/
|
||||
public Proxy proxy;
|
||||
/**
|
||||
@@ -124,11 +126,14 @@ public interface Browser extends AutoCloseable {
|
||||
*/
|
||||
public Boolean recordHarOmitContent;
|
||||
/**
|
||||
* Path on the filesystem to write the HAR file to.
|
||||
* Enables <a href="http://www.softwareishard.com/blog/har-12-spec">HAR</a> recording for all pages into the specified HAR
|
||||
* file on the filesystem. If not specified, the HAR is not recorded. Make sure to call {@link BrowserContext#close
|
||||
* BrowserContext.close()} for the HAR to be saved.
|
||||
*/
|
||||
public Path recordHarPath;
|
||||
/**
|
||||
* Path to the directory to put videos into.
|
||||
* Enables video recording for all pages into the specified directory. If not specified videos are not recorded. Make sure
|
||||
* to call {@link BrowserContext#close BrowserContext.close()} for videos to be saved.
|
||||
*/
|
||||
public Path recordVideoDir;
|
||||
/**
|
||||
@@ -137,6 +142,11 @@ public interface Browser extends AutoCloseable {
|
||||
* be scaled down if necessary to fit the specified size.
|
||||
*/
|
||||
public RecordVideoSize recordVideoSize;
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* Populates context with given storage state. This option can be used to initialize context with logged-in information
|
||||
* obtained via {@link BrowserContext#storageState BrowserContext.storageState()}.
|
||||
@@ -159,7 +169,7 @@ public interface Browser extends AutoCloseable {
|
||||
*/
|
||||
public String userAgent;
|
||||
/**
|
||||
* Sets a consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default viewport.
|
||||
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default viewport.
|
||||
*/
|
||||
public Optional<ViewportSize> viewportSize;
|
||||
|
||||
@@ -251,6 +261,13 @@ public interface Browser extends AutoCloseable {
|
||||
this.recordVideoSize = recordVideoSize;
|
||||
return this;
|
||||
}
|
||||
public NewContextOptions setScreenSize(int width, int height) {
|
||||
return setScreenSize(new ScreenSize(width, height));
|
||||
}
|
||||
public NewContextOptions setScreenSize(ScreenSize screenSize) {
|
||||
this.screenSize = screenSize;
|
||||
return this;
|
||||
}
|
||||
public NewContextOptions setStorageState(String storageState) {
|
||||
this.storageState = storageState;
|
||||
return this;
|
||||
@@ -286,7 +303,7 @@ public interface Browser extends AutoCloseable {
|
||||
public Boolean bypassCSP;
|
||||
/**
|
||||
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code "no-preference"}. See
|
||||
* {@link Page#emulateMedia Page.emulateMedia()} for more details. Defaults to '{@code light}'.
|
||||
* {@link Page#emulateMedia Page.emulateMedia()} for more details. Defaults to {@code "light"}.
|
||||
*/
|
||||
public ColorScheme colorScheme;
|
||||
/**
|
||||
@@ -334,9 +351,11 @@ public interface Browser extends AutoCloseable {
|
||||
*/
|
||||
public List<String> permissions;
|
||||
/**
|
||||
* Network proxy settings to use with this context. Note that browser needs to be launched with the global proxy for this
|
||||
* option to work. If all contexts override the proxy, global proxy will be never used and can be any string, for example
|
||||
* {@code launch({ proxy: { server: 'per-context' } })}.
|
||||
* Network proxy settings to use with this context.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> For Chromium on Windows the browser needs to be launched with the global proxy for this option to work. If all contexts
|
||||
* override the proxy, global proxy will be never used and can be any string, for example {@code launch({ proxy: { server:
|
||||
* 'http://per-context' } })}.
|
||||
*/
|
||||
public Proxy proxy;
|
||||
/**
|
||||
@@ -344,11 +363,14 @@ public interface Browser extends AutoCloseable {
|
||||
*/
|
||||
public Boolean recordHarOmitContent;
|
||||
/**
|
||||
* Path on the filesystem to write the HAR file to.
|
||||
* Enables <a href="http://www.softwareishard.com/blog/har-12-spec">HAR</a> recording for all pages into the specified HAR
|
||||
* file on the filesystem. If not specified, the HAR is not recorded. Make sure to call {@link BrowserContext#close
|
||||
* BrowserContext.close()} for the HAR to be saved.
|
||||
*/
|
||||
public Path recordHarPath;
|
||||
/**
|
||||
* Path to the directory to put videos into.
|
||||
* Enables video recording for all pages into the specified directory. If not specified videos are not recorded. Make sure
|
||||
* to call {@link BrowserContext#close BrowserContext.close()} for videos to be saved.
|
||||
*/
|
||||
public Path recordVideoDir;
|
||||
/**
|
||||
@@ -357,6 +379,11 @@ public interface Browser extends AutoCloseable {
|
||||
* be scaled down if necessary to fit the specified size.
|
||||
*/
|
||||
public RecordVideoSize recordVideoSize;
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* Populates context with given storage state. This option can be used to initialize context with logged-in information
|
||||
* obtained via {@link BrowserContext#storageState BrowserContext.storageState()}.
|
||||
@@ -379,7 +406,7 @@ public interface Browser extends AutoCloseable {
|
||||
*/
|
||||
public String userAgent;
|
||||
/**
|
||||
* Sets a consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default viewport.
|
||||
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default viewport.
|
||||
*/
|
||||
public Optional<ViewportSize> viewportSize;
|
||||
|
||||
@@ -471,6 +498,13 @@ public interface Browser extends AutoCloseable {
|
||||
this.recordVideoSize = recordVideoSize;
|
||||
return this;
|
||||
}
|
||||
public NewPageOptions setScreenSize(int width, int height) {
|
||||
return setScreenSize(new ScreenSize(width, height));
|
||||
}
|
||||
public NewPageOptions setScreenSize(ScreenSize screenSize) {
|
||||
this.screenSize = screenSize;
|
||||
return this;
|
||||
}
|
||||
public NewPageOptions setStorageState(String storageState) {
|
||||
this.storageState = storageState;
|
||||
return this;
|
||||
@@ -495,6 +529,33 @@ public interface Browser extends AutoCloseable {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class StartTracingOptions {
|
||||
/**
|
||||
* specify custom categories to use instead of default.
|
||||
*/
|
||||
public List<String> categories;
|
||||
/**
|
||||
* A path to write the trace file to.
|
||||
*/
|
||||
public Path path;
|
||||
/**
|
||||
* captures screenshots in the trace.
|
||||
*/
|
||||
public Boolean screenshots;
|
||||
|
||||
public StartTracingOptions setCategories(List<String> categories) {
|
||||
this.categories = categories;
|
||||
return this;
|
||||
}
|
||||
public StartTracingOptions setPath(Path path) {
|
||||
this.path = path;
|
||||
return this;
|
||||
}
|
||||
public StartTracingOptions setScreenshots(boolean screenshots) {
|
||||
this.screenshots = screenshots;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* In case this browser is obtained using {@link BrowserType#launch BrowserType.launch()}, closes the browser and all of
|
||||
* its pages (if any were opened).
|
||||
@@ -563,6 +624,59 @@ public interface Browser extends AutoCloseable {
|
||||
* BrowserContext#newPage BrowserContext.newPage()} to control their exact life times.
|
||||
*/
|
||||
Page newPage(NewPageOptions options);
|
||||
/**
|
||||
* <strong>NOTE:</strong> Tracing is only supported on Chromium-based browsers.
|
||||
*
|
||||
* <p> You can use {@link Browser#startTracing Browser.startTracing()} and {@link Browser#stopTracing Browser.stopTracing()} to
|
||||
* create a trace file that can be opened in Chrome DevTools performance panel.
|
||||
* <pre>{@code
|
||||
* browser.startTracing(page, new Browser.StartTracingOptions()
|
||||
* .setPath(Paths.get("trace.json")));
|
||||
* page.goto('https://www.google.com');
|
||||
* browser.stopTracing();
|
||||
* }</pre>
|
||||
*
|
||||
* @param page Optional, if specified, tracing includes screenshots of the given page.
|
||||
*/
|
||||
default void startTracing(Page page) {
|
||||
startTracing(page, null);
|
||||
}
|
||||
/**
|
||||
* <strong>NOTE:</strong> Tracing is only supported on Chromium-based browsers.
|
||||
*
|
||||
* <p> You can use {@link Browser#startTracing Browser.startTracing()} and {@link Browser#stopTracing Browser.stopTracing()} to
|
||||
* create a trace file that can be opened in Chrome DevTools performance panel.
|
||||
* <pre>{@code
|
||||
* browser.startTracing(page, new Browser.StartTracingOptions()
|
||||
* .setPath(Paths.get("trace.json")));
|
||||
* page.goto('https://www.google.com');
|
||||
* browser.stopTracing();
|
||||
* }</pre>
|
||||
*/
|
||||
default void startTracing() {
|
||||
startTracing(null);
|
||||
}
|
||||
/**
|
||||
* <strong>NOTE:</strong> Tracing is only supported on Chromium-based browsers.
|
||||
*
|
||||
* <p> You can use {@link Browser#startTracing Browser.startTracing()} and {@link Browser#stopTracing Browser.stopTracing()} to
|
||||
* create a trace file that can be opened in Chrome DevTools performance panel.
|
||||
* <pre>{@code
|
||||
* browser.startTracing(page, new Browser.StartTracingOptions()
|
||||
* .setPath(Paths.get("trace.json")));
|
||||
* page.goto('https://www.google.com');
|
||||
* browser.stopTracing();
|
||||
* }</pre>
|
||||
*
|
||||
* @param page Optional, if specified, tracing includes screenshots of the given page.
|
||||
*/
|
||||
void startTracing(Page page, StartTracingOptions options);
|
||||
/**
|
||||
* <strong>NOTE:</strong> Tracing is only supported on Chromium-based browsers.
|
||||
*
|
||||
* <p> Returns the buffer with trace data.
|
||||
*/
|
||||
byte[] stopTracing();
|
||||
/**
|
||||
* Returns the browser version.
|
||||
*/
|
||||
|
||||
@@ -470,7 +470,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* Routing provides the capability to modify network requests that are made by any page in the browser context. Once route
|
||||
* is enabled, every request matching the url pattern will stall unless it's continued, fulfilled or aborted.
|
||||
*
|
||||
* <p> An example of a naïve handler that aborts all image requests:
|
||||
* <p> An example of a naive handler that aborts all image requests:
|
||||
* <pre>{@code
|
||||
* BrowserContext context = browser.newContext();
|
||||
* context.route("**\/*.{png,jpg,jpeg}", route -> route.abort());
|
||||
@@ -488,9 +488,22 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* browser.close();
|
||||
* }</pre>
|
||||
*
|
||||
* <p> It is possible to examine the request to decide the route action. For example, mocking all requests that contain some
|
||||
* post data, and leaving all other requests as is:
|
||||
* <pre>{@code
|
||||
* context.route("/api/**", route -> {
|
||||
* if (route.request().postData().contains("my-string"))
|
||||
* route.fulfill(new Route.FulfillOptions().setBody("mocked-data"));
|
||||
* else
|
||||
* route.resume();
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Page routes (set up with {@link Page#route Page.route()}) take precedence over browser context routes when request
|
||||
* matches both handlers.
|
||||
*
|
||||
* <p> To remove a route with its handler you can use {@link BrowserContext#unroute BrowserContext.unroute()}.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
|
||||
*
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing.
|
||||
@@ -501,7 +514,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* Routing provides the capability to modify network requests that are made by any page in the browser context. Once route
|
||||
* is enabled, every request matching the url pattern will stall unless it's continued, fulfilled or aborted.
|
||||
*
|
||||
* <p> An example of a naïve handler that aborts all image requests:
|
||||
* <p> An example of a naive handler that aborts all image requests:
|
||||
* <pre>{@code
|
||||
* BrowserContext context = browser.newContext();
|
||||
* context.route("**\/*.{png,jpg,jpeg}", route -> route.abort());
|
||||
@@ -519,9 +532,22 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* browser.close();
|
||||
* }</pre>
|
||||
*
|
||||
* <p> It is possible to examine the request to decide the route action. For example, mocking all requests that contain some
|
||||
* post data, and leaving all other requests as is:
|
||||
* <pre>{@code
|
||||
* context.route("/api/**", route -> {
|
||||
* if (route.request().postData().contains("my-string"))
|
||||
* route.fulfill(new Route.FulfillOptions().setBody("mocked-data"));
|
||||
* else
|
||||
* route.resume();
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Page routes (set up with {@link Page#route Page.route()}) take precedence over browser context routes when request
|
||||
* matches both handlers.
|
||||
*
|
||||
* <p> To remove a route with its handler you can use {@link BrowserContext#unroute BrowserContext.unroute()}.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
|
||||
*
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing.
|
||||
@@ -532,7 +558,7 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* Routing provides the capability to modify network requests that are made by any page in the browser context. Once route
|
||||
* is enabled, every request matching the url pattern will stall unless it's continued, fulfilled or aborted.
|
||||
*
|
||||
* <p> An example of a naïve handler that aborts all image requests:
|
||||
* <p> An example of a naive handler that aborts all image requests:
|
||||
* <pre>{@code
|
||||
* BrowserContext context = browser.newContext();
|
||||
* context.route("**\/*.{png,jpg,jpeg}", route -> route.abort());
|
||||
@@ -550,9 +576,22 @@ public interface BrowserContext extends AutoCloseable {
|
||||
* browser.close();
|
||||
* }</pre>
|
||||
*
|
||||
* <p> It is possible to examine the request to decide the route action. For example, mocking all requests that contain some
|
||||
* post data, and leaving all other requests as is:
|
||||
* <pre>{@code
|
||||
* context.route("/api/**", route -> {
|
||||
* if (route.request().postData().contains("my-string"))
|
||||
* route.fulfill(new Route.FulfillOptions().setBody("mocked-data"));
|
||||
* else
|
||||
* route.resume();
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* <p> Page routes (set up with {@link Page#route Page.route()}) take precedence over browser context routes when request
|
||||
* matches both handlers.
|
||||
*
|
||||
* <p> To remove a route with its handler you can use {@link BrowserContext#unroute BrowserContext.unroute()}.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Enabling routing disables http cache.
|
||||
*
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while routing.
|
||||
|
||||
@@ -42,6 +42,10 @@ import java.util.*;
|
||||
*/
|
||||
public interface BrowserType {
|
||||
class ConnectOptions {
|
||||
/**
|
||||
* Additional HTTP headers to be sent with web socket connect request. Optional.
|
||||
*/
|
||||
public Map<String, String> headers;
|
||||
/**
|
||||
* Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going on.
|
||||
* Defaults to 0.
|
||||
@@ -53,6 +57,10 @@ public interface BrowserType {
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
public ConnectOptions setHeaders(Map<String, String> headers) {
|
||||
this.headers = headers;
|
||||
return this;
|
||||
}
|
||||
public ConnectOptions setSlowMo(double slowMo) {
|
||||
this.slowMo = slowMo;
|
||||
return this;
|
||||
@@ -62,12 +70,46 @@ public interface BrowserType {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class ConnectOverCDPOptions {
|
||||
/**
|
||||
* Additional HTTP headers to be sent with connect request. Optional.
|
||||
*/
|
||||
public Map<String, String> headers;
|
||||
/**
|
||||
* Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going on.
|
||||
* Defaults to 0.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public Double timeout;
|
||||
|
||||
public ConnectOverCDPOptions setHeaders(Map<String, String> headers) {
|
||||
this.headers = headers;
|
||||
return this;
|
||||
}
|
||||
public ConnectOverCDPOptions setSlowMo(double slowMo) {
|
||||
this.slowMo = slowMo;
|
||||
return this;
|
||||
}
|
||||
public ConnectOverCDPOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class LaunchOptions {
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* Browser distribution channel. Read more about using <a
|
||||
* href="https://playwright.dev/java/docs/browsers/#google-chrome--microsoft-edge">Google Chrome and Microsoft Edge</a>.
|
||||
*/
|
||||
public BrowserChannel channel;
|
||||
/**
|
||||
* Enable Chromium sandboxing. Defaults to {@code false}.
|
||||
*/
|
||||
@@ -144,6 +186,10 @@ public interface BrowserType {
|
||||
this.args = args;
|
||||
return this;
|
||||
}
|
||||
public LaunchOptions setChannel(BrowserChannel channel) {
|
||||
this.channel = channel;
|
||||
return this;
|
||||
}
|
||||
public LaunchOptions setChromiumSandbox(boolean chromiumSandbox) {
|
||||
this.chromiumSandbox = chromiumSandbox;
|
||||
return this;
|
||||
@@ -222,13 +268,18 @@ public interface BrowserType {
|
||||
* Toggles bypassing page's Content-Security-Policy.
|
||||
*/
|
||||
public Boolean bypassCSP;
|
||||
/**
|
||||
* Browser distribution channel. Read more about using <a
|
||||
* href="https://playwright.dev/java/docs/browsers/#google-chrome--microsoft-edge">Google Chrome and Microsoft Edge</a>.
|
||||
*/
|
||||
public BrowserChannel channel;
|
||||
/**
|
||||
* Enable Chromium sandboxing. Defaults to {@code true}.
|
||||
*/
|
||||
public Boolean chromiumSandbox;
|
||||
/**
|
||||
* Emulates {@code "prefers-colors-scheme"} media feature, supported values are {@code "light"}, {@code "dark"}, {@code "no-preference"}. See
|
||||
* {@link Page#emulateMedia Page.emulateMedia()} for more details. Defaults to '{@code light}'.
|
||||
* {@link Page#emulateMedia Page.emulateMedia()} for more details. Defaults to {@code "light"}.
|
||||
*/
|
||||
public ColorScheme colorScheme;
|
||||
/**
|
||||
@@ -333,11 +384,14 @@ public interface BrowserType {
|
||||
*/
|
||||
public Boolean recordHarOmitContent;
|
||||
/**
|
||||
* Path on the filesystem to write the HAR file to.
|
||||
* Enables <a href="http://www.softwareishard.com/blog/har-12-spec">HAR</a> recording for all pages into the specified HAR
|
||||
* file on the filesystem. If not specified, the HAR is not recorded. Make sure to call {@link BrowserContext#close
|
||||
* BrowserContext.close()} for the HAR to be saved.
|
||||
*/
|
||||
public Path recordHarPath;
|
||||
/**
|
||||
* Path to the directory to put videos into.
|
||||
* Enables video recording for all pages into the specified directory. If not specified videos are not recorded. Make sure
|
||||
* to call {@link BrowserContext#close BrowserContext.close()} for videos to be saved.
|
||||
*/
|
||||
public Path recordVideoDir;
|
||||
/**
|
||||
@@ -346,6 +400,11 @@ public interface BrowserType {
|
||||
* be scaled down if necessary to fit the specified size.
|
||||
*/
|
||||
public RecordVideoSize recordVideoSize;
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* Slows down Playwright operations by the specified amount of milliseconds. Useful so that you can see what is going on.
|
||||
* Defaults to 0.
|
||||
@@ -367,7 +426,7 @@ public interface BrowserType {
|
||||
*/
|
||||
public String userAgent;
|
||||
/**
|
||||
* Sets a consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default viewport.
|
||||
* Emulates consistent viewport for each page. Defaults to an 1280x720 viewport. {@code null} disables the default viewport.
|
||||
*/
|
||||
public Optional<ViewportSize> viewportSize;
|
||||
|
||||
@@ -383,6 +442,10 @@ public interface BrowserType {
|
||||
this.bypassCSP = bypassCSP;
|
||||
return this;
|
||||
}
|
||||
public LaunchPersistentContextOptions setChannel(BrowserChannel channel) {
|
||||
this.channel = channel;
|
||||
return this;
|
||||
}
|
||||
public LaunchPersistentContextOptions setChromiumSandbox(boolean chromiumSandbox) {
|
||||
this.chromiumSandbox = chromiumSandbox;
|
||||
return this;
|
||||
@@ -507,6 +570,13 @@ public interface BrowserType {
|
||||
this.recordVideoSize = recordVideoSize;
|
||||
return this;
|
||||
}
|
||||
public LaunchPersistentContextOptions setScreenSize(int width, int height) {
|
||||
return setScreenSize(new ScreenSize(width, height));
|
||||
}
|
||||
public LaunchPersistentContextOptions setScreenSize(ScreenSize screenSize) {
|
||||
this.screenSize = screenSize;
|
||||
return this;
|
||||
}
|
||||
public LaunchPersistentContextOptions setSlowMo(double slowMo) {
|
||||
this.slowMo = slowMo;
|
||||
return this;
|
||||
@@ -545,6 +615,30 @@ public interface BrowserType {
|
||||
* @param wsEndpoint A browser websocket endpoint to connect to.
|
||||
*/
|
||||
Browser connect(String wsEndpoint, ConnectOptions options);
|
||||
/**
|
||||
* This methods attaches Playwright to an existing browser instance using the Chrome DevTools Protocol.
|
||||
*
|
||||
* <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.
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
/**
|
||||
* This methods attaches Playwright to an existing browser instance using the Chrome DevTools Protocol.
|
||||
*
|
||||
* <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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
|
||||
@@ -22,11 +22,17 @@ import java.util.*;
|
||||
* {@code ConsoleMessage} objects are dispatched by page via the {@link Page#onConsole Page.onConsole()} event.
|
||||
*/
|
||||
public interface ConsoleMessage {
|
||||
/**
|
||||
* List of arguments passed to a {@code console} function call. See also {@link Page#onConsole Page.onConsole()}.
|
||||
*/
|
||||
List<JSHandle> args();
|
||||
/**
|
||||
* URL of the resource followed by 0-based line and column numbers in the resource formatted as {@code URL:line:column}.
|
||||
*/
|
||||
String location();
|
||||
/**
|
||||
* The text of the console message.
|
||||
*/
|
||||
String text();
|
||||
/**
|
||||
* One of the following values: {@code "log"}, {@code "debug"}, {@code "info"}, {@code "error"}, {@code "warning"}, {@code "dir"}, {@code "dirxml"}, {@code "table"},
|
||||
|
||||
@@ -29,7 +29,7 @@ import java.util.*;
|
||||
* <p> Download event is emitted once the download starts. Download path becomes available once download completes:
|
||||
* <pre>{@code
|
||||
* // wait for download to start
|
||||
* Download download = page.waitForDownload(() -> page.click("a"));
|
||||
* Download download = page.waitForDownload(() -> page.click("a"));
|
||||
* // wait for download to complete
|
||||
* Path path = download.path();
|
||||
* }</pre>
|
||||
@@ -52,19 +52,20 @@ public interface Download {
|
||||
*/
|
||||
InputStream createReadStream();
|
||||
/**
|
||||
* Deletes the downloaded file.
|
||||
* Deletes the downloaded file. Will wait for the download to finish if necessary.
|
||||
*/
|
||||
void delete();
|
||||
/**
|
||||
* Returns download error if any.
|
||||
* Returns download error if any. Will wait for the download to finish if necessary.
|
||||
*/
|
||||
String failure();
|
||||
/**
|
||||
* Returns path to the downloaded file in case of successful download.
|
||||
* 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.
|
||||
*/
|
||||
Path path();
|
||||
/**
|
||||
* Saves the download to a user-specified path.
|
||||
* Saves the download to a user-specified path. It is safe to call this method while the download is still in progress.
|
||||
*
|
||||
* @param path Path where the download should be saved.
|
||||
*/
|
||||
|
||||
@@ -60,12 +60,23 @@ public interface ElementHandle extends JSHandle {
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
* A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of the
|
||||
* element.
|
||||
*/
|
||||
public Position position;
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* When set, this method only performs the <a href="https://playwright.dev/java/docs/actionability/">actionability</a>
|
||||
* checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
|
||||
* performing it.
|
||||
*/
|
||||
public Boolean trial;
|
||||
|
||||
public CheckOptions setForce(boolean force) {
|
||||
this.force = force;
|
||||
@@ -75,10 +86,21 @@ public interface ElementHandle extends JSHandle {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
return this;
|
||||
}
|
||||
public CheckOptions setPosition(double x, double y) {
|
||||
return setPosition(new Position(x, y));
|
||||
}
|
||||
public CheckOptions setPosition(Position position) {
|
||||
this.position = position;
|
||||
return this;
|
||||
}
|
||||
public CheckOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
public CheckOptions setTrial(boolean trial) {
|
||||
this.trial = trial;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class ClickOptions {
|
||||
/**
|
||||
@@ -120,6 +142,12 @@ public interface ElementHandle extends JSHandle {
|
||||
* Page.setDefaultTimeout()} methods.
|
||||
*/
|
||||
public Double timeout;
|
||||
/**
|
||||
* When set, this method only performs the <a href="https://playwright.dev/java/docs/actionability/">actionability</a>
|
||||
* checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
|
||||
* performing it.
|
||||
*/
|
||||
public Boolean trial;
|
||||
|
||||
public ClickOptions setButton(MouseButton button) {
|
||||
this.button = button;
|
||||
@@ -156,6 +184,10 @@ public interface ElementHandle extends JSHandle {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
public ClickOptions setTrial(boolean trial) {
|
||||
this.trial = trial;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class DblclickOptions {
|
||||
/**
|
||||
@@ -193,6 +225,12 @@ public interface ElementHandle extends JSHandle {
|
||||
* Page.setDefaultTimeout()} methods.
|
||||
*/
|
||||
public Double timeout;
|
||||
/**
|
||||
* When set, this method only performs the <a href="https://playwright.dev/java/docs/actionability/">actionability</a>
|
||||
* checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
|
||||
* performing it.
|
||||
*/
|
||||
public Boolean trial;
|
||||
|
||||
public DblclickOptions setButton(MouseButton button) {
|
||||
this.button = button;
|
||||
@@ -225,6 +263,10 @@ public interface ElementHandle extends JSHandle {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
public DblclickOptions setTrial(boolean trial) {
|
||||
this.trial = trial;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class FillOptions {
|
||||
/**
|
||||
@@ -271,6 +313,12 @@ public interface ElementHandle extends JSHandle {
|
||||
* Page.setDefaultTimeout()} methods.
|
||||
*/
|
||||
public Double timeout;
|
||||
/**
|
||||
* When set, this method only performs the <a href="https://playwright.dev/java/docs/actionability/">actionability</a>
|
||||
* checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
|
||||
* performing it.
|
||||
*/
|
||||
public Boolean trial;
|
||||
|
||||
public HoverOptions setForce(boolean force) {
|
||||
this.force = force;
|
||||
@@ -291,6 +339,10 @@ public interface ElementHandle extends JSHandle {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
public HoverOptions setTrial(boolean trial) {
|
||||
this.trial = trial;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class PressOptions {
|
||||
/**
|
||||
@@ -471,6 +523,12 @@ public interface ElementHandle extends JSHandle {
|
||||
* Page.setDefaultTimeout()} methods.
|
||||
*/
|
||||
public Double timeout;
|
||||
/**
|
||||
* When set, this method only performs the <a href="https://playwright.dev/java/docs/actionability/">actionability</a>
|
||||
* checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
|
||||
* performing it.
|
||||
*/
|
||||
public Boolean trial;
|
||||
|
||||
public TapOptions setForce(boolean force) {
|
||||
this.force = force;
|
||||
@@ -495,6 +553,10 @@ public interface ElementHandle extends JSHandle {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
public TapOptions setTrial(boolean trial) {
|
||||
this.trial = trial;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class TypeOptions {
|
||||
/**
|
||||
@@ -539,12 +601,23 @@ public interface ElementHandle extends JSHandle {
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
* A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of the
|
||||
* element.
|
||||
*/
|
||||
public Position position;
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* When set, this method only performs the <a href="https://playwright.dev/java/docs/actionability/">actionability</a>
|
||||
* checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
|
||||
* performing it.
|
||||
*/
|
||||
public Boolean trial;
|
||||
|
||||
public UncheckOptions setForce(boolean force) {
|
||||
this.force = force;
|
||||
@@ -554,10 +627,21 @@ public interface ElementHandle extends JSHandle {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
return this;
|
||||
}
|
||||
public UncheckOptions setPosition(double x, double y) {
|
||||
return setPosition(new Position(x, y));
|
||||
}
|
||||
public UncheckOptions setPosition(Position position) {
|
||||
this.position = position;
|
||||
return this;
|
||||
}
|
||||
public UncheckOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
public UncheckOptions setTrial(boolean trial) {
|
||||
this.trial = trial;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class WaitForElementStateOptions {
|
||||
/**
|
||||
@@ -623,20 +707,20 @@ public interface ElementHandle extends JSHandle {
|
||||
/**
|
||||
* This method checks the element by performing the following steps:
|
||||
* <ol>
|
||||
* <li> Ensure that element is a checkbox or a radio input. If not, this method rejects. If the element is already checked, this
|
||||
* <li> Ensure that element is a checkbox or a radio input. If not, this method throws. If the element is already checked, this
|
||||
* method returns immediately.</li>
|
||||
* <li> Wait for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks on the element, unless
|
||||
* {@code force} option is set.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link Page#mouse Page.mouse()} to click in the center of the element.</li>
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set.</li>
|
||||
* <li> Ensure that the element is now checked. If not, this method rejects.</li>
|
||||
* <li> Ensure that the element is now checked. If not, this method throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method rejects.
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*/
|
||||
default void check() {
|
||||
check(null);
|
||||
@@ -644,20 +728,20 @@ public interface ElementHandle extends JSHandle {
|
||||
/**
|
||||
* This method checks the element by performing the following steps:
|
||||
* <ol>
|
||||
* <li> Ensure that element is a checkbox or a radio input. If not, this method rejects. If the element is already checked, this
|
||||
* <li> Ensure that element is a checkbox or a radio input. If not, this method throws. If the element is already checked, this
|
||||
* method returns immediately.</li>
|
||||
* <li> Wait for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks on the element, unless
|
||||
* {@code force} option is set.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link Page#mouse Page.mouse()} to click in the center of the element.</li>
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set.</li>
|
||||
* <li> Ensure that the element is now checked. If not, this method rejects.</li>
|
||||
* <li> Ensure that the element is now checked. If not, this method throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method rejects.
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*/
|
||||
void check(CheckOptions options);
|
||||
/**
|
||||
@@ -670,10 +754,10 @@ public interface ElementHandle extends JSHandle {
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method rejects.
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*/
|
||||
default void click() {
|
||||
click(null);
|
||||
@@ -688,10 +772,10 @@ public interface ElementHandle extends JSHandle {
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method rejects.
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*/
|
||||
void click(ClickOptions options);
|
||||
/**
|
||||
@@ -706,13 +790,13 @@ public interface ElementHandle extends JSHandle {
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link Page#mouse Page.mouse()} to double click in the center of the element, or the specified {@code position}.</li>
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set. Note that if the first
|
||||
* click of the {@code dblclick()} triggers a navigation event, this method will reject.</li>
|
||||
* click of the {@code dblclick()} triggers a navigation event, this method will throw.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method rejects.
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> {@code elementHandle.dblclick()} dispatches two {@code click} events and a single {@code dblclick} event.
|
||||
*/
|
||||
@@ -727,20 +811,20 @@ public interface ElementHandle extends JSHandle {
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link Page#mouse Page.mouse()} to double click in the center of the element, or the specified {@code position}.</li>
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set. Note that if the first
|
||||
* click of the {@code dblclick()} triggers a navigation event, this method will reject.</li>
|
||||
* click of the {@code dblclick()} triggers a navigation event, this method will throw.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method rejects.
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> {@code elementHandle.dblclick()} dispatches two {@code click} events and a single {@code dblclick} event.
|
||||
*/
|
||||
void dblclick(DblclickOptions options);
|
||||
/**
|
||||
* The snippet below dispatches the {@code click} event on the element. Regardless of the visibility state of the elment, {@code click}
|
||||
* is dispatched. This is equivalend to calling <a
|
||||
* The snippet below dispatches the {@code click} event on the element. Regardless of the visibility state of the element,
|
||||
* {@code click} is dispatched. This is equivalent to calling <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click">element.click()</a>.
|
||||
* <pre>{@code
|
||||
* elementHandle.dispatchEvent("click");
|
||||
@@ -775,8 +859,8 @@ public interface ElementHandle extends JSHandle {
|
||||
dispatchEvent(type, null);
|
||||
}
|
||||
/**
|
||||
* The snippet below dispatches the {@code click} event on the element. Regardless of the visibility state of the elment, {@code click}
|
||||
* is dispatched. This is equivalend to calling <a
|
||||
* The snippet below dispatches the {@code click} event on the element. Regardless of the visibility state of the element,
|
||||
* {@code click} is dispatched. This is equivalent to calling <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click">element.click()</a>.
|
||||
* <pre>{@code
|
||||
* elementHandle.dispatchEvent("click");
|
||||
@@ -913,10 +997,15 @@ public interface ElementHandle extends JSHandle {
|
||||
Object evalOnSelectorAll(String selector, String expression, Object arg);
|
||||
/**
|
||||
* This method waits for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, focuses the
|
||||
* element, fills it and triggers an {@code input} event after filling. If the element is inside the {@code <label>} element that has
|
||||
* associated <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, that control
|
||||
* will be filled instead. If the element to be filled is not an {@code <input>}, {@code <textarea>} or {@code [contenteditable]} element,
|
||||
* this method throws an error. Note that you can pass an empty string to clear the input field.
|
||||
* element, fills it and triggers an {@code input} event after filling. Note that you can pass an empty string to clear the input
|
||||
* field.
|
||||
*
|
||||
* <p> If the target element is not an {@code <input>}, {@code <textarea>} or {@code [contenteditable]} element, this method throws an error.
|
||||
* However, if the element is inside the {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be filled
|
||||
* instead.
|
||||
*
|
||||
* <p> To send fine-grained keyboard events, use {@link ElementHandle#type ElementHandle.type()}.
|
||||
*
|
||||
* @param value Value to set for the {@code <input>}, {@code <textarea>} or {@code [contenteditable]} element.
|
||||
*/
|
||||
@@ -925,10 +1014,15 @@ public interface ElementHandle extends JSHandle {
|
||||
}
|
||||
/**
|
||||
* This method waits for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, focuses the
|
||||
* element, fills it and triggers an {@code input} event after filling. If the element is inside the {@code <label>} element that has
|
||||
* associated <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, that control
|
||||
* will be filled instead. If the element to be filled is not an {@code <input>}, {@code <textarea>} or {@code [contenteditable]} element,
|
||||
* this method throws an error. Note that you can pass an empty string to clear the input field.
|
||||
* element, fills it and triggers an {@code input} event after filling. Note that you can pass an empty string to clear the input
|
||||
* field.
|
||||
*
|
||||
* <p> If the target element is not an {@code <input>}, {@code <textarea>} or {@code [contenteditable]} element, this method throws an error.
|
||||
* However, if the element is inside the {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be filled
|
||||
* instead.
|
||||
*
|
||||
* <p> To send fine-grained keyboard events, use {@link ElementHandle#type ElementHandle.type()}.
|
||||
*
|
||||
* @param value Value to set for the {@code <input>}, {@code <textarea>} or {@code [contenteditable]} element.
|
||||
*/
|
||||
@@ -953,10 +1047,10 @@ public interface ElementHandle extends JSHandle {
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method rejects.
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*/
|
||||
default void hover() {
|
||||
hover(null);
|
||||
@@ -971,10 +1065,10 @@ public interface ElementHandle extends JSHandle {
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method rejects.
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*/
|
||||
void hover(HoverOptions options);
|
||||
/**
|
||||
@@ -1033,7 +1127,7 @@ public interface ElementHandle extends JSHandle {
|
||||
* <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 speficied with the
|
||||
* <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.
|
||||
*
|
||||
* @param key Name of the key to press or a character to generate, such as {@code ArrowLeft} or {@code a}.
|
||||
@@ -1059,7 +1153,7 @@ public interface ElementHandle extends JSHandle {
|
||||
* <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 speficied with the
|
||||
* <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.
|
||||
*
|
||||
* @param key Name of the key to press or a character to generate, such as {@code ArrowLeft} or {@code a}.
|
||||
@@ -1120,12 +1214,17 @@ public interface ElementHandle extends JSHandle {
|
||||
*/
|
||||
void scrollIntoViewIfNeeded(ScrollIntoViewIfNeededOptions options);
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until
|
||||
* all specified options are present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If element is not a {@code <select>}
|
||||
* element, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* handle.selectOption("blue");
|
||||
@@ -1143,12 +1242,17 @@ public interface ElementHandle extends JSHandle {
|
||||
return selectOption(values, null);
|
||||
}
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until
|
||||
* all specified options are present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If element is not a {@code <select>}
|
||||
* element, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* handle.selectOption("blue");
|
||||
@@ -1164,12 +1268,17 @@ public interface ElementHandle extends JSHandle {
|
||||
*/
|
||||
List<String> selectOption(String values, SelectOptionOptions options);
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until
|
||||
* all specified options are present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If element is not a {@code <select>}
|
||||
* element, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* handle.selectOption("blue");
|
||||
@@ -1187,12 +1296,17 @@ public interface ElementHandle extends JSHandle {
|
||||
return selectOption(values, null);
|
||||
}
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until
|
||||
* all specified options are present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If element is not a {@code <select>}
|
||||
* element, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* handle.selectOption("blue");
|
||||
@@ -1208,12 +1322,17 @@ public interface ElementHandle extends JSHandle {
|
||||
*/
|
||||
List<String> selectOption(ElementHandle values, SelectOptionOptions options);
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until
|
||||
* all specified options are present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If element is not a {@code <select>}
|
||||
* element, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* handle.selectOption("blue");
|
||||
@@ -1231,12 +1350,17 @@ public interface ElementHandle extends JSHandle {
|
||||
return selectOption(values, null);
|
||||
}
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until
|
||||
* all specified options are present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If element is not a {@code <select>}
|
||||
* element, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* handle.selectOption("blue");
|
||||
@@ -1252,12 +1376,17 @@ public interface ElementHandle extends JSHandle {
|
||||
*/
|
||||
List<String> selectOption(String[] values, SelectOptionOptions options);
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until
|
||||
* all specified options are present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If element is not a {@code <select>}
|
||||
* element, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* handle.selectOption("blue");
|
||||
@@ -1275,12 +1404,17 @@ public interface ElementHandle extends JSHandle {
|
||||
return selectOption(values, null);
|
||||
}
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until
|
||||
* all specified options are present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If element is not a {@code <select>}
|
||||
* element, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* handle.selectOption("blue");
|
||||
@@ -1296,12 +1430,17 @@ public interface ElementHandle extends JSHandle {
|
||||
*/
|
||||
List<String> selectOption(SelectOption values, SelectOptionOptions options);
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until
|
||||
* all specified options are present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If element is not a {@code <select>}
|
||||
* element, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* handle.selectOption("blue");
|
||||
@@ -1319,12 +1458,17 @@ public interface ElementHandle extends JSHandle {
|
||||
return selectOption(values, null);
|
||||
}
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until
|
||||
* all specified options are present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If element is not a {@code <select>}
|
||||
* element, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* handle.selectOption("blue");
|
||||
@@ -1340,12 +1484,17 @@ public interface ElementHandle extends JSHandle {
|
||||
*/
|
||||
List<String> selectOption(ElementHandle[] values, SelectOptionOptions options);
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until
|
||||
* all specified options are present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If element is not a {@code <select>}
|
||||
* element, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* handle.selectOption("blue");
|
||||
@@ -1363,12 +1512,17 @@ public interface ElementHandle extends JSHandle {
|
||||
return selectOption(values, null);
|
||||
}
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until
|
||||
* all specified options are present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If element is not a {@code <select>}
|
||||
* element, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* handle.selectOption("blue");
|
||||
@@ -1477,10 +1631,10 @@ public interface ElementHandle extends JSHandle {
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method rejects.
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> {@code elementHandle.tap()} requires that the {@code hasTouch} option of the browser context be set to true.
|
||||
*/
|
||||
@@ -1497,10 +1651,10 @@ public interface ElementHandle extends JSHandle {
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method rejects.
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> {@code elementHandle.tap()} requires that the {@code hasTouch} option of the browser context be set to true.
|
||||
*/
|
||||
@@ -1552,20 +1706,20 @@ public interface ElementHandle extends JSHandle {
|
||||
/**
|
||||
* This method checks the element by performing the following steps:
|
||||
* <ol>
|
||||
* <li> Ensure that element is a checkbox or a radio input. If not, this method rejects. If the element is already unchecked,
|
||||
* <li> Ensure that element is a checkbox or a radio input. If not, this method throws. If the element is already unchecked,
|
||||
* this method returns immediately.</li>
|
||||
* <li> Wait for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks on the element, unless
|
||||
* {@code force} option is set.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link Page#mouse Page.mouse()} to click in the center of the element.</li>
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set.</li>
|
||||
* <li> Ensure that the element is now unchecked. If not, this method rejects.</li>
|
||||
* <li> Ensure that the element is now unchecked. If not, this method throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method rejects.
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*/
|
||||
default void uncheck() {
|
||||
uncheck(null);
|
||||
@@ -1573,20 +1727,20 @@ public interface ElementHandle extends JSHandle {
|
||||
/**
|
||||
* This method checks the element by performing the following steps:
|
||||
* <ol>
|
||||
* <li> Ensure that element is a checkbox or a radio input. If not, this method rejects. If the element is already unchecked,
|
||||
* <li> Ensure that element is a checkbox or a radio input. If not, this method throws. If the element is already unchecked,
|
||||
* this method returns immediately.</li>
|
||||
* <li> Wait for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks on the element, unless
|
||||
* {@code force} option is set.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link Page#mouse Page.mouse()} to click in the center of the element.</li>
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set.</li>
|
||||
* <li> Ensure that the element is now unchecked. If not, this method rejects.</li>
|
||||
* <li> Ensure that the element is now unchecked. If not, this method throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method rejects.
|
||||
* <p> If the element is detached from the DOM at any moment during the action, this method throws.
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*/
|
||||
void uncheck(UncheckOptions options);
|
||||
/**
|
||||
|
||||
@@ -137,12 +137,23 @@ public interface Frame {
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
* A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of the
|
||||
* element.
|
||||
*/
|
||||
public Position position;
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* When set, this method only performs the <a href="https://playwright.dev/java/docs/actionability/">actionability</a>
|
||||
* checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
|
||||
* performing it.
|
||||
*/
|
||||
public Boolean trial;
|
||||
|
||||
public CheckOptions setForce(boolean force) {
|
||||
this.force = force;
|
||||
@@ -152,10 +163,21 @@ public interface Frame {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
return this;
|
||||
}
|
||||
public CheckOptions setPosition(double x, double y) {
|
||||
return setPosition(new Position(x, y));
|
||||
}
|
||||
public CheckOptions setPosition(Position position) {
|
||||
this.position = position;
|
||||
return this;
|
||||
}
|
||||
public CheckOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
public CheckOptions setTrial(boolean trial) {
|
||||
this.trial = trial;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class ClickOptions {
|
||||
/**
|
||||
@@ -197,6 +219,12 @@ public interface Frame {
|
||||
* Page.setDefaultTimeout()} methods.
|
||||
*/
|
||||
public Double timeout;
|
||||
/**
|
||||
* When set, this method only performs the <a href="https://playwright.dev/java/docs/actionability/">actionability</a>
|
||||
* checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
|
||||
* performing it.
|
||||
*/
|
||||
public Boolean trial;
|
||||
|
||||
public ClickOptions setButton(MouseButton button) {
|
||||
this.button = button;
|
||||
@@ -233,6 +261,10 @@ public interface Frame {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
public ClickOptions setTrial(boolean trial) {
|
||||
this.trial = trial;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class DblclickOptions {
|
||||
/**
|
||||
@@ -270,6 +302,12 @@ public interface Frame {
|
||||
* Page.setDefaultTimeout()} methods.
|
||||
*/
|
||||
public Double timeout;
|
||||
/**
|
||||
* When set, this method only performs the <a href="https://playwright.dev/java/docs/actionability/">actionability</a>
|
||||
* checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
|
||||
* performing it.
|
||||
*/
|
||||
public Boolean trial;
|
||||
|
||||
public DblclickOptions setButton(MouseButton button) {
|
||||
this.button = button;
|
||||
@@ -302,6 +340,10 @@ public interface Frame {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
public DblclickOptions setTrial(boolean trial) {
|
||||
this.trial = trial;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class DispatchEventOptions {
|
||||
/**
|
||||
@@ -423,6 +465,12 @@ public interface Frame {
|
||||
* Page.setDefaultTimeout()} methods.
|
||||
*/
|
||||
public Double timeout;
|
||||
/**
|
||||
* When set, this method only performs the <a href="https://playwright.dev/java/docs/actionability/">actionability</a>
|
||||
* checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
|
||||
* performing it.
|
||||
*/
|
||||
public Boolean trial;
|
||||
|
||||
public HoverOptions setForce(boolean force) {
|
||||
this.force = force;
|
||||
@@ -443,6 +491,10 @@ public interface Frame {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
public HoverOptions setTrial(boolean trial) {
|
||||
this.trial = trial;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class InnerHTMLOptions {
|
||||
/**
|
||||
@@ -680,6 +732,12 @@ public interface Frame {
|
||||
* Page.setDefaultTimeout()} methods.
|
||||
*/
|
||||
public Double timeout;
|
||||
/**
|
||||
* When set, this method only performs the <a href="https://playwright.dev/java/docs/actionability/">actionability</a>
|
||||
* checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
|
||||
* performing it.
|
||||
*/
|
||||
public Boolean trial;
|
||||
|
||||
public TapOptions setForce(boolean force) {
|
||||
this.force = force;
|
||||
@@ -704,6 +762,10 @@ public interface Frame {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
public TapOptions setTrial(boolean trial) {
|
||||
this.trial = trial;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class TextContentOptions {
|
||||
/**
|
||||
@@ -761,12 +823,23 @@ public interface Frame {
|
||||
* inaccessible pages. Defaults to {@code false}.
|
||||
*/
|
||||
public Boolean noWaitAfter;
|
||||
/**
|
||||
* A point to use relative to the top-left corner of element padding box. If not specified, uses some visible point of the
|
||||
* element.
|
||||
*/
|
||||
public Position position;
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* When set, this method only performs the <a href="https://playwright.dev/java/docs/actionability/">actionability</a>
|
||||
* checks and skips the action. Defaults to {@code false}. Useful to wait until the element is ready for the action without
|
||||
* performing it.
|
||||
*/
|
||||
public Boolean trial;
|
||||
|
||||
public UncheckOptions setForce(boolean force) {
|
||||
this.force = force;
|
||||
@@ -776,10 +849,21 @@ public interface Frame {
|
||||
this.noWaitAfter = noWaitAfter;
|
||||
return this;
|
||||
}
|
||||
public UncheckOptions setPosition(double x, double y) {
|
||||
return setPosition(new Position(x, y));
|
||||
}
|
||||
public UncheckOptions setPosition(Position position) {
|
||||
this.position = position;
|
||||
return this;
|
||||
}
|
||||
public UncheckOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
public UncheckOptions setTrial(boolean trial) {
|
||||
this.trial = trial;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class WaitForFunctionOptions {
|
||||
/**
|
||||
@@ -888,6 +972,33 @@ public interface Frame {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
class WaitForURLOptions {
|
||||
/**
|
||||
* Maximum operation time in milliseconds, defaults to 30 seconds, pass {@code 0} to disable timeout. The default value can be
|
||||
* changed by using the {@link BrowserContext#setDefaultNavigationTimeout BrowserContext.setDefaultNavigationTimeout()},
|
||||
* {@link BrowserContext#setDefaultTimeout BrowserContext.setDefaultTimeout()}, {@link Page#setDefaultNavigationTimeout
|
||||
* Page.setDefaultNavigationTimeout()} or {@link Page#setDefaultTimeout Page.setDefaultTimeout()} methods.
|
||||
*/
|
||||
public Double timeout;
|
||||
/**
|
||||
* When to consider operation succeeded, defaults to {@code load}. Events can be either:
|
||||
* <ul>
|
||||
* <li> {@code "domcontentloaded"} - consider operation to be finished when the {@code DOMContentLoaded} event is fired.</li>
|
||||
* <li> {@code "load"} - consider operation to be finished when the {@code load} event is fired.</li>
|
||||
* <li> {@code "networkidle"} - consider operation to be finished when there are no network connections for at least {@code 500} ms.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public WaitUntilState waitUntil;
|
||||
|
||||
public WaitForURLOptions setTimeout(double timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
public WaitForURLOptions setWaitUntil(WaitUntilState waitUntil) {
|
||||
this.waitUntil = waitUntil;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns the added tag when the script's onload fires or when the script content was injected into frame.
|
||||
*
|
||||
@@ -921,19 +1032,19 @@ public interface Frame {
|
||||
/**
|
||||
* This method checks an element matching {@code selector} by performing the following steps:
|
||||
* <ol>
|
||||
* <li> Find an element match matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Ensure that matched element is a checkbox or a radio input. If not, this method rejects. If the element is already
|
||||
* <li> Find an element matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Ensure that matched element is a checkbox or a radio input. If not, this method throws. If the element is already
|
||||
* checked, this method returns immediately.</li>
|
||||
* <li> Wait for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks on the matched element,
|
||||
* unless {@code force} option is set. If the element is detached during the checks, the whole action is retried.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link Page#mouse Page.mouse()} to click in the center of the element.</li>
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set.</li>
|
||||
* <li> Ensure that the element is now checked. If not, this method rejects.</li>
|
||||
* <li> Ensure that the element is now checked. If not, this method throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*
|
||||
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See <a
|
||||
* href="https://playwright.dev/java/docs/selectors/">working with selectors</a> for more details.
|
||||
@@ -944,19 +1055,19 @@ public interface Frame {
|
||||
/**
|
||||
* This method checks an element matching {@code selector} by performing the following steps:
|
||||
* <ol>
|
||||
* <li> Find an element match matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Ensure that matched element is a checkbox or a radio input. If not, this method rejects. If the element is already
|
||||
* <li> Find an element matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Ensure that matched element is a checkbox or a radio input. If not, this method throws. If the element is already
|
||||
* checked, this method returns immediately.</li>
|
||||
* <li> Wait for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks on the matched element,
|
||||
* unless {@code force} option is set. If the element is detached during the checks, the whole action is retried.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link Page#mouse Page.mouse()} to click in the center of the element.</li>
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set.</li>
|
||||
* <li> Ensure that the element is now checked. If not, this method rejects.</li>
|
||||
* <li> Ensure that the element is now checked. If not, this method throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*
|
||||
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See <a
|
||||
* href="https://playwright.dev/java/docs/selectors/">working with selectors</a> for more details.
|
||||
@@ -966,7 +1077,7 @@ public interface Frame {
|
||||
/**
|
||||
* This method clicks an element matching {@code selector} by performing the following steps:
|
||||
* <ol>
|
||||
* <li> Find an element match matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Find an element matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Wait for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks on the matched element,
|
||||
* unless {@code force} option is set. If the element is detached during the checks, the whole action is retried.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
@@ -974,8 +1085,8 @@ public interface Frame {
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*
|
||||
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See <a
|
||||
* href="https://playwright.dev/java/docs/selectors/">working with selectors</a> for more details.
|
||||
@@ -986,7 +1097,7 @@ public interface Frame {
|
||||
/**
|
||||
* This method clicks an element matching {@code selector} by performing the following steps:
|
||||
* <ol>
|
||||
* <li> Find an element match matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Find an element matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Wait for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks on the matched element,
|
||||
* unless {@code force} option is set. If the element is detached during the checks, the whole action is retried.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
@@ -994,8 +1105,8 @@ public interface Frame {
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*
|
||||
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See <a
|
||||
* href="https://playwright.dev/java/docs/selectors/">working with selectors</a> for more details.
|
||||
@@ -1008,17 +1119,17 @@ public interface Frame {
|
||||
/**
|
||||
* This method double clicks an element matching {@code selector} by performing the following steps:
|
||||
* <ol>
|
||||
* <li> Find an element match matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Find an element matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Wait for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks on the matched element,
|
||||
* unless {@code force} option is set. If the element is detached during the checks, the whole action is retried.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link Page#mouse Page.mouse()} to double click in the center of the element, or the specified {@code position}.</li>
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set. Note that if the first
|
||||
* click of the {@code dblclick()} triggers a navigation event, this method will reject.</li>
|
||||
* click of the {@code dblclick()} triggers a navigation event, this method will throw.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> {@code frame.dblclick()} dispatches two {@code click} events and a single {@code dblclick} event.
|
||||
*
|
||||
@@ -1031,17 +1142,17 @@ public interface Frame {
|
||||
/**
|
||||
* This method double clicks an element matching {@code selector} by performing the following steps:
|
||||
* <ol>
|
||||
* <li> Find an element match matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Find an element matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Wait for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks on the matched element,
|
||||
* unless {@code force} option is set. If the element is detached during the checks, the whole action is retried.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link Page#mouse Page.mouse()} to double click in the center of the element, or the specified {@code position}.</li>
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set. Note that if the first
|
||||
* click of the {@code dblclick()} triggers a navigation event, this method will reject.</li>
|
||||
* click of the {@code dblclick()} triggers a navigation event, this method will throw.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> {@code frame.dblclick()} dispatches two {@code click} events and a single {@code dblclick} event.
|
||||
*
|
||||
@@ -1050,8 +1161,8 @@ public interface Frame {
|
||||
*/
|
||||
void dblclick(String selector, DblclickOptions options);
|
||||
/**
|
||||
* The snippet below dispatches the {@code click} event on the element. Regardless of the visibility state of the elment, {@code click}
|
||||
* is dispatched. This is equivalend to calling <a
|
||||
* The snippet below dispatches the {@code click} event on the element. Regardless of the visibility state of the element,
|
||||
* {@code click} is dispatched. This is equivalent to calling <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click">element.click()</a>.
|
||||
* <pre>{@code
|
||||
* frame.dispatchEvent("button#submit", "click");
|
||||
@@ -1089,8 +1200,8 @@ public interface Frame {
|
||||
dispatchEvent(selector, type, eventInit, null);
|
||||
}
|
||||
/**
|
||||
* The snippet below dispatches the {@code click} event on the element. Regardless of the visibility state of the elment, {@code click}
|
||||
* is dispatched. This is equivalend to calling <a
|
||||
* The snippet below dispatches the {@code click} event on the element. Regardless of the visibility state of the element,
|
||||
* {@code click} is dispatched. This is equivalent to calling <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click">element.click()</a>.
|
||||
* <pre>{@code
|
||||
* frame.dispatchEvent("button#submit", "click");
|
||||
@@ -1127,8 +1238,8 @@ public interface Frame {
|
||||
dispatchEvent(selector, type, null);
|
||||
}
|
||||
/**
|
||||
* The snippet below dispatches the {@code click} event on the element. Regardless of the visibility state of the elment, {@code click}
|
||||
* is dispatched. This is equivalend to calling <a
|
||||
* The snippet below dispatches the {@code click} event on the element. Regardless of the visibility state of the element,
|
||||
* {@code click} is dispatched. This is equivalent to calling <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click">element.click()</a>.
|
||||
* <pre>{@code
|
||||
* frame.dispatchEvent("button#submit", "click");
|
||||
@@ -1334,7 +1445,7 @@ public interface Frame {
|
||||
* Returns the return value of {@code expression} as a {@code JSHandle}.
|
||||
*
|
||||
* <p> The only difference between {@link Frame#evaluate Frame.evaluate()} and {@link Frame#evaluateHandle
|
||||
* Frame.evaluateHandle()} is that [method: Frame.evaluateHandle{@code ] returns }JSHandle`.
|
||||
* Frame.evaluateHandle()} is that {@link Frame#evaluateHandle Frame.evaluateHandle()} returns {@code JSHandle}.
|
||||
*
|
||||
* <p> If the function, passed to the {@link Frame#evaluateHandle Frame.evaluateHandle()}, returns a <a
|
||||
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then {@link
|
||||
@@ -1367,7 +1478,7 @@ public interface Frame {
|
||||
* Returns the return value of {@code expression} as a {@code JSHandle}.
|
||||
*
|
||||
* <p> The only difference between {@link Frame#evaluate Frame.evaluate()} and {@link Frame#evaluateHandle
|
||||
* Frame.evaluateHandle()} is that [method: Frame.evaluateHandle{@code ] returns }JSHandle`.
|
||||
* Frame.evaluateHandle()} is that {@link Frame#evaluateHandle Frame.evaluateHandle()} returns {@code JSHandle}.
|
||||
*
|
||||
* <p> If the function, passed to the {@link Frame#evaluateHandle Frame.evaluateHandle()}, returns a <a
|
||||
* href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'>Promise</a>, then {@link
|
||||
@@ -1398,10 +1509,12 @@ public interface Frame {
|
||||
/**
|
||||
* This method waits for an element matching {@code selector}, waits for <a
|
||||
* href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, focuses the element, fills it and
|
||||
* triggers an {@code input} event after filling. If the element is inside the {@code <label>} element that has associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, that control will be
|
||||
* filled instead. If the element to be filled is not an {@code <input>}, {@code <textarea>} or {@code [contenteditable]} element, this
|
||||
* method throws an error. Note that you can pass an empty string to clear the input field.
|
||||
* triggers an {@code input} event after filling. Note that you can pass an empty string to clear the input field.
|
||||
*
|
||||
* <p> If the target element is not an {@code <input>}, {@code <textarea>} or {@code [contenteditable]} element, this method throws an error.
|
||||
* However, if the element is inside the {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be filled
|
||||
* instead.
|
||||
*
|
||||
* <p> To send fine-grained keyboard events, use {@link Frame#type Frame.type()}.
|
||||
*
|
||||
@@ -1415,10 +1528,12 @@ public interface Frame {
|
||||
/**
|
||||
* This method waits for an element matching {@code selector}, waits for <a
|
||||
* href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, focuses the element, fills it and
|
||||
* triggers an {@code input} event after filling. If the element is inside the {@code <label>} element that has associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, that control will be
|
||||
* filled instead. If the element to be filled is not an {@code <input>}, {@code <textarea>} or {@code [contenteditable]} element, this
|
||||
* method throws an error. Note that you can pass an empty string to clear the input field.
|
||||
* triggers an {@code input} event after filling. Note that you can pass an empty string to clear the input field.
|
||||
*
|
||||
* <p> If the target element is not an {@code <input>}, {@code <textarea>} or {@code [contenteditable]} element, this method throws an error.
|
||||
* However, if the element is inside the {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be filled
|
||||
* instead.
|
||||
*
|
||||
* <p> To send fine-grained keyboard events, use {@link Frame#type Frame.type()}.
|
||||
*
|
||||
@@ -1534,7 +1649,7 @@ public interface Frame {
|
||||
/**
|
||||
* This method hovers over an element matching {@code selector} by performing the following steps:
|
||||
* <ol>
|
||||
* <li> Find an element match matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Find an element matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Wait for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks on the matched element,
|
||||
* unless {@code force} option is set. If the element is detached during the checks, the whole action is retried.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
@@ -1542,8 +1657,8 @@ public interface Frame {
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*
|
||||
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See <a
|
||||
* href="https://playwright.dev/java/docs/selectors/">working with selectors</a> for more details.
|
||||
@@ -1554,7 +1669,7 @@ public interface Frame {
|
||||
/**
|
||||
* This method hovers over an element matching {@code selector} by performing the following steps:
|
||||
* <ol>
|
||||
* <li> Find an element match matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Find an element matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Wait for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks on the matched element,
|
||||
* unless {@code force} option is set. If the element is detached during the checks, the whole action is retried.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
@@ -1562,8 +1677,8 @@ public interface Frame {
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*
|
||||
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See <a
|
||||
* href="https://playwright.dev/java/docs/selectors/">working with selectors</a> for more details.
|
||||
@@ -1741,7 +1856,7 @@ public interface Frame {
|
||||
* <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 speficied with the
|
||||
* <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.
|
||||
*
|
||||
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See <a
|
||||
@@ -1767,7 +1882,7 @@ public interface Frame {
|
||||
* <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 speficied with the
|
||||
* <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.
|
||||
*
|
||||
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See <a
|
||||
@@ -1798,12 +1913,18 @@ public interface Frame {
|
||||
*/
|
||||
List<ElementHandle> querySelectorAll(String selector);
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for an element matching {@code selector}, waits for <a
|
||||
* href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until all specified options are
|
||||
* present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If there's no {@code <select>} element
|
||||
* matching {@code selector}, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* frame.selectOption("select#colors", "blue");
|
||||
@@ -1823,12 +1944,18 @@ public interface Frame {
|
||||
return selectOption(selector, values, null);
|
||||
}
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for an element matching {@code selector}, waits for <a
|
||||
* href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until all specified options are
|
||||
* present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If there's no {@code <select>} element
|
||||
* matching {@code selector}, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* frame.selectOption("select#colors", "blue");
|
||||
@@ -1846,12 +1973,18 @@ public interface Frame {
|
||||
*/
|
||||
List<String> selectOption(String selector, String values, SelectOptionOptions options);
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for an element matching {@code selector}, waits for <a
|
||||
* href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until all specified options are
|
||||
* present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If there's no {@code <select>} element
|
||||
* matching {@code selector}, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* frame.selectOption("select#colors", "blue");
|
||||
@@ -1871,12 +2004,18 @@ public interface Frame {
|
||||
return selectOption(selector, values, null);
|
||||
}
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for an element matching {@code selector}, waits for <a
|
||||
* href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until all specified options are
|
||||
* present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If there's no {@code <select>} element
|
||||
* matching {@code selector}, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* frame.selectOption("select#colors", "blue");
|
||||
@@ -1894,12 +2033,18 @@ public interface Frame {
|
||||
*/
|
||||
List<String> selectOption(String selector, ElementHandle values, SelectOptionOptions options);
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for an element matching {@code selector}, waits for <a
|
||||
* href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until all specified options are
|
||||
* present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If there's no {@code <select>} element
|
||||
* matching {@code selector}, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* frame.selectOption("select#colors", "blue");
|
||||
@@ -1919,12 +2064,18 @@ public interface Frame {
|
||||
return selectOption(selector, values, null);
|
||||
}
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for an element matching {@code selector}, waits for <a
|
||||
* href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until all specified options are
|
||||
* present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If there's no {@code <select>} element
|
||||
* matching {@code selector}, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* frame.selectOption("select#colors", "blue");
|
||||
@@ -1942,12 +2093,18 @@ public interface Frame {
|
||||
*/
|
||||
List<String> selectOption(String selector, String[] values, SelectOptionOptions options);
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for an element matching {@code selector}, waits for <a
|
||||
* href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until all specified options are
|
||||
* present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If there's no {@code <select>} element
|
||||
* matching {@code selector}, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* frame.selectOption("select#colors", "blue");
|
||||
@@ -1967,12 +2124,18 @@ public interface Frame {
|
||||
return selectOption(selector, values, null);
|
||||
}
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for an element matching {@code selector}, waits for <a
|
||||
* href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until all specified options are
|
||||
* present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If there's no {@code <select>} element
|
||||
* matching {@code selector}, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* frame.selectOption("select#colors", "blue");
|
||||
@@ -1990,12 +2153,18 @@ public interface Frame {
|
||||
*/
|
||||
List<String> selectOption(String selector, SelectOption values, SelectOptionOptions options);
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for an element matching {@code selector}, waits for <a
|
||||
* href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until all specified options are
|
||||
* present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If there's no {@code <select>} element
|
||||
* matching {@code selector}, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* frame.selectOption("select#colors", "blue");
|
||||
@@ -2015,12 +2184,18 @@ public interface Frame {
|
||||
return selectOption(selector, values, null);
|
||||
}
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for an element matching {@code selector}, waits for <a
|
||||
* href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until all specified options are
|
||||
* present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If there's no {@code <select>} element
|
||||
* matching {@code selector}, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* frame.selectOption("select#colors", "blue");
|
||||
@@ -2038,12 +2213,18 @@ public interface Frame {
|
||||
*/
|
||||
List<String> selectOption(String selector, ElementHandle[] values, SelectOptionOptions options);
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for an element matching {@code selector}, waits for <a
|
||||
* href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until all specified options are
|
||||
* present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If there's no {@code <select>} element
|
||||
* matching {@code selector}, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* frame.selectOption("select#colors", "blue");
|
||||
@@ -2063,12 +2244,18 @@ public interface Frame {
|
||||
return selectOption(selector, values, null);
|
||||
}
|
||||
/**
|
||||
* Returns the array of option values that have been successfully selected.
|
||||
* This method waits for an element matching {@code selector}, waits for <a
|
||||
* href="https://playwright.dev/java/docs/actionability/">actionability</a> checks, waits until all specified options are
|
||||
* present in the {@code <select>} element and selects these options.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected. If there's no {@code <select>} element
|
||||
* matching {@code selector}, the method throws an error.
|
||||
* <p> If the target element is not a {@code <select>} element, this method throws an error. However, if the element is inside the
|
||||
* {@code <label>} element that has an associated <a
|
||||
* href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control">control</a>, the control will be used
|
||||
* instead.
|
||||
*
|
||||
* <p> Will wait until all specified options are present in the {@code <select>} element.
|
||||
* <p> Returns the array of option values that have been successfully selected.
|
||||
*
|
||||
* <p> Triggers a {@code change} and {@code input} event once all the provided options have been selected.
|
||||
* <pre>{@code
|
||||
* // single selection matching the value
|
||||
* frame.selectOption("select#colors", "blue");
|
||||
@@ -2198,7 +2385,7 @@ public interface Frame {
|
||||
/**
|
||||
* This method taps an element matching {@code selector} by performing the following steps:
|
||||
* <ol>
|
||||
* <li> Find an element match matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Find an element matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Wait for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks on the matched element,
|
||||
* unless {@code force} option is set. If the element is detached during the checks, the whole action is retried.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
@@ -2206,8 +2393,8 @@ public interface Frame {
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> {@code frame.tap()} requires that the {@code hasTouch} option of the browser context be set to true.
|
||||
*
|
||||
@@ -2220,7 +2407,7 @@ public interface Frame {
|
||||
/**
|
||||
* This method taps an element matching {@code selector} by performing the following steps:
|
||||
* <ol>
|
||||
* <li> Find an element match matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Find an element matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Wait for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks on the matched element,
|
||||
* unless {@code force} option is set. If the element is detached during the checks, the whole action is retried.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
@@ -2228,8 +2415,8 @@ public interface Frame {
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> {@code frame.tap()} requires that the {@code hasTouch} option of the browser context be set to true.
|
||||
*
|
||||
@@ -2266,7 +2453,7 @@ public interface Frame {
|
||||
* // Types instantly
|
||||
* frame.type("#mytextarea", "Hello");
|
||||
* // Types slower, like a user
|
||||
* frame.type("#mytextarea", "World", new Frame.TypeOptions().setDelay(100));
|
||||
* frame.type("#mytextarea", "World", new Frame.TypeOptions().setDelay(100));
|
||||
* }</pre>
|
||||
*
|
||||
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See <a
|
||||
@@ -2285,7 +2472,7 @@ public interface Frame {
|
||||
* // Types instantly
|
||||
* frame.type("#mytextarea", "Hello");
|
||||
* // Types slower, like a user
|
||||
* frame.type("#mytextarea", "World", new Frame.TypeOptions().setDelay(100));
|
||||
* frame.type("#mytextarea", "World", new Frame.TypeOptions().setDelay(100));
|
||||
* }</pre>
|
||||
*
|
||||
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See <a
|
||||
@@ -2296,19 +2483,19 @@ public interface Frame {
|
||||
/**
|
||||
* This method checks an element matching {@code selector} by performing the following steps:
|
||||
* <ol>
|
||||
* <li> Find an element match matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Ensure that matched element is a checkbox or a radio input. If not, this method rejects. If the element is already
|
||||
* <li> Find an element matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Ensure that matched element is a checkbox or a radio input. If not, this method throws. If the element is already
|
||||
* unchecked, this method returns immediately.</li>
|
||||
* <li> Wait for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks on the matched element,
|
||||
* unless {@code force} option is set. If the element is detached during the checks, the whole action is retried.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link Page#mouse Page.mouse()} to click in the center of the element.</li>
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set.</li>
|
||||
* <li> Ensure that the element is now unchecked. If not, this method rejects.</li>
|
||||
* <li> Ensure that the element is now unchecked. If not, this method throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*
|
||||
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See <a
|
||||
* href="https://playwright.dev/java/docs/selectors/">working with selectors</a> for more details.
|
||||
@@ -2319,19 +2506,19 @@ public interface Frame {
|
||||
/**
|
||||
* This method checks an element matching {@code selector} by performing the following steps:
|
||||
* <ol>
|
||||
* <li> Find an element match matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Ensure that matched element is a checkbox or a radio input. If not, this method rejects. If the element is already
|
||||
* <li> Find an element matching {@code selector}. If there is none, wait until a matching element is attached to the DOM.</li>
|
||||
* <li> Ensure that matched element is a checkbox or a radio input. If not, this method throws. If the element is already
|
||||
* unchecked, this method returns immediately.</li>
|
||||
* <li> Wait for <a href="https://playwright.dev/java/docs/actionability/">actionability</a> checks on the matched element,
|
||||
* unless {@code force} option is set. If the element is detached during the checks, the whole action is retried.</li>
|
||||
* <li> Scroll the element into view if needed.</li>
|
||||
* <li> Use {@link Page#mouse Page.mouse()} to click in the center of the element.</li>
|
||||
* <li> Wait for initiated navigations to either succeed or fail, unless {@code noWaitAfter} option is set.</li>
|
||||
* <li> Ensure that the element is now unchecked. If not, this method rejects.</li>
|
||||
* <li> Ensure that the element is now unchecked. If not, this method throws.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method rejects with a {@code TimeoutError}.
|
||||
* Passing zero timeout disables this.
|
||||
* <p> When all steps combined have not finished during the specified {@code timeout}, this method throws a {@code TimeoutError}. Passing
|
||||
* zero timeout disables this.
|
||||
*
|
||||
* @param selector A selector to search for element. If there are multiple elements satisfying the selector, the first will be used. See <a
|
||||
* href="https://playwright.dev/java/docs/selectors/">working with selectors</a> for more details.
|
||||
@@ -2614,5 +2801,71 @@ public interface Frame {
|
||||
* @param timeout A timeout to wait for
|
||||
*/
|
||||
void waitForTimeout(double timeout);
|
||||
/**
|
||||
* Waits for the frame to navigate to the given URL.
|
||||
* <pre>{@code
|
||||
* frame.click("a.delayed-navigation"); // Clicking the link will indirectly cause a navigation
|
||||
* frame.waitForURL("**\/target.html");
|
||||
* }</pre>
|
||||
*
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while waiting for the navigation.
|
||||
*/
|
||||
default void waitForURL(String url) {
|
||||
waitForURL(url, null);
|
||||
}
|
||||
/**
|
||||
* Waits for the frame to navigate to the given URL.
|
||||
* <pre>{@code
|
||||
* frame.click("a.delayed-navigation"); // Clicking the link will indirectly cause a navigation
|
||||
* frame.waitForURL("**\/target.html");
|
||||
* }</pre>
|
||||
*
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while waiting for the navigation.
|
||||
*/
|
||||
void waitForURL(String url, WaitForURLOptions options);
|
||||
/**
|
||||
* Waits for the frame to navigate to the given URL.
|
||||
* <pre>{@code
|
||||
* frame.click("a.delayed-navigation"); // Clicking the link will indirectly cause a navigation
|
||||
* frame.waitForURL("**\/target.html");
|
||||
* }</pre>
|
||||
*
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while waiting for the navigation.
|
||||
*/
|
||||
default void waitForURL(Pattern url) {
|
||||
waitForURL(url, null);
|
||||
}
|
||||
/**
|
||||
* Waits for the frame to navigate to the given URL.
|
||||
* <pre>{@code
|
||||
* frame.click("a.delayed-navigation"); // Clicking the link will indirectly cause a navigation
|
||||
* frame.waitForURL("**\/target.html");
|
||||
* }</pre>
|
||||
*
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while waiting for the navigation.
|
||||
*/
|
||||
void waitForURL(Pattern url, WaitForURLOptions options);
|
||||
/**
|
||||
* Waits for the frame to navigate to the given URL.
|
||||
* <pre>{@code
|
||||
* frame.click("a.delayed-navigation"); // Clicking the link will indirectly cause a navigation
|
||||
* frame.waitForURL("**\/target.html");
|
||||
* }</pre>
|
||||
*
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while waiting for the navigation.
|
||||
*/
|
||||
default void waitForURL(Predicate<String> url) {
|
||||
waitForURL(url, null);
|
||||
}
|
||||
/**
|
||||
* Waits for the frame to navigate to the given URL.
|
||||
* <pre>{@code
|
||||
* frame.click("a.delayed-navigation"); // Clicking the link will indirectly cause a navigation
|
||||
* frame.waitForURL("**\/target.html");
|
||||
* }</pre>
|
||||
*
|
||||
* @param url A glob pattern, regex pattern or predicate receiving [URL] to match while waiting for the navigation.
|
||||
*/
|
||||
void waitForURL(Predicate<String> url, WaitForURLOptions options);
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ public interface Keyboard {
|
||||
* <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 speficied with the
|
||||
* <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();
|
||||
@@ -170,7 +170,7 @@ public interface Keyboard {
|
||||
* <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 speficied with the
|
||||
* <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();
|
||||
@@ -202,6 +202,8 @@ public interface Keyboard {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Modifier keys DO NOT effect {@code keyboard.type}. Holding down {@code Shift} will not type the text in upper case.
|
||||
*
|
||||
* <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.
|
||||
*/
|
||||
default void type(String text) {
|
||||
@@ -220,6 +222,8 @@ public interface Keyboard {
|
||||
*
|
||||
* <p> <strong>NOTE:</strong> Modifier keys DO NOT effect {@code keyboard.type}. Holding down {@code Shift} will not type the text in upper case.
|
||||
*
|
||||
* <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.
|
||||
*/
|
||||
void type(String text, TypeOptions options);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -41,11 +41,11 @@ import java.util.*;
|
||||
*/
|
||||
public interface Playwright extends AutoCloseable {
|
||||
/**
|
||||
* This object can be used to launch or connect to Chromium, returning instances of {@code ChromiumBrowser}.
|
||||
* This object can be used to launch or connect to Chromium, returning instances of {@code Browser}.
|
||||
*/
|
||||
BrowserType chromium();
|
||||
/**
|
||||
* This object can be used to launch or connect to Firefox, returning instances of {@code FirefoxBrowser}.
|
||||
* This object can be used to launch or connect to Firefox, returning instances of {@code Browser}.
|
||||
*/
|
||||
BrowserType firefox();
|
||||
/**
|
||||
@@ -54,7 +54,7 @@ public interface Playwright extends AutoCloseable {
|
||||
*/
|
||||
Selectors selectors();
|
||||
/**
|
||||
* This object can be used to launch or connect to WebKit, returning instances of {@code WebKitBrowser}.
|
||||
* This object can be used to launch or connect to WebKit, returning instances of {@code Browser}.
|
||||
*/
|
||||
BrowserType webkit();
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
/**
|
||||
* PlaywrightException is thrown whenever certain operations are terminated abnormally, e.g. browser closes while {@link
|
||||
* Page#evaluate Page.evaluate()} is running. All Playwright exceptions inherit from this class.
|
||||
*/
|
||||
public class PlaywrightException extends RuntimeException {
|
||||
public PlaywrightException(String message) {
|
||||
super(message);
|
||||
|
||||
@@ -20,7 +20,7 @@ import java.util.*;
|
||||
|
||||
/**
|
||||
* The Touchscreen class operates in main-frame CSS pixels relative to the top-left corner of the viewport. Methods on the
|
||||
* touchscreen can only be used in browser contexts that have been intialized with {@code hasTouch} set to true.
|
||||
* touchscreen can only be used in browser contexts that have been initialized with {@code hasTouch} set to true.
|
||||
*/
|
||||
public interface Touchscreen {
|
||||
/**
|
||||
|
||||
@@ -20,16 +20,27 @@ import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* When browser context is created with the {@code videosPath} option, each page has a video object associated with it.
|
||||
* When browser context is created with the {@code recordVideo} option, each page has a video object associated with it.
|
||||
* <pre>{@code
|
||||
* System.out.println(page.video().path());
|
||||
* }</pre>
|
||||
*/
|
||||
public interface Video {
|
||||
/**
|
||||
* Deletes the video file. Will wait for the video to finish if necessary.
|
||||
*/
|
||||
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.
|
||||
* upon closing the browser context. This method throws when connected remotely.
|
||||
*/
|
||||
Path path();
|
||||
/**
|
||||
* Saves the video to a user-specified path. It is safe to call this method while the video is still in progress, or after
|
||||
* 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.
|
||||
*/
|
||||
void saveAs(Path path);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ public interface WebSocket {
|
||||
void offClose(Consumer<WebSocket> handler);
|
||||
|
||||
/**
|
||||
* Fired when the websocket recieves a frame.
|
||||
* Fired when the websocket receives a frame.
|
||||
*/
|
||||
void onFrameReceived(Consumer<WebSocketFrame> handler);
|
||||
/**
|
||||
|
||||
@@ -65,7 +65,7 @@ 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
|
||||
* Worker#evaluate Worker.evaluate()} returns {@code undefined}. Playwright also supports transferring some additional values
|
||||
* that are not serializable by {@code JSON}: {@code -0}, {@code NaN}, {@code Infinity}, {@code -Infinity}.
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
|
||||
@@ -82,7 +82,7 @@ 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
|
||||
* Worker#evaluate Worker.evaluate()} returns {@code undefined}. Playwright also supports transferring some additional values
|
||||
* that are not serializable by {@code JSON}: {@code -0}, {@code NaN}, {@code Infinity}, {@code -Infinity}.
|
||||
*
|
||||
* @param expression JavaScript expression to be evaluated in the browser context. If it looks like a function declaration, it is interpreted
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.impl;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.FileSystems;
|
||||
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();
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
sendMessage("delete");
|
||||
}
|
||||
|
||||
public String failure() {
|
||||
JsonObject result = sendMessage("failure").getAsJsonObject();
|
||||
if (result.has("error")) {
|
||||
return result.get("error").getAsString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Path pathAfterFinished() {
|
||||
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();
|
||||
return FileSystems.getDefault().getPath(json.get("value").getAsString());
|
||||
}
|
||||
|
||||
public void saveAs(Path path) {
|
||||
if (isRemote) {
|
||||
JsonObject jsonObject = sendMessage("saveAsStream").getAsJsonObject();
|
||||
Stream stream = connection.getExistingObject(jsonObject.getAsJsonObject("stream").get("guid").getAsString());
|
||||
writeToFile(stream.stream(), path);
|
||||
return;
|
||||
}
|
||||
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("path", path.toString());
|
||||
sendMessage("saveAs", params);
|
||||
}
|
||||
}
|
||||
@@ -19,13 +19,22 @@ 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.*;
|
||||
import com.microsoft.playwright.BrowserContext;
|
||||
import com.microsoft.playwright.Page;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
import com.microsoft.playwright.Route;
|
||||
import com.microsoft.playwright.options.BindingCallback;
|
||||
import com.microsoft.playwright.options.Cookie;
|
||||
import com.microsoft.playwright.options.FunctionCallback;
|
||||
import com.microsoft.playwright.options.Geolocation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -35,7 +44,6 @@ import static com.microsoft.playwright.impl.Utils.isSafeCloseError;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static java.nio.file.Files.readAllBytes;
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.emptyList;
|
||||
|
||||
class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
private final BrowserImpl browser;
|
||||
@@ -92,6 +100,10 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
|
||||
@Override
|
||||
public Page waitForPage(WaitForPageOptions options, Runnable code) {
|
||||
return withWaitLogging("BrowserContext.close", () -> waitForPageImpl(options, code));
|
||||
}
|
||||
|
||||
private Page waitForPageImpl(WaitForPageOptions options, Runnable code) {
|
||||
if (options == null) {
|
||||
options = new WaitForPageOptions();
|
||||
}
|
||||
@@ -105,7 +117,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
|
||||
@Override
|
||||
public List<Cookie> cookies(String url) {
|
||||
return cookies(url == null ? emptyList() : asList(url));
|
||||
return cookies(url == null ? new ArrayList<>() : asList(url));
|
||||
}
|
||||
|
||||
private void closeImpl() {
|
||||
@@ -177,7 +189,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
private List<Cookie> cookiesImpl(List<String> urls) {
|
||||
JsonObject params = new JsonObject();
|
||||
if (urls == null) {
|
||||
urls = emptyList();
|
||||
urls = new ArrayList<>();
|
||||
}
|
||||
params.add("urls", gson().toJsonTree(urls));
|
||||
JsonObject json = sendMessage("cookies", params).getAsJsonObject();
|
||||
@@ -225,7 +237,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
options = new GrantPermissionsOptions();
|
||||
}
|
||||
if (permissions == null) {
|
||||
permissions = emptyList();
|
||||
permissions = new ArrayList<>();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.add("permissions", gson().toJsonTree(permissions));
|
||||
@@ -395,8 +407,11 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext {
|
||||
}
|
||||
} else if ("page".equals(event)) {
|
||||
PageImpl page = connection.getExistingObject(params.getAsJsonObject("page").get("guid").getAsString());
|
||||
listeners.notify(EventType.PAGE, page);
|
||||
pages.add(page);
|
||||
listeners.notify(EventType.PAGE, page);
|
||||
if (page.opener() != null && !page.opener().isClosed()) {
|
||||
page.opener().notifyPopup(page);
|
||||
}
|
||||
} else if ("bindingCall".equals(event)) {
|
||||
BindingCall bindingCall = connection.getExistingObject(params.getAsJsonObject("binding").get("guid").getAsString());
|
||||
BindingCallback binding = bindings.get(bindingCall.name());
|
||||
|
||||
@@ -27,10 +27,7 @@ import com.microsoft.playwright.PlaywrightException;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
@@ -40,7 +37,8 @@ import static com.microsoft.playwright.impl.Utils.isSafeCloseError;
|
||||
class BrowserImpl extends ChannelOwner implements Browser {
|
||||
final Set<BrowserContextImpl> contexts = new HashSet<>();
|
||||
private final ListenerCollection<EventType> listeners = new ListenerCollection<>();
|
||||
public boolean isRemote;
|
||||
boolean isRemote;
|
||||
boolean isConnectedOverWebSocket;
|
||||
private boolean isConnected = true;
|
||||
|
||||
enum EventType {
|
||||
@@ -67,7 +65,7 @@ class BrowserImpl extends ChannelOwner implements Browser {
|
||||
}
|
||||
|
||||
private void closeImpl() {
|
||||
if (isRemote) {
|
||||
if (isConnectedOverWebSocket) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (IOException e) {
|
||||
@@ -182,6 +180,34 @@ class BrowserImpl extends ChannelOwner implements Browser {
|
||||
return withLogging("Browser.newPage", () -> newPageImpl(options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startTracing(Page page, StartTracingOptions options) {
|
||||
withLogging("Browser.startTracing", () -> startTracingImpl(page, options));
|
||||
}
|
||||
|
||||
private void startTracingImpl(Page page, StartTracingOptions options) {
|
||||
if (options == null) {
|
||||
options = new StartTracingOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
if (page != null) {
|
||||
JsonObject jsonPage = new JsonObject();
|
||||
jsonPage.addProperty("guid", ((PageImpl) page).guid);
|
||||
params.add("page", jsonPage);
|
||||
}
|
||||
sendMessage("startTracing", params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] stopTracing() {
|
||||
return withLogging("Browser.stopTracing", () -> stopTracingImpl());
|
||||
}
|
||||
|
||||
private byte[] stopTracingImpl() {
|
||||
JsonObject json = sendMessage("stopTracing").getAsJsonObject();
|
||||
return Base64.getDecoder().decode(json.get("binary").getAsString());
|
||||
}
|
||||
|
||||
private Page newPageImpl(NewPageOptions options) {
|
||||
BrowserContextImpl context = newContext(convertViaJson(options, NewContextOptions.class));
|
||||
PageImpl page = context.newPage();
|
||||
|
||||
@@ -27,6 +27,8 @@ import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
@@ -58,26 +60,34 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
|
||||
private Browser connectImpl(String wsEndpoint, ConnectOptions options) {
|
||||
try {
|
||||
Duration timeout = Duration.ofDays(1);
|
||||
if (options != null && options.timeout != null) {
|
||||
timeout = Duration.ofMillis(Math.round(options.timeout));
|
||||
}
|
||||
WebSocketTransport transport = new WebSocketTransport(new URI(wsEndpoint), timeout);
|
||||
Connection connection = new Connection(transport);
|
||||
RemoteBrowser remoteBrowser = (RemoteBrowser) connection.waitForObjectWithKnownName("remoteBrowser");
|
||||
PlaywrightImpl playwright = this.connection.getExistingObject("Playwright");
|
||||
SelectorsImpl selectors = remoteBrowser.selectors();
|
||||
playwright.sharedSelectors.addChannel(selectors);
|
||||
BrowserImpl browser = remoteBrowser.browser();
|
||||
browser.isRemote = true;
|
||||
Consumer<WebSocketTransport> connectionCloseListener = new Consumer<WebSocketTransport>() {
|
||||
@Override
|
||||
public void accept(WebSocketTransport t) {
|
||||
browser.notifyRemoteClosed();
|
||||
Map<String, String> headers = Collections.emptyMap();
|
||||
if (options != null) {
|
||||
if (options.timeout != null) {
|
||||
timeout = Duration.ofMillis(Math.round(options.timeout));
|
||||
}
|
||||
};
|
||||
if (options.headers != null) {
|
||||
headers = options.headers;
|
||||
}
|
||||
}
|
||||
WebSocketTransport transport = new WebSocketTransport(new URI(wsEndpoint), headers, timeout);
|
||||
Connection connection = new Connection(transport);
|
||||
PlaywrightImpl playwright = (PlaywrightImpl) connection.waitForObjectWithKnownName("Playwright");
|
||||
if (!playwright.initializer.has("preLaunchedBrowser")) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
throw new PlaywrightException("Malformed endpoint. Did you use launchServer method?");
|
||||
}
|
||||
playwright.initSharedSelectors(this.connection.getExistingObject("Playwright"));
|
||||
BrowserImpl browser = connection.getExistingObject(playwright.initializer.getAsJsonObject("preLaunchedBrowser").get("guid").getAsString());
|
||||
browser.isRemote = true;
|
||||
browser.isConnectedOverWebSocket = true;
|
||||
Consumer<WebSocketTransport> connectionCloseListener = t -> browser.notifyRemoteClosed();
|
||||
transport.onClose(connectionCloseListener);
|
||||
browser.onDisconnected(b -> {
|
||||
playwright.sharedSelectors.removeChannel(selectors);
|
||||
playwright.unregisterSelectors();
|
||||
transport.offClose(connectionCloseListener);
|
||||
try {
|
||||
connection.close();
|
||||
@@ -91,6 +101,34 @@ class BrowserTypeImpl extends ChannelOwner implements BrowserType {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Browser connectOverCDP(String endpointURL, ConnectOverCDPOptions options) {
|
||||
if (!"chromium".equals(name())) {
|
||||
throw new PlaywrightException("Connecting over CDP is only supported in Chromium.");
|
||||
}
|
||||
return withLogging("BrowserType.connectOverCDP", () -> connectOverCDPImpl(endpointURL, options));
|
||||
}
|
||||
|
||||
private Browser connectOverCDPImpl(String endpointURL, ConnectOverCDPOptions options) {
|
||||
if (options == null) {
|
||||
options = new ConnectOverCDPOptions();
|
||||
}
|
||||
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
params.addProperty("sdkLanguage", "java");
|
||||
params.addProperty("endpointURL", endpointURL);
|
||||
JsonObject json = sendMessage("connectOverCDP", params).getAsJsonObject();
|
||||
|
||||
BrowserImpl browser = connection.getExistingObject(json.getAsJsonObject("browser").get("guid").getAsString());
|
||||
browser.isRemote = true;
|
||||
if (json.has("defaultContext")) {
|
||||
String contextId = json.getAsJsonObject("defaultContext").get("guid").getAsString();
|
||||
BrowserContextImpl defaultContext = connection.getExistingObject(contextId);
|
||||
browser.contexts.add(defaultContext);
|
||||
}
|
||||
return browser;
|
||||
}
|
||||
|
||||
public String executablePath() {
|
||||
return initializer.get("executablePath").getAsString();
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.google.gson.JsonObject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
class ChannelOwner extends LoggingSupport {
|
||||
final Connection connection;
|
||||
@@ -67,6 +68,11 @@ class ChannelOwner extends LoggingSupport {
|
||||
objects.clear();
|
||||
}
|
||||
|
||||
<T> T withWaitLogging(String apiName, Supplier<T> code) {
|
||||
return super.withLogging(apiName, new WaitForEventLogger<>(this, apiName, code));
|
||||
}
|
||||
|
||||
|
||||
WaitableResult<JsonElement> sendMessageAsync(String method, JsonObject params) {
|
||||
return connection.sendMessageAsync(guid, method, params);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.microsoft.playwright.impl.LoggingSupport.logWithTimestamp;
|
||||
import static com.microsoft.playwright.impl.Serialization.gson;
|
||||
|
||||
class Message {
|
||||
@@ -67,6 +68,11 @@ public class Connection {
|
||||
private int lastId = 0;
|
||||
private final Path srcDir;
|
||||
private final Map<Integer, WaitableResult<JsonElement>> callbacks = new HashMap<>();
|
||||
private static final boolean isLogging;
|
||||
static {
|
||||
String debug = System.getenv("DEBUG");
|
||||
isLogging = (debug != null) && debug.contains("pw:channel");
|
||||
}
|
||||
|
||||
class Root extends ChannelOwner {
|
||||
Root(Connection connection) {
|
||||
@@ -153,7 +159,11 @@ public class Connection {
|
||||
metadata.add("stack", currentStackTrace());
|
||||
message.add("metadata", metadata);
|
||||
}
|
||||
transport.send(gson().toJson(message));
|
||||
String messageString = gson().toJson(message);
|
||||
if (isLogging) {
|
||||
logWithTimestamp("SEND ► " + messageString);
|
||||
}
|
||||
transport.send(messageString);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -184,6 +194,9 @@ public class Connection {
|
||||
if (messageString == null) {
|
||||
return;
|
||||
}
|
||||
if (isLogging) {
|
||||
logWithTimestamp("◀ RECV " + messageString);
|
||||
}
|
||||
Gson gson = gson();
|
||||
Message message = gson.fromJson(messageString, Message.class);
|
||||
dispatch(message);
|
||||
@@ -255,6 +268,9 @@ public class Connection {
|
||||
case "AndroidDevice":
|
||||
// result = new AndroidDevice(parent, type, guid, initializer);
|
||||
break;
|
||||
case "Artifact":
|
||||
result = new ArtifactImpl(parent, type, guid, initializer);
|
||||
break;
|
||||
case "BindingCall":
|
||||
result = new BindingCall(parent, type, guid, initializer);
|
||||
break;
|
||||
@@ -273,9 +289,6 @@ public class Connection {
|
||||
case "Dialog":
|
||||
result = new DialogImpl(parent, type, guid, initializer);
|
||||
break;
|
||||
case "Download":
|
||||
result = new DownloadImpl(parent, type, guid, initializer);
|
||||
break;
|
||||
case "Electron":
|
||||
// result = new Playwright(parent, type, guid, initializer);
|
||||
break;
|
||||
@@ -297,9 +310,6 @@ public class Connection {
|
||||
case "Request":
|
||||
result = new RequestImpl(parent, type, guid, initializer);
|
||||
break;
|
||||
case "RemoteBrowser":
|
||||
result = new RemoteBrowser(parent, type, guid, initializer);
|
||||
break;
|
||||
case "Response":
|
||||
result = new ResponseImpl(parent, type, guid, initializer);
|
||||
break;
|
||||
|
||||
@@ -16,27 +16,19 @@
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.microsoft.playwright.BrowserContext;
|
||||
import com.microsoft.playwright.Download;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static com.microsoft.playwright.impl.Utils.writeToFile;
|
||||
class DownloadImpl extends LoggingSupport implements Download {
|
||||
private final ArtifactImpl artifact;
|
||||
private final JsonObject initializer;
|
||||
|
||||
public class DownloadImpl extends ChannelOwner implements Download {
|
||||
private final BrowserImpl browser;
|
||||
|
||||
public DownloadImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
browser = ((BrowserContextImpl) parent).browser();
|
||||
DownloadImpl(ArtifactImpl artifact, JsonObject initializer) {
|
||||
this.artifact = artifact;
|
||||
this.initializer = initializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,58 +43,26 @@ public class DownloadImpl extends ChannelOwner implements Download {
|
||||
|
||||
@Override
|
||||
public InputStream createReadStream() {
|
||||
return withLogging("Download.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();
|
||||
});
|
||||
return withLogging("Download.createReadStream", () -> artifact.createReadStream());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
withLogging("Download.delete", () -> {
|
||||
sendMessage("delete");
|
||||
});
|
||||
withLogging("Download.delete", () -> artifact.delete());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String failure() {
|
||||
return withLogging("Download.failure", () -> {
|
||||
JsonObject result = sendMessage("failure").getAsJsonObject();
|
||||
if (result.has("error")) {
|
||||
return result.get("error").getAsString();
|
||||
}
|
||||
return null;
|
||||
});
|
||||
return withLogging("Download.failure", () -> artifact.failure());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path path() {
|
||||
return withLogging("Download.path", () -> {
|
||||
if (browser != null && browser.isRemote) {
|
||||
throw new PlaywrightException("Path is not available when using browserType.connect(). Use download.saveAs() to save a local copy.");
|
||||
}
|
||||
JsonObject json = sendMessage("path").getAsJsonObject();
|
||||
return FileSystems.getDefault().getPath(json.get("value").getAsString());
|
||||
});
|
||||
return withLogging("Download.path", () -> artifact.pathAfterFinished());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAs(Path path) {
|
||||
withLogging("Download.saveAs", () -> {
|
||||
if (browser != null && browser.isRemote) {
|
||||
JsonObject jsonObject = sendMessage("saveAsStream").getAsJsonObject();
|
||||
Stream stream = connection.getExistingObject(jsonObject.getAsJsonObject("stream").get("guid").getAsString());
|
||||
writeToFile(stream.stream(), path);
|
||||
return;
|
||||
}
|
||||
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("path", path.toString());
|
||||
sendMessage("saveAs", params);
|
||||
});
|
||||
withLogging("Download.saveAs", () -> artifact.saveAs(path));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.microsoft.playwright.options.LoadState.*;
|
||||
import static com.microsoft.playwright.impl.Serialization.*;
|
||||
@@ -856,10 +858,14 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
|
||||
@Override
|
||||
public Response waitForNavigation(WaitForNavigationOptions options, Runnable code) {
|
||||
return withLogging("Frame.waitForNavigation", () -> waitForNavigationImpl(code, options));
|
||||
return withLogging("Frame.waitForNavigation", () -> waitForNavigationImpl(code, options, null));
|
||||
}
|
||||
|
||||
Response waitForNavigationImpl(Runnable code, WaitForNavigationOptions options) {
|
||||
return waitForNavigationImpl(code, options, null);
|
||||
}
|
||||
|
||||
private Response waitForNavigationImpl(Runnable code, WaitForNavigationOptions options, UrlMatcher matcher) {
|
||||
if (options == null) {
|
||||
options = new WaitForNavigationOptions();
|
||||
}
|
||||
@@ -868,7 +874,9 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
|
||||
List<Waitable<Response>> waitables = new ArrayList<>();
|
||||
UrlMatcher matcher = UrlMatcher.forOneOf(options.url);
|
||||
if (matcher == null) {
|
||||
matcher = UrlMatcher.forOneOf(options.url);
|
||||
}
|
||||
waitables.add(new WaitForNavigationHelper(matcher, convertViaJson(options.waitUntil, LoadState.class)));
|
||||
waitables.add(page.createWaitForCloseHelper());
|
||||
waitables.add(page.createWaitableFrameDetach(this));
|
||||
@@ -910,6 +918,37 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitForURL(String url, WaitForURLOptions options) {
|
||||
waitForURL(new UrlMatcher(url), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitForURL(Pattern url, WaitForURLOptions options) {
|
||||
waitForURL(new UrlMatcher(url), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitForURL(Predicate<String> url, WaitForURLOptions options) {
|
||||
waitForURL(new UrlMatcher(url), options);
|
||||
}
|
||||
|
||||
private void waitForURL(UrlMatcher matcher, WaitForURLOptions options) {
|
||||
withLogging("Frame.waitForURL", () -> waitForURLImpl(matcher, options));
|
||||
}
|
||||
|
||||
void waitForURLImpl(UrlMatcher matcher, WaitForURLOptions options) {
|
||||
if (options == null) {
|
||||
options = new WaitForURLOptions();
|
||||
}
|
||||
if (matcher.test(url())) {
|
||||
waitForLoadStateImpl(convertViaJson(options.waitUntil, LoadState.class),
|
||||
convertViaJson(options, WaitForLoadStateOptions.class));
|
||||
return;
|
||||
}
|
||||
waitForNavigationImpl(() -> {}, convertViaJson(options, WaitForNavigationOptions.class), matcher);
|
||||
}
|
||||
|
||||
protected void handleEvent(String event, JsonObject params) {
|
||||
if ("loadstate".equals(event)) {
|
||||
JsonElement add = params.get("add");
|
||||
|
||||
@@ -54,9 +54,14 @@ class LoggingSupport {
|
||||
}
|
||||
}
|
||||
|
||||
private void logApi(String message) {
|
||||
static void logWithTimestamp(String message) {
|
||||
// This matches log format produced by the server.
|
||||
String timestamp = ZonedDateTime.now().format(timestampFormat);
|
||||
System.err.println(timestamp + " pw:api " + message);
|
||||
System.err.println(timestamp + " " + message);
|
||||
}
|
||||
|
||||
private void logApi(String message) {
|
||||
// This matches log format produced by the server.
|
||||
logWithTimestamp("pw:api " + message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
private final KeyboardImpl keyboard;
|
||||
private final MouseImpl mouse;
|
||||
private final TouchscreenImpl touchscreen;
|
||||
final Waitable<?> waitableClosedOrCrashed;
|
||||
private ViewportSize viewport;
|
||||
private final Router routes = new Router();
|
||||
private final Set<FrameImpl> frames = new LinkedHashSet<>();
|
||||
@@ -70,6 +71,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
final Set<Worker> workers = new HashSet<>();
|
||||
private final TimeoutSettings timeoutSettings;
|
||||
private VideoImpl video;
|
||||
private final PageImpl opener;
|
||||
|
||||
enum EventType {
|
||||
CLOSE,
|
||||
@@ -107,6 +109,12 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
touchscreen = new TouchscreenImpl(this);
|
||||
frames.add(mainFrame);
|
||||
timeoutSettings = new TimeoutSettings(browserContext.timeoutSettings);
|
||||
waitableClosedOrCrashed = createWaitForCloseHelper();
|
||||
if (initializer.has("opener")) {
|
||||
opener = connection.getExistingObject(initializer.getAsJsonObject("opener").get("guid").getAsString());
|
||||
} else {
|
||||
opener = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -119,10 +127,6 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
} else {
|
||||
dialog.dismiss();
|
||||
}
|
||||
} else if ("popup".equals(event)) {
|
||||
String guid = params.getAsJsonObject("page").get("guid").getAsString();
|
||||
PageImpl popup = connection.getExistingObject(guid);
|
||||
listeners.notify(EventType.POPUP, popup);
|
||||
} else if ("worker".equals(event)) {
|
||||
String guid = params.getAsJsonObject("worker").get("guid").getAsString();
|
||||
WorkerImpl worker = connection.getExistingObject(guid);
|
||||
@@ -138,8 +142,10 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
ConsoleMessageImpl message = connection.getExistingObject(guid);
|
||||
listeners.notify(EventType.CONSOLE, message);
|
||||
} else if ("download".equals(event)) {
|
||||
String guid = params.getAsJsonObject("download").get("guid").getAsString();
|
||||
DownloadImpl download = connection.getExistingObject(guid);
|
||||
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(artifact, params);
|
||||
listeners.notify(EventType.DOWNLOAD, download);
|
||||
} else if ("fileChooser".equals(event)) {
|
||||
String guid = params.getAsJsonObject("element").get("guid").getAsString();
|
||||
@@ -211,7 +217,9 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
route.resume();
|
||||
}
|
||||
} else if ("video".equals(event)) {
|
||||
video().setRelativePath(params.get("relativePath").getAsString());
|
||||
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 = "";
|
||||
@@ -229,6 +237,10 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
}
|
||||
}
|
||||
|
||||
void notifyPopup(PageImpl popup) {
|
||||
listeners.notify(EventType.POPUP, popup);
|
||||
}
|
||||
|
||||
void didClose() {
|
||||
isClosed = true;
|
||||
browserContext.pages.remove(this);
|
||||
@@ -445,6 +457,10 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public Page waitForClose(WaitForCloseOptions options, Runnable code) {
|
||||
return withWaitLogging("Page.waitForClose", () -> waitForCloseImpl(options, code));
|
||||
}
|
||||
|
||||
private Page waitForCloseImpl(WaitForCloseOptions options, Runnable code) {
|
||||
if (options == null) {
|
||||
options = new WaitForCloseOptions();
|
||||
}
|
||||
@@ -453,22 +469,22 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public ConsoleMessage waitForConsoleMessage(WaitForConsoleMessageOptions options, Runnable code) {
|
||||
return withWaitLogging("Page.waitForConsoleMessage", () -> waitForConsoleMessageImpl(options, code));
|
||||
}
|
||||
|
||||
private ConsoleMessage waitForConsoleMessageImpl(WaitForConsoleMessageOptions options, Runnable code) {
|
||||
if (options == null) {
|
||||
options = new WaitForConsoleMessageOptions();
|
||||
}
|
||||
return waitForEventWithTimeout(EventType.CONSOLE, code, options.timeout);
|
||||
}
|
||||
|
||||
private <T> T waitForEventWithTimeout(EventType eventType, Runnable code, Double timeout) {
|
||||
List<Waitable<T>> waitables = new ArrayList<>();
|
||||
waitables.add(new WaitableEvent<>(listeners, eventType));
|
||||
waitables.add(createWaitForCloseHelper());
|
||||
waitables.add(createWaitableTimeout(timeout));
|
||||
return runUntil(code, new WaitableRace<>(waitables));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Download waitForDownload(WaitForDownloadOptions options, Runnable code) {
|
||||
return withWaitLogging("Page.waitForDownload", () -> waitForDownloadImpl(options, code));
|
||||
}
|
||||
|
||||
private Download waitForDownloadImpl(WaitForDownloadOptions options, Runnable code) {
|
||||
if (options == null) {
|
||||
options = new WaitForDownloadOptions();
|
||||
}
|
||||
@@ -477,6 +493,10 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public FileChooser waitForFileChooser(WaitForFileChooserOptions options, Runnable code) {
|
||||
return withWaitLogging("Page.waitForFileChooser", () -> waitForFileChooserImpl(options, code));
|
||||
}
|
||||
|
||||
private FileChooser waitForFileChooserImpl(WaitForFileChooserOptions options, Runnable code) {
|
||||
// TODO: enable/disable file chooser interception
|
||||
if (options == null) {
|
||||
options = new WaitForFileChooserOptions();
|
||||
@@ -486,6 +506,10 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public Page waitForPopup(WaitForPopupOptions options, Runnable code) {
|
||||
return withWaitLogging("Page.waitForPopup", () -> waitForPopupImpl(options, code));
|
||||
}
|
||||
|
||||
private Page waitForPopupImpl(WaitForPopupOptions options, Runnable code) {
|
||||
if (options == null) {
|
||||
options = new WaitForPopupOptions();
|
||||
}
|
||||
@@ -494,6 +518,10 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public WebSocket waitForWebSocket(WaitForWebSocketOptions options, Runnable code) {
|
||||
return withWaitLogging("Page.waitForWebSocket", () -> waitForWebSocketImpl(options, code));
|
||||
}
|
||||
|
||||
private WebSocket waitForWebSocketImpl(WaitForWebSocketOptions options, Runnable code) {
|
||||
if (options == null) {
|
||||
options = new WaitForWebSocketOptions();
|
||||
}
|
||||
@@ -502,12 +530,24 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public Worker waitForWorker(WaitForWorkerOptions options, Runnable code) {
|
||||
return withWaitLogging("Page.waitForWorker", () -> waitForWorkerImpl(options, code));
|
||||
}
|
||||
|
||||
private Worker waitForWorkerImpl(WaitForWorkerOptions options, Runnable code) {
|
||||
if (options == null) {
|
||||
options = new WaitForWorkerOptions();
|
||||
}
|
||||
return waitForEventWithTimeout(EventType.WORKER, code, options.timeout);
|
||||
}
|
||||
|
||||
private <T> T waitForEventWithTimeout(EventType eventType, Runnable code, Double timeout) {
|
||||
List<Waitable<T>> waitables = new ArrayList<>();
|
||||
waitables.add(new WaitableEvent<>(listeners, eventType));
|
||||
waitables.add(createWaitForCloseHelper());
|
||||
waitables.add(createWaitableTimeout(timeout));
|
||||
return runUntil(code, new WaitableRace<>(waitables));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(CloseOptions options) {
|
||||
if (isClosed) {
|
||||
@@ -843,14 +883,11 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page opener() {
|
||||
return withLogging("Page.opener", () -> {
|
||||
JsonObject result = sendMessage("opener").getAsJsonObject();
|
||||
if (!result.has("page")) {
|
||||
return null;
|
||||
}
|
||||
return connection.getExistingObject(result.getAsJsonObject("page").get("guid").getAsString());
|
||||
});
|
||||
public PageImpl opener() {
|
||||
if (opener == null || opener.isClosed()) {
|
||||
return null;
|
||||
}
|
||||
return opener;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1144,20 +1181,23 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
return mainFrame.url();
|
||||
}
|
||||
|
||||
|
||||
private VideoImpl forceVideo() {
|
||||
if (video == null) {
|
||||
video = new VideoImpl(this);
|
||||
}
|
||||
return video;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VideoImpl video() {
|
||||
if (video != null) {
|
||||
return video;
|
||||
}
|
||||
// Note: we are creating Video object lazily, because we do not know
|
||||
// BrowserContextOptions when constructing the page - it is assigned
|
||||
// too late during launchPersistentContext.
|
||||
if (browserContext.videosDir == null) {
|
||||
return null;
|
||||
}
|
||||
video = new VideoImpl(this);
|
||||
// In case of persistent profile, we already have it.
|
||||
if (initializer.has("videoRelativePath")) {
|
||||
video.setRelativePath(initializer.get("videoRelativePath").getAsString());
|
||||
}
|
||||
return video;
|
||||
return forceVideo();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1259,7 +1299,7 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
|
||||
@Override
|
||||
public Request waitForRequest(Predicate<Request> predicate, WaitForRequestOptions options, Runnable code) {
|
||||
return withLogging("Page.waitForRequest", () -> waitForRequestImpl(predicate, options, code));
|
||||
return withWaitLogging("Page.waitForRequest", () -> waitForRequestImpl(predicate, options, code));
|
||||
}
|
||||
|
||||
private static Predicate<Request> toRequestPredicate(UrlMatcher matcher) {
|
||||
@@ -1320,6 +1360,25 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
withLogging("Page.waitForTimeout", () -> mainFrame.waitForTimeoutImpl(timeout));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitForURL(String url, WaitForURLOptions options) {
|
||||
waitForURL(new UrlMatcher(url), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitForURL(Pattern url, WaitForURLOptions options) {
|
||||
waitForURL(new UrlMatcher(url), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void waitForURL(Predicate<String> url, WaitForURLOptions options) {
|
||||
waitForURL(new UrlMatcher(url), options);
|
||||
}
|
||||
|
||||
private void waitForURL(UrlMatcher matcher, WaitForURLOptions options) {
|
||||
withLogging("Page.waitForURL", () -> mainFrame.waitForURLImpl(matcher, convertViaJson(options, Frame.WaitForURLOptions.class)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Worker> workers() {
|
||||
return new ArrayList<>(workers);
|
||||
|
||||
@@ -59,7 +59,16 @@ public class PipeTransport implements Transport {
|
||||
throw new PlaywrightException("Playwright connection closed");
|
||||
}
|
||||
try {
|
||||
return incoming.poll(timeout.toMillis(), TimeUnit.MILLISECONDS);
|
||||
String message = incoming.poll(timeout.toMillis(), TimeUnit.MILLISECONDS);
|
||||
if (message == null && readerThread.exception != null) {
|
||||
try {
|
||||
close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
throw new PlaywrightException("Failed to read message from driver, pipe closed.", readerThread.exception);
|
||||
}
|
||||
return message;
|
||||
} catch (InterruptedException e) {
|
||||
throw new PlaywrightException("Failed to read message", e);
|
||||
}
|
||||
@@ -84,6 +93,7 @@ class ReaderThread extends Thread {
|
||||
private final DataInputStream in;
|
||||
private final BlockingQueue<String> queue;
|
||||
volatile boolean isClosing;
|
||||
volatile Exception exception;
|
||||
|
||||
private static int readIntLE(DataInputStream in) throws IOException {
|
||||
int ch1 = in.read();
|
||||
@@ -109,7 +119,7 @@ class ReaderThread extends Thread {
|
||||
queue.put(readMessage());
|
||||
} catch (IOException e) {
|
||||
if (!isInterrupted() && !isClosing) {
|
||||
e.printStackTrace();
|
||||
exception = e;
|
||||
}
|
||||
break;
|
||||
} catch (InterruptedException e) {
|
||||
|
||||
@@ -38,6 +38,7 @@ public class PlaywrightImpl extends ChannelOwner implements Playwright {
|
||||
Connection connection = new Connection(new PipeTransport(p.getInputStream(), p.getOutputStream()));
|
||||
PlaywrightImpl result = (PlaywrightImpl) connection.waitForObjectWithKnownName("Playwright");
|
||||
result.driverProcess = p;
|
||||
result.initSharedSelectors(null);
|
||||
return result;
|
||||
} catch (IOException e) {
|
||||
throw new PlaywrightException("Failed to launch driver", e);
|
||||
@@ -47,15 +48,30 @@ public class PlaywrightImpl extends ChannelOwner implements Playwright {
|
||||
private final BrowserTypeImpl chromium;
|
||||
private final BrowserTypeImpl firefox;
|
||||
private final BrowserTypeImpl webkit;
|
||||
final SharedSelectors sharedSelectors = new SharedSelectors();;
|
||||
private final SelectorsImpl selectors;
|
||||
private SharedSelectors sharedSelectors;;
|
||||
|
||||
PlaywrightImpl(ChannelOwner parent, String type, String guid, JsonObject initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
chromium = parent.connection.getExistingObject(initializer.getAsJsonObject("chromium").get("guid").getAsString());
|
||||
firefox = parent.connection.getExistingObject(initializer.getAsJsonObject("firefox").get("guid").getAsString());
|
||||
webkit = parent.connection.getExistingObject(initializer.getAsJsonObject("webkit").get("guid").getAsString());
|
||||
SelectorsImpl channel = parent.connection.getExistingObject(initializer.getAsJsonObject("selectors").get("guid").getAsString());
|
||||
sharedSelectors.addChannel(channel);
|
||||
|
||||
selectors = connection.getExistingObject(initializer.getAsJsonObject("selectors").get("guid").getAsString());
|
||||
}
|
||||
|
||||
void initSharedSelectors(PlaywrightImpl parent) {
|
||||
assert sharedSelectors == null;
|
||||
if (parent == null) {
|
||||
sharedSelectors = new SharedSelectors();;
|
||||
} else {
|
||||
sharedSelectors = parent.sharedSelectors;
|
||||
}
|
||||
sharedSelectors.addChannel(selectors);
|
||||
}
|
||||
|
||||
void unregisterSelectors() {
|
||||
sharedSelectors.removeChannel(selectors);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,8 +20,9 @@ import com.google.gson.*;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import com.microsoft.playwright.ElementHandle;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
import com.microsoft.playwright.options.*;
|
||||
import com.microsoft.playwright.*;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -38,6 +39,7 @@ class Serialization {
|
||||
if (gson == null) {
|
||||
gson = new GsonBuilder()
|
||||
.registerTypeAdapter(SameSiteAttribute.class, new SameSiteAdapter().nullSafe())
|
||||
.registerTypeAdapter(BrowserChannel.class, new BrowserChannelSerializer())
|
||||
.registerTypeAdapter(ColorScheme.class, new ColorSchemeAdapter().nullSafe())
|
||||
.registerTypeAdapter(Media.class, new MediaSerializer())
|
||||
.registerTypeAdapter(ScreenshotType.class, new ToLowerCaseSerializer<ScreenshotType>())
|
||||
@@ -48,8 +50,9 @@ class Serialization {
|
||||
.registerTypeAdapter((new TypeToken<List<KeyboardModifier>>(){}).getType(), new KeyboardModifiersSerializer())
|
||||
.registerTypeAdapter(Optional.class, new OptionalSerializer())
|
||||
.registerTypeHierarchyAdapter(JSHandleImpl.class, new HandleSerializer())
|
||||
.registerTypeHierarchyAdapter(Map.class, new StringMapSerializer())
|
||||
.registerTypeAdapter(Path.class, new PathSerializer()).create();
|
||||
.registerTypeAdapter((new TypeToken<Map<String, String>>(){}).getType(), new StringMapSerializer())
|
||||
.registerTypeAdapter((new TypeToken<Map<String, Object>>(){}).getType(), new FirefoxUserPrefsSerializer())
|
||||
.registerTypeHierarchyAdapter(Path.class, new PathSerializer()).create();
|
||||
}
|
||||
return gson;
|
||||
}
|
||||
@@ -274,6 +277,16 @@ class Serialization {
|
||||
}
|
||||
}
|
||||
|
||||
private static class FirefoxUserPrefsSerializer implements JsonSerializer<Map<String, Object>> {
|
||||
@Override
|
||||
public JsonElement serialize(Map<String, Object> src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
if (!"java.util.Map<java.lang.String, java.lang.Object>".equals(typeOfSrc.getTypeName())) {
|
||||
throw new PlaywrightException("Unexpected map type: " + typeOfSrc);
|
||||
}
|
||||
return context.serialize(src, Map.class);
|
||||
}
|
||||
}
|
||||
|
||||
private static class StringMapSerializer implements JsonSerializer<Map<String, String>> {
|
||||
@Override
|
||||
public JsonElement serialize(Map<String, String> src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
@@ -284,6 +297,13 @@ 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 MediaSerializer implements JsonSerializer<Media> {
|
||||
@Override
|
||||
public JsonElement serialize(Media src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
|
||||
@@ -16,32 +16,40 @@
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.microsoft.playwright.FileChooser;
|
||||
import com.google.gson.*;
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
import com.microsoft.playwright.options.FilePayload;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
|
||||
class Utils {
|
||||
// TODO: generate converter.
|
||||
static <F, T> T convertViaJson(F f, Class<T> t) {
|
||||
Gson gson = new Gson();
|
||||
Gson gson = new GsonBuilder()
|
||||
// Necessary to avoid access to private fields/classes,
|
||||
// see https://github.com/microsoft/playwright-java/issues/423
|
||||
.registerTypeAdapter(Optional.class, new OptionalSerializer())
|
||||
.create();
|
||||
String json = gson.toJson(f);
|
||||
return gson.fromJson(json, t);
|
||||
}
|
||||
|
||||
static boolean isFunctionBody(String expression) {
|
||||
expression = expression.trim();
|
||||
return expression.startsWith("function") ||
|
||||
expression.startsWith("async ") ||
|
||||
expression.contains("=>");
|
||||
private static class OptionalSerializer implements JsonSerializer<Optional> {
|
||||
@Override
|
||||
public JsonElement serialize(Optional src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject result = new JsonObject();
|
||||
if (src.isPresent()) {
|
||||
result.add("value", context.serialize(src.get()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
static Set<Character> escapeGlobChars = new HashSet<>(Arrays.asList('/', '$', '^', '+', '.', '(', ')', '=', '!', '|'));
|
||||
@@ -171,4 +179,12 @@ class Utils {
|
||||
return error.endsWith("Browser has been closed") || error.endsWith("Target page, context or browser has been closed");
|
||||
}
|
||||
|
||||
static String createGuid() {
|
||||
StringBuffer result = new StringBuffer();
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.append(Integer.toHexString(random.nextInt()));
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,27 +16,67 @@
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.microsoft.playwright.PlaywrightException;
|
||||
import com.microsoft.playwright.Video;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
class VideoImpl implements Video {
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
class VideoImpl extends LoggingSupport implements Video {
|
||||
private final PageImpl page;
|
||||
private Path fullPath;
|
||||
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 setRelativePath(String path) {
|
||||
fullPath = page.context().videosDir.resolve(path);
|
||||
void setArtifact(ArtifactImpl artifact) {
|
||||
artifact.isRemote = isRemote;
|
||||
waitableArtifact.complete(artifact);
|
||||
}
|
||||
|
||||
private ArtifactImpl waitForArtifact() {
|
||||
Waitable<ArtifactImpl> waitable = new WaitableRace<>(asList(waitableArtifact, (Waitable<ArtifactImpl>) page.waitableClosedOrCrashed));
|
||||
return page.runUntil(() -> {}, waitable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
withLogging("Video.delete", () -> {
|
||||
try {
|
||||
waitForArtifact().delete();
|
||||
} catch (PlaywrightException e) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path path() {
|
||||
while (fullPath == null) {
|
||||
page.connection.processOneMessage();
|
||||
}
|
||||
return fullPath;
|
||||
return withLogging("Video.path", () -> {
|
||||
if (isRemote) {
|
||||
throw new PlaywrightException("Path is not available when using browserType.connect(). Use saveAs() to save a local copy.");
|
||||
}
|
||||
try {
|
||||
return Paths.get(waitForArtifact().initializer.get("absolutePath").getAsString());
|
||||
} catch (PlaywrightException e) {
|
||||
throw new PlaywrightException("Page did not produce any video frames", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAs(Path path) {
|
||||
withLogging("Video.saveAs", () -> {
|
||||
try {
|
||||
waitForArtifact().saveAs(path);
|
||||
} catch (PlaywrightException e) {
|
||||
throw new PlaywrightException("Page did not produce any video frames", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.impl;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static com.microsoft.playwright.impl.Utils.createGuid;
|
||||
|
||||
public class WaitForEventLogger<T> implements Supplier<T> {
|
||||
private final Supplier<T> supplier;
|
||||
private final ChannelOwner channel;
|
||||
private final String waitId;
|
||||
private final String apiName;
|
||||
|
||||
WaitForEventLogger(ChannelOwner channelOwner, String apiName, Supplier<T> supplier) {
|
||||
this.supplier = supplier;
|
||||
this.channel = channelOwner;
|
||||
this.apiName = apiName;
|
||||
this.waitId = createGuid();
|
||||
JsonObject info = new JsonObject();
|
||||
info.addProperty("phase", "before");
|
||||
sendWaitForEventInfo(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
JsonObject info = new JsonObject();
|
||||
info.addProperty("phase", "after");
|
||||
try {
|
||||
return supplier.get();
|
||||
} catch (RuntimeException e) {
|
||||
info.addProperty("error", e.getMessage());
|
||||
throw e;
|
||||
} finally {
|
||||
sendWaitForEventInfo(info);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendWaitForEventInfo(JsonObject info) {
|
||||
info.addProperty("apiName", apiName);
|
||||
info.addProperty("waitId", waitId);
|
||||
JsonObject params = new JsonObject();
|
||||
params.add("info", info);
|
||||
channel.sendMessageAsync("waitForEventInfo", params);
|
||||
}
|
||||
}
|
||||
@@ -86,6 +86,10 @@ class WebSocketImpl extends ChannelOwner implements WebSocket {
|
||||
|
||||
@Override
|
||||
public WebSocketFrame waitForFrameReceived(WaitForFrameReceivedOptions options, Runnable code) {
|
||||
return withWaitLogging("WebSocket.waitForFrameReceived", () -> waitForFrameReceivedImpl(options, code));
|
||||
}
|
||||
|
||||
private WebSocketFrame waitForFrameReceivedImpl(WaitForFrameReceivedOptions options, Runnable code) {
|
||||
if (options == null) {
|
||||
options = new WaitForFrameReceivedOptions();
|
||||
}
|
||||
@@ -94,6 +98,10 @@ class WebSocketImpl extends ChannelOwner implements WebSocket {
|
||||
|
||||
@Override
|
||||
public WebSocketFrame waitForFrameSent(WaitForFrameSentOptions options, Runnable code) {
|
||||
return withWaitLogging("WebSocket.waitForFrameSent", () -> waitForFrameSentImpl(options, code));
|
||||
}
|
||||
|
||||
private WebSocketFrame waitForFrameSentImpl(WaitForFrameSentOptions options, Runnable code) {
|
||||
if (options == null) {
|
||||
options = new WaitForFrameSentOptions();
|
||||
}
|
||||
|
||||
@@ -23,14 +23,15 @@ import org.java_websocket.handshake.ServerHandshake;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
||||
class WebSocketTransport implements Transport {
|
||||
private final BlockingQueue<String> incoming = new ArrayBlockingQueue<>(1000);
|
||||
private final BlockingQueue<String> incoming = new LinkedBlockingQueue<>();
|
||||
private final ClientConnection clientConnection;
|
||||
private boolean isClosed;
|
||||
private volatile Exception lastError;
|
||||
@@ -62,8 +63,11 @@ class WebSocketTransport implements Transport {
|
||||
}
|
||||
}
|
||||
|
||||
WebSocketTransport(URI uri, Duration timeout) {
|
||||
WebSocketTransport(URI uri, Map<String, String> headers, Duration timeout) {
|
||||
clientConnection = new ClientConnection(uri);
|
||||
for (Map.Entry<String, String> entry : headers.entrySet()) {
|
||||
clientConnection.addHeader(entry.getKey(), entry.getValue());
|
||||
}
|
||||
try {
|
||||
if (!clientConnection.connectBlocking(timeout.toMillis(), TimeUnit.MILLISECONDS)) {
|
||||
throw new PlaywrightException("Failed to connect", lastError);
|
||||
|
||||
@@ -59,6 +59,10 @@ class WorkerImpl extends ChannelOwner implements Worker {
|
||||
|
||||
@Override
|
||||
public Worker waitForClose(WaitForCloseOptions options, Runnable code) {
|
||||
return withWaitLogging("Worker.waitForClose", () -> waitForCloseImpl(options, code));
|
||||
}
|
||||
|
||||
private Worker waitForCloseImpl(WaitForCloseOptions options, Runnable code) {
|
||||
if (options == null) {
|
||||
options = new WaitForCloseOptions();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 BrowserChannel {
|
||||
CHROME,
|
||||
CHROME_BETA,
|
||||
CHROME_DEV,
|
||||
CHROME_CANARY,
|
||||
MSEDGE,
|
||||
MSEDGE_BETA,
|
||||
MSEDGE_DEV,
|
||||
MSEDGE_CANARY,
|
||||
FIREFOX_STABLE
|
||||
}
|
||||
@@ -18,11 +18,11 @@ package com.microsoft.playwright.options;
|
||||
|
||||
public class FilePayload {
|
||||
/**
|
||||
* [File] name
|
||||
* File name
|
||||
*/
|
||||
public String name;
|
||||
/**
|
||||
* [File] type
|
||||
* File type
|
||||
*/
|
||||
public String mimeType;
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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 class ScreenSize {
|
||||
/**
|
||||
* page width in pixels.
|
||||
*/
|
||||
public int width;
|
||||
/**
|
||||
* page height in pixels.
|
||||
*/
|
||||
public int height;
|
||||
|
||||
public ScreenSize(int width, int height) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
*/
|
||||
public class TestAutoClose {
|
||||
@Test
|
||||
void shouldAllowUsingTryWithResources() throws Exception {
|
||||
void shouldAllowUsingTryWithResources() {
|
||||
try (Playwright playwright = Playwright.create();
|
||||
Browser browser = Utils.getBrowserTypeFromEnv(playwright).launch();
|
||||
BrowserContext context = browser.newContext();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.options.BrowserChannel;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
@@ -23,6 +24,8 @@ import org.junit.jupiter.api.BeforeEach;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static com.microsoft.playwright.Utils.getBrowserNameFromEnv;
|
||||
|
||||
public class TestBase {
|
||||
static Server server;
|
||||
static Server httpsServer;
|
||||
@@ -40,15 +43,33 @@ public class TestBase {
|
||||
}
|
||||
|
||||
static boolean isChromium() {
|
||||
return "chromium".equals(browserType.name());
|
||||
return "chromium".equals(getBrowserNameFromEnv());
|
||||
}
|
||||
|
||||
static boolean isWebKit() {
|
||||
return "webkit".equals(browserType.name());
|
||||
return "webkit".equals(getBrowserNameFromEnv());
|
||||
}
|
||||
|
||||
static boolean isFirefox() {
|
||||
return "firefox".equals(browserType.name());
|
||||
return "firefox".equals(getBrowserNameFromEnv());
|
||||
}
|
||||
|
||||
static BrowserChannel getBrowserChannelFromEnv() {
|
||||
String channel = System.getenv("BROWSER_CHANNEL");
|
||||
if (channel == null) {
|
||||
return null;
|
||||
}
|
||||
switch (channel) {
|
||||
case "chrome": return BrowserChannel.CHROME;
|
||||
case "chrome-beta": return BrowserChannel.CHROME_BETA;
|
||||
case "chrome-dev": return BrowserChannel.CHROME_DEV;
|
||||
case "chrome-canary": return BrowserChannel.CHROME_CANARY;
|
||||
case "msedge": return BrowserChannel.MSEDGE;
|
||||
case "msedge-beta": return BrowserChannel.MSEDGE_BETA;
|
||||
case "msedge-dev": return BrowserChannel.MSEDGE_DEV;
|
||||
case "msedge-canary": return BrowserChannel.MSEDGE_CANARY;
|
||||
default: throw new IllegalArgumentException("Unknown BROWSER_CHANNEL " + channel);
|
||||
}
|
||||
}
|
||||
|
||||
static BrowserType.LaunchOptions createLaunchOptions() {
|
||||
@@ -57,6 +78,7 @@ public class TestBase {
|
||||
BrowserType.LaunchOptions options;
|
||||
options = new BrowserType.LaunchOptions();
|
||||
options.headless = !headful;
|
||||
options.channel = getBrowserChannelFromEnv();
|
||||
return options;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ import org.junit.jupiter.api.condition.DisabledIf;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.microsoft.playwright.Utils.assertJsonEquals;
|
||||
import static com.microsoft.playwright.Utils.getOS;
|
||||
@@ -183,4 +185,19 @@ public class TestBrowserContextCookies extends TestBase {
|
||||
" sameSite: 'NONE'\n" +
|
||||
"}]", cookies);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAcceptSameSiteAttribute() {
|
||||
context.addCookies(asList(
|
||||
new Cookie("one", "uno").setUrl(server.EMPTY_PAGE).setSameSite(SameSiteAttribute.LAX),
|
||||
new Cookie("two", "dos").setUrl(server.EMPTY_PAGE).setSameSite(SameSiteAttribute.STRICT),
|
||||
new Cookie("three", "tres").setUrl(server.EMPTY_PAGE).setSameSite(SameSiteAttribute.NONE)));
|
||||
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Object documentCookie = page.evaluate("document.cookie.split('; ').sort().join('; ')");
|
||||
assertEquals("one=uno; three=tres; two=dos", documentCookie);
|
||||
|
||||
List<SameSiteAttribute> list = context.cookies().stream().map(c -> c.sameSite).sorted().collect(Collectors.toList());
|
||||
assertEquals(asList( SameSiteAttribute.STRICT, SameSiteAttribute.LAX, SameSiteAttribute.NONE), list);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -88,8 +88,10 @@ public class TestBrowserContextExposeFunction extends TestBase {
|
||||
context.exposeFunction("woof", args -> actualArgs.add(args[0]));
|
||||
context.addInitScript("window['woof']('context')");
|
||||
Page page = context.newPage();
|
||||
page.addInitScript("window['woof']('page')");
|
||||
page.evaluate("undefined");
|
||||
assertEquals(asList("context"), actualArgs);
|
||||
actualArgs.clear();
|
||||
page.addInitScript("window['woof']('page')");
|
||||
page.reload();
|
||||
assertEquals(asList("context", "page"), actualArgs);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* 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 com.microsoft.playwright.options.LoadState;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class TestBrowserContextLocale extends TestBase {
|
||||
@Test
|
||||
void shouldAffectAcceptLanguageHeader() throws ExecutionException, InterruptedException {
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions().setLocale("fr-CH"));
|
||||
Page page = context.newPage();
|
||||
Future<Server.Request> request = server.futureRequest("/empty.html");
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
assertEquals("fr-CH", request.get().headers.get("accept-language").get(0).substring(0, 5));
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAffectNavigatorLanguage() {
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions().setLocale("fr-CH"));
|
||||
Page page = context.newPage();
|
||||
assertEquals("fr-CH", page.evaluate("() => navigator.language"));
|
||||
context.close();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void shouldFormatNumber() {
|
||||
{
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions().setLocale("en-US"));
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
assertEquals("1,000,000.5", page.evaluate("() => (1000000.50).toLocaleString()"));
|
||||
context.close();
|
||||
}
|
||||
{
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions().setLocale("fr-CH"));
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
assertEquals("1 000 000,5", page.evaluate("() => (1000000.50).toLocaleString().replace(/\\s/g, ' ')"));
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFormatDate() {
|
||||
{
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions()
|
||||
.setLocale("en-US").setTimezoneId("America/Los_Angeles"));
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
String formatted = "Sat Nov 19 2016 10:12:34 GMT-0800 (Pacific Standard Time)";
|
||||
assertEquals(formatted, page.evaluate("new Date(1479579154987).toString()"));
|
||||
context.close();
|
||||
}
|
||||
{
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions()
|
||||
.setLocale("de-DE").setTimezoneId("Europe/Berlin"));
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
assertEquals("Sat Nov 19 2016 19:12:34 GMT+0100 (Mitteleuropäische Normalzeit)",
|
||||
page.evaluate("new Date(1479579154987).toString()"));
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFormatNumberInPopups() {
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions().setLocale("fr-CH"));
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Page popup = page.waitForPopup(() -> page.evaluate(
|
||||
"url => window.open(url)", server.PREFIX + "/formatted-number.html"));
|
||||
popup.waitForLoadState(LoadState.DOMCONTENTLOADED);
|
||||
Object result = popup.evaluate("window['result']");
|
||||
assertEquals("1 000 000,5", result);
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAffectNavigatorLanguageInPopups() {
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions().setLocale("fr-CH"));
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Page popup = page.waitForPopup(() -> page.evaluate(
|
||||
"url => window.open(url)", server.PREFIX + "/formatted-number.html"));
|
||||
popup.waitForLoadState(LoadState.DOMCONTENTLOADED);
|
||||
Object result = popup.evaluate("window.initialNavigatorLanguage");
|
||||
assertEquals("fr-CH", result);
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWorkForMultiplePagesSharingSameProcess() {
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions().setLocale("ru-RU"));
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Page popup = page.waitForPopup(() -> page.evaluate(
|
||||
"url => window.open(url)", server.EMPTY_PAGE));
|
||||
popup = page.waitForPopup(() -> page.evaluate(
|
||||
"url => window.open(url)", server.EMPTY_PAGE));
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldBeIsolatedBetweenContexts() {
|
||||
BrowserContext context1 = browser.newContext(new Browser.NewContextOptions().setLocale("en-US"));
|
||||
// By default firefox limits number of child web processes to 8.
|
||||
for (int i = 0; i < 8; i++)
|
||||
context1.newPage();
|
||||
|
||||
BrowserContext context2 = browser.newContext(new Browser.NewContextOptions().setLocale("ru-RU"));
|
||||
Page page2 = context2.newPage();
|
||||
|
||||
String localeNumber = "(1000000.50).toLocaleString()";
|
||||
for (Page page : context1.pages()) {
|
||||
assertEquals("1,000,000.5", page.evaluate(localeNumber));
|
||||
}
|
||||
assertEquals("1 000 000,5", page2.evaluate(localeNumber));
|
||||
context1.close();
|
||||
context2.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotChangeDefaultLocaleInAnotherContext() {
|
||||
Function<BrowserContext, String> getContextLocale = (context) -> {
|
||||
Page page = context.newPage();
|
||||
return (String) page.evaluate("(new Intl.NumberFormat()).resolvedOptions().locale");
|
||||
};
|
||||
|
||||
String defaultLocale;
|
||||
{
|
||||
BrowserContext context = browser.newContext();
|
||||
defaultLocale = getContextLocale.apply(context);
|
||||
context.close();
|
||||
}
|
||||
String localeOverride = "ru-RU".equals(defaultLocale) ? "de-DE" : "ru-RU";
|
||||
{
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions().setLocale(localeOverride));
|
||||
assertEquals(localeOverride, getContextLocale.apply(context));
|
||||
context.close();
|
||||
}
|
||||
{
|
||||
BrowserContext context = browser.newContext();
|
||||
assertEquals(defaultLocale, getContextLocale.apply(context));
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.microsoft.playwright.options.Proxy;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledIf;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.Base64;
|
||||
@@ -37,16 +38,18 @@ public class TestBrowserContextProxy extends TestBase {
|
||||
launchBrowser(options);
|
||||
}
|
||||
|
||||
static boolean isChromiumWindows() {
|
||||
return isChromium() && isWindows;
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowForMissingGlobalProxy() {
|
||||
Browser browser = browserType.launch(createLaunchOptions());
|
||||
try {
|
||||
@EnabledIf(value="isChromiumWindows", disabledReason="Platform-specific")
|
||||
void shouldThrowForMissingGlobalProxyOnChromiumWindows() {
|
||||
try (Browser browser = browserType.launch(createLaunchOptions())) {
|
||||
browser.newContext(new Browser.NewContextOptions().setProxy("localhost:" + server.PORT));
|
||||
fail("did not throw");
|
||||
} catch (PlaywrightException e) {
|
||||
assertTrue(e.getMessage().contains("Browser needs to be launched with the global proxy"));
|
||||
} finally {
|
||||
browser.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 org.junit.jupiter.api.Assumptions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledIf;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static com.microsoft.playwright.Utils.getBrowserNameFromEnv;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestBrowserTypeBasic extends TestBase {
|
||||
@Test
|
||||
void browserTypeExecutablePathShouldWork() {
|
||||
Assumptions.assumeTrue(getBrowserChannelFromEnv() == null);
|
||||
Assumptions.assumeTrue(createLaunchOptions().executablePath == null, "Skip with custom executable path");
|
||||
String executablePath = browserType.executablePath();
|
||||
assertTrue(Files.exists(Paths.get(executablePath)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void browserTypeNameShouldWork() {
|
||||
assertEquals(getBrowserNameFromEnv(), browserType.name());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledIf(value="com.microsoft.playwright.TestBase#isChromium", disabledReason="Non-chromium behavior")
|
||||
void shouldThrowWhenTryingToConnectWithNotChromium() {
|
||||
try {
|
||||
browserType.connectOverCDP("foo");
|
||||
fail("did not throw");
|
||||
} catch (PlaywrightException e) {
|
||||
assertTrue(e.getMessage().contains("Connecting over CDP is only supported in Chromium."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,14 +18,17 @@ package com.microsoft.playwright;
|
||||
|
||||
import com.microsoft.playwright.impl.Driver;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static com.microsoft.playwright.Utils.mapOf;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestBrowserTypeConnect extends TestBase {
|
||||
@@ -39,7 +42,12 @@ public class TestBrowserTypeConnect extends TestBase {
|
||||
void kill() throws InterruptedException {
|
||||
process.destroy();
|
||||
int exitCode = process.waitFor();
|
||||
assertEquals(0, exitCode);
|
||||
// FIXME: 2 tests are failing this check on windows:
|
||||
// disconnectedEventShouldBeEmittedWhenBrowserIsClosedOrServerIsClosed
|
||||
// shouldThrowWhenUsedAfterIsConnectedReturnsFalse
|
||||
if (!isWindows) {
|
||||
assertEquals(0, exitCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,6 +136,20 @@ public class TestBrowserTypeConnect extends TestBase {
|
||||
browser2.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSendExtraHeadersWithConnectRequest() throws Exception {
|
||||
try (WebSocketServerImpl webSocketServer = WebSocketServerImpl.create()) {
|
||||
try {
|
||||
browserType.connect("ws://localhost:" + webSocketServer.getPort() + "/ws",
|
||||
new BrowserType.ConnectOptions().setHeaders(mapOf("User-Agent", "Playwright", "foo", "bar")));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
assertNotNull(webSocketServer.lastClientHandshake);
|
||||
assertEquals("Playwright", webSocketServer.lastClientHandshake.getFieldValue("User-Agent"));
|
||||
assertEquals("bar", webSocketServer.lastClientHandshake.getFieldValue("foo"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void disconnectedEventShouldBeEmittedWhenBrowserIsClosedOrServerIsClosed() throws InterruptedException {
|
||||
// Launch another server to not affect other tests.
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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 com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.List;
|
||||
|
||||
import static com.microsoft.playwright.Utils.mapOf;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
@EnabledIf(value="com.microsoft.playwright.TestBase#isChromium", disabledReason="Chromium-specific API")
|
||||
public class TestChromium extends TestBase {
|
||||
@Override
|
||||
void createContextAndPage() {
|
||||
// Do not create anything.
|
||||
}
|
||||
|
||||
private static int nextPort = 9339;
|
||||
|
||||
private static String wsEndpointFromUrl(String urlString) throws IOException {
|
||||
URL url = new URL(urlString);
|
||||
URLConnection request = url.openConnection();
|
||||
request.connect();
|
||||
Reader reader = new InputStreamReader((InputStream) request.getContent());
|
||||
JsonObject json = new Gson().fromJson(reader, JsonObject.class);
|
||||
return json.get("webSocketDebuggerUrl").getAsString();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldConnectToAnExistingCdpSession() throws IOException {
|
||||
int port = nextPort++;
|
||||
try (Browser browserServer = browserType.launch(createLaunchOptions()
|
||||
.setArgs(asList("--remote-debugging-port=" + port)))) {
|
||||
Browser cdpBrowser = browserType.connectOverCDP("http://localhost:" + port);
|
||||
List<BrowserContext> contexts = cdpBrowser.contexts();
|
||||
assertEquals(1, contexts.size());
|
||||
cdpBrowser.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldConnectToAnExistingCdpSessionTwice() throws IOException {
|
||||
int port = nextPort++;
|
||||
try (Browser browserServer = browserType.launch(createLaunchOptions()
|
||||
.setArgs(asList("--remote-debugging-port=" + port)))) {
|
||||
String endpointUrl = "http://localhost:" + port;
|
||||
Browser cdpBrowser1 = browserType.connectOverCDP(endpointUrl);
|
||||
Browser cdpBrowser2 = browserType.connectOverCDP(endpointUrl);
|
||||
List<BrowserContext> contexts1 = cdpBrowser1.contexts();
|
||||
assertEquals(1, contexts1.size());
|
||||
Page page1 = contexts1.get(0).newPage();
|
||||
page1.navigate(server.EMPTY_PAGE);
|
||||
|
||||
List<BrowserContext> contexts2 = cdpBrowser2.contexts();
|
||||
assertEquals(1, contexts2.size());
|
||||
Page page2 = contexts2.get(0).newPage();
|
||||
page2.navigate(server.EMPTY_PAGE);
|
||||
|
||||
assertEquals(2, contexts1.get(0).pages().size());
|
||||
assertEquals(2, contexts2.get(0).pages().size());
|
||||
|
||||
cdpBrowser1.close();
|
||||
cdpBrowser2.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldConnectOverAWsEndpoint() throws IOException {
|
||||
int port = nextPort++;
|
||||
try (Browser browserServer = browserType.launch(createLaunchOptions()
|
||||
.setArgs(asList("--remote-debugging-port=" + port)))) {
|
||||
String wsEndpoint = wsEndpointFromUrl("http://localhost:" + port + "/json/version/");
|
||||
|
||||
Browser cdpBrowser1 = browserType.connectOverCDP(wsEndpoint);
|
||||
List<BrowserContext> contexts1 = cdpBrowser1.contexts();
|
||||
assertEquals(1, contexts1.size());
|
||||
cdpBrowser1.close();
|
||||
|
||||
Browser cdpBrowser2 = browserType.connectOverCDP(wsEndpoint);
|
||||
List<BrowserContext> contexts2 = cdpBrowser2.contexts();
|
||||
assertEquals(1, contexts2.size());
|
||||
cdpBrowser2.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSendExtraHeadersWithConnectRequest() throws Exception {
|
||||
try (WebSocketServerImpl webSocketServer = WebSocketServerImpl.create()) {
|
||||
try {
|
||||
browserType.connectOverCDP("ws://localhost:" + webSocketServer.getPort() + "/ws",
|
||||
new BrowserType.ConnectOverCDPOptions().setHeaders(mapOf("User-Agent", "Playwright", "foo", "bar")));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
assertNotNull(webSocketServer.lastClientHandshake);
|
||||
assertEquals("Playwright", webSocketServer.lastClientHandshake.getFieldValue("User-Agent"));
|
||||
assertEquals("bar", webSocketServer.lastClientHandshake.getFieldValue("foo"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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 com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@EnabledIf(value="com.microsoft.playwright.TestBase#isChromium", disabledReason="Chromium-only API")
|
||||
public class TestChromiumTracing extends TestBase {
|
||||
@Test
|
||||
void shouldOutputATrace(@TempDir Path tempDir) {
|
||||
Page page = browser.newPage();
|
||||
Path outputTraceFile = tempDir.resolve("trace.json");
|
||||
browser.startTracing(page, new Browser.StartTracingOptions()
|
||||
.setScreenshots(true).setPath(outputTraceFile));
|
||||
page.navigate(server.PREFIX + "/grid.html");
|
||||
browser.stopTracing();
|
||||
assertTrue(Files.exists(outputTraceFile));
|
||||
page.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCreateDirectoriesAsNeeded(@TempDir Path tempDir) {
|
||||
Page page = browser.newPage();
|
||||
Path filePath = tempDir.resolve("these/are/directories/trace.json");
|
||||
browser.startTracing(page, new Browser.StartTracingOptions()
|
||||
.setScreenshots(true).setPath(filePath));
|
||||
page.navigate(server.PREFIX + "/grid.html");
|
||||
browser.stopTracing();
|
||||
assertTrue(Files.exists(filePath));
|
||||
page.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRunWithCustomCategoriesIfProvided(@TempDir Path tempDir) throws IOException {
|
||||
Page page = browser.newPage();
|
||||
Path outputTraceFile = tempDir.resolve("trace.json");
|
||||
browser.startTracing(page, new Browser.StartTracingOptions()
|
||||
.setPath(outputTraceFile)
|
||||
.setCategories(asList("disabled-by-default-v8.cpu_profiler.hires")));
|
||||
browser.stopTracing();
|
||||
byte[] data = Files.readAllBytes(outputTraceFile);
|
||||
JsonObject traceJson = new Gson().fromJson(new FileReader(outputTraceFile.toFile()), JsonObject.class);
|
||||
assertTrue(traceJson.getAsJsonObject("metadata").get("trace-config")
|
||||
.getAsString().contains("disabled-by-default-v8.cpu_profiler.hires"));
|
||||
page.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowIfTracingOnTwoPages(@TempDir Path tempDir) {
|
||||
Page page = browser.newPage();
|
||||
Path outputTraceFile = tempDir.resolve("trace.json");
|
||||
browser.startTracing(page, new Browser.StartTracingOptions()
|
||||
.setPath(outputTraceFile));
|
||||
Page newPage = browser.newPage();
|
||||
try {
|
||||
browser.startTracing(newPage, new Browser.StartTracingOptions()
|
||||
.setPath(outputTraceFile));
|
||||
fail("did not throw");
|
||||
} catch (PlaywrightException e) {
|
||||
}
|
||||
newPage.close();
|
||||
browser.stopTracing();
|
||||
page.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnABuffer(@TempDir Path tempDir) throws IOException {
|
||||
Page page = browser.newPage();
|
||||
Path outputTraceFile = tempDir.resolve("trace.json");
|
||||
browser.startTracing(page, new Browser.StartTracingOptions()
|
||||
.setScreenshots(true).setPath(outputTraceFile));
|
||||
page.navigate(server.PREFIX + "/grid.html");
|
||||
byte[] trace = browser.stopTracing();
|
||||
byte[] buf = Files.readAllBytes(outputTraceFile);
|
||||
assertArrayEquals(buf, trace);
|
||||
page.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWorkWithoutOptions() {
|
||||
Page page = browser.newPage();
|
||||
browser.startTracing(page);
|
||||
page.navigate(server.PREFIX + "/grid.html");
|
||||
byte[] trace = browser.stopTracing();
|
||||
assertNotNull(trace);
|
||||
page.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSupportABufferWithoutAPath() {
|
||||
Page page = browser.newPage();
|
||||
browser.startTracing(page, new Browser.StartTracingOptions().setScreenshots(true));
|
||||
page.navigate(server.PREFIX + "/grid.html");
|
||||
byte[] trace = browser.stopTracing();
|
||||
assertTrue(new String(trace, StandardCharsets.UTF_8).contains("screenshot"));
|
||||
page.close();
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import org.junit.jupiter.api.condition.DisabledIf;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static com.microsoft.playwright.options.KeyboardModifier.SHIFT;
|
||||
|
||||
@@ -213,7 +213,7 @@ public class TestDownload extends TestBase {
|
||||
download.saveAs(userPath);
|
||||
fail("did not throw");
|
||||
} catch (PlaywrightException e) {
|
||||
assertTrue(e.getMessage().contains("Download already deleted. Save before deleting."));
|
||||
assertTrue(e.getMessage().contains("Target page, context or browser has been closed"), e.getMessage());
|
||||
}
|
||||
page.close();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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 org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIf;
|
||||
|
||||
import static com.microsoft.playwright.Utils.mapOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public class TestFirefoxLauncher extends TestBase {
|
||||
|
||||
@BeforeAll
|
||||
// Hide base class method to not launch browser.
|
||||
static void launchBrowser() {
|
||||
}
|
||||
|
||||
@Override
|
||||
void createContextAndPage() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledIf(value="com.microsoft.playwright.TestBase#isFirefox", disabledReason="skip")
|
||||
void shouldPassFirefoxUserPreferences() {
|
||||
BrowserType.LaunchOptions options = new BrowserType.LaunchOptions().setFirefoxUserPrefs(
|
||||
mapOf(
|
||||
"network.proxy.type", 1,
|
||||
"network.proxy.http", "127.0.0.1",
|
||||
"network.proxy.http_port", 3333));
|
||||
launchBrowser(options);
|
||||
Page page = browser.newPage();
|
||||
try {
|
||||
page.navigate("http://example.com");
|
||||
fail("did not throw");
|
||||
} catch (PlaywrightException e) {
|
||||
assertTrue(e.getMessage().contains("NS_ERROR_PROXY_CONNECTION_REFUSED"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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 com.google.gson.Gson;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static com.microsoft.playwright.Utils.mapOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class TestNetworkPostData extends TestBase {
|
||||
@Test
|
||||
void shouldReturnCorrectPostDataBufferForUtf8Body() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
String value = "baẞ";
|
||||
Request request = page.waitForRequest("**", () -> {
|
||||
page.evaluate("({url, value}) => {\n" +
|
||||
" const request = new Request(url, {\n" +
|
||||
" method: 'POST',\n" +
|
||||
" body: JSON.stringify(value),\n" +
|
||||
" });\n" +
|
||||
" request.headers.set('content-type', 'application/json;charset=UTF-8');\n" +
|
||||
" return fetch(request);\n" +
|
||||
"}", mapOf("url", server.PREFIX + "/title.html", "value", value));
|
||||
});
|
||||
assertTrue(Arrays.equals(new Gson().toJson(value).getBytes(StandardCharsets.UTF_8), request.postDataBuffer()));
|
||||
assertEquals(new Gson().toJson(value), request.postData());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnPostDataWOContentType() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Request request = page.waitForRequest("**", () -> {
|
||||
page.evaluate("({url}) => {\n" +
|
||||
" const request = new Request(url, {\n" +
|
||||
" method: 'POST',\n" +
|
||||
" body: JSON.stringify({ value: 42 }),\n" +
|
||||
" });\n" +
|
||||
" request.headers.set('content-type', '');\n" +
|
||||
" return fetch(request);\n" +
|
||||
"}", mapOf("url", server.PREFIX + "/title.html"));
|
||||
});
|
||||
assertEquals(new Gson().toJson(mapOf("value", 42)), request.postData());
|
||||
}
|
||||
|
||||
void shouldThrowOnInvalidJSONInPostData() {
|
||||
// Thre is no postDataJSON() in java
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnPostDataForPUTRequests() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Request request = page.waitForRequest("**", () -> {
|
||||
page.evaluate("({url}) => {\n" +
|
||||
" const request = new Request(url, {\n" +
|
||||
" method: 'PUT',\n" +
|
||||
" body: JSON.stringify({ value: 42 }),\n" +
|
||||
" });\n" +
|
||||
" return fetch(request);\n" +
|
||||
"}", mapOf("url", server.PREFIX + "/title.html"));
|
||||
});
|
||||
assertEquals(new Gson().toJson(mapOf("value", 42)), request.postData());
|
||||
}
|
||||
}
|
||||
@@ -67,8 +67,10 @@ public class TestPageBasic extends TestBase {
|
||||
assertEquals("", dialog.message());
|
||||
} else if (isWebKit()) {
|
||||
assertEquals("Leave?", dialog.message());
|
||||
} else {
|
||||
} else if (isChromium()) {
|
||||
assertEquals("This page is asking you to confirm that you want to leave - data you have entered may not be saved.", dialog.message());
|
||||
} else {
|
||||
assertEquals("This page is asking you to confirm that you want to leave — information you’ve entered may not be saved.", dialog.message());
|
||||
}
|
||||
dialog.accept();
|
||||
});
|
||||
|
||||
@@ -368,6 +368,8 @@ public class TestPageKeyboard extends TestBase {
|
||||
void shouldSupportMacOSShortcuts() {
|
||||
// Test for MacOS only
|
||||
Assumptions.assumeTrue(isMac);
|
||||
// @see https://github.com/microsoft/playwright/issues/5721
|
||||
Assumptions.assumeFalse(isFirefox());
|
||||
page.navigate(server.PREFIX + "/input/textarea.html");
|
||||
ElementHandle textarea = page.querySelector("textarea");
|
||||
textarea.type("some text");
|
||||
|
||||
@@ -523,6 +523,7 @@ public class TestPageRoute extends TestBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledIf(value="com.microsoft.playwright.TestBase#isChromium", disabledReason="https://github.com/microsoft/playwright/issues/6016")
|
||||
void shouldSupportCorsWithPOST() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
page.route("**/cars", route -> {
|
||||
@@ -545,6 +546,7 @@ public class TestPageRoute extends TestBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledIf(value="com.microsoft.playwright.TestBase#isChromium", disabledReason="https://github.com/microsoft/playwright/issues/6016")
|
||||
void shouldSupportCorsWithCredentials() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
page.route("**/cars", route -> {
|
||||
@@ -597,6 +599,7 @@ public class TestPageRoute extends TestBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledIf(value="com.microsoft.playwright.TestBase#isChromium", disabledReason="https://github.com/microsoft/playwright/issues/6016")
|
||||
void shouldSupportCorsForDifferentMethods() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
page.route("**/cars", route -> {
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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 com.microsoft.playwright.options.WaitUntilState;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestPageWaitForUrl extends TestBase {
|
||||
@Test
|
||||
void shouldWork() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
page.evaluate("url => window.location.href = url", server.PREFIX + "/grid.html");
|
||||
page.waitForURL("**/grid.html");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRespectTimeout() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
try {
|
||||
page.waitForURL("**/frame.html", new Page.WaitForURLOptions().setTimeout(2500));
|
||||
fail("did not throw");
|
||||
} catch (TimeoutError e) {
|
||||
assertTrue(e.getMessage().contains("Timeout 2500ms exceeded"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWorkWithBothDomcontentloadedAndLoad() {
|
||||
page.navigate(server.PREFIX + "/one-style.html");
|
||||
page.waitForURL("**/one-style.html", new Page.WaitForURLOptions().setWaitUntil(WaitUntilState.DOMCONTENTLOADED));
|
||||
page.waitForURL("**/one-style.html", new Page.WaitForURLOptions().setWaitUntil(WaitUntilState.LOAD));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWorkWithClickingOnAnchorLinks() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
page.setContent("<a href='#foobar'>foobar</a>");
|
||||
page.click("a");
|
||||
page.waitForURL("**/*#foobar");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWorkWithHistoryPushState() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
page.setContent("<a onclick='javascript:pushState()'>SPA</a>\n" +
|
||||
"<script>\n" +
|
||||
" function pushState() { history.pushState({}, '', 'wow.html') }\n" +
|
||||
"</script>");
|
||||
page.click("a");
|
||||
page.waitForURL("**/wow.html");
|
||||
assertEquals(server.PREFIX + "/wow.html", page.url());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWorkWithHistoryReplaceState() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
page.setContent(" <a onclick='javascript:replaceState()'>SPA</a>\n" +
|
||||
"<script>\n" +
|
||||
" function replaceState() { history.replaceState({}, '', '/replaced.html') }\n" +
|
||||
"</script>");
|
||||
page.click("a");
|
||||
page.waitForURL("**/replaced.html");
|
||||
assertEquals(server.PREFIX + "/replaced.html", page.url());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWorkWithDOMHistoryBackHistoryForward() {
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
page.setContent("<a id=back onclick='javascript:goBack()'>back</a>\n" +
|
||||
"<a id=forward onclick='javascript:goForward()'>forward</a>\n" +
|
||||
"<script>\n" +
|
||||
" function goBack() { history.back(); }\n" +
|
||||
" function goForward() { history.forward(); }\n" +
|
||||
" history.pushState({}, '', '/first.html');\n" +
|
||||
" history.pushState({}, '', '/second.html');\n" +
|
||||
"</script>");
|
||||
assertEquals(server.PREFIX + "/second.html", page.url());
|
||||
|
||||
page.click("a#back");
|
||||
page.waitForURL("**/first.html");
|
||||
assertEquals(server.PREFIX + "/first.html", page.url());
|
||||
|
||||
page.click("a#forward");
|
||||
page.waitForURL("**/second.html");
|
||||
assertEquals(server.PREFIX + "/second.html", page.url());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWorkOnFrame() {
|
||||
page.navigate(server.PREFIX + "/frames/one-frame.html");
|
||||
Frame frame = page.frames().get(1);
|
||||
frame.evaluate("url => window.location.href = url", server.PREFIX + "/grid.html");
|
||||
frame.waitForURL("**/grid.html");
|
||||
}
|
||||
}
|
||||
@@ -84,7 +84,7 @@ public class TestRequestContinue extends TestBase {
|
||||
});
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
assertNotNull(error[0]);
|
||||
assertTrue(error[0].getMessage().contains("New URL must have same protocol as overriden URL"));
|
||||
assertTrue(error[0].getMessage().contains("New URL must have same protocol as overridden URL"), error[0].getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -19,10 +19,13 @@ package com.microsoft.playwright;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestScreencast extends TestBase {
|
||||
@Test
|
||||
@@ -36,5 +39,90 @@ public class TestScreencast extends TestBase {
|
||||
assertTrue(path.startsWith(videosDir));
|
||||
context.close();
|
||||
assertTrue(Files.exists(path));
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSaveAsVideo(@TempDir Path videosDir) {
|
||||
BrowserContext context = browser.newContext(
|
||||
new Browser.NewContextOptions()
|
||||
.setRecordVideoDir(videosDir)
|
||||
.setRecordVideoSize(320, 240)
|
||||
.setViewportSize(320, 240));
|
||||
Page page = context.newPage();
|
||||
page.evaluate("() => document.body.style.backgroundColor = 'red'");
|
||||
page.waitForTimeout(1000);
|
||||
context.close();
|
||||
|
||||
Path saveAsPath = videosDir.resolve("my-video.webm");
|
||||
page.video().saveAs(saveAsPath);
|
||||
assertTrue(Files.exists(saveAsPath));
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveAsShouldThrowWhenNoVideoFrames(@TempDir Path videosDir) {
|
||||
BrowserContext context = browser.newContext(
|
||||
new Browser.NewContextOptions()
|
||||
.setRecordVideoDir(videosDir)
|
||||
.setRecordVideoSize(320, 240)
|
||||
.setViewportSize(320, 240));
|
||||
|
||||
Page page = context.newPage();
|
||||
Page popup = context.waitForPage(() -> {
|
||||
page.evaluate("() => {\n" +
|
||||
" const win = window.open('about:blank');\n" +
|
||||
" win.close();\n" +
|
||||
"}");
|
||||
});
|
||||
page.close();
|
||||
|
||||
Path saveAsPath = videosDir.resolve("my-video.webm");
|
||||
try {
|
||||
popup.video().saveAs(saveAsPath);
|
||||
} catch (PlaywrightException e) {
|
||||
// WebKit pauses renderer before win.close() and actually writes something.
|
||||
if (isWebKit()) {
|
||||
assertTrue(Files.exists(saveAsPath));
|
||||
} else {
|
||||
assertTrue(e.getMessage().contains("Page did not produce any video frames"), e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDeleteVideo(@TempDir Path videosDir) {
|
||||
BrowserContext context = browser.newContext(
|
||||
new Browser.NewContextOptions()
|
||||
.setRecordVideoDir(videosDir)
|
||||
.setRecordVideoSize(320, 240)
|
||||
.setViewportSize(320, 240));
|
||||
Page page = context.newPage();
|
||||
page.evaluate("() => document.body.style.backgroundColor = 'red'");
|
||||
page.waitForTimeout(1000);
|
||||
context.close();
|
||||
|
||||
page.video().delete();
|
||||
Path videoPath = page.video().path();
|
||||
assertFalse(Files.exists(videoPath));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWaitForVideoFinishWhenPageIsClosed(@TempDir Path videosDir) throws IOException {
|
||||
try (Browser browser = browserType.launch(createLaunchOptions())) {
|
||||
BrowserContext context = browser.newContext(
|
||||
new Browser.NewContextOptions()
|
||||
.setRecordVideoDir(videosDir)
|
||||
.setRecordVideoSize(320, 240)
|
||||
.setViewportSize(320, 240));
|
||||
Page page = context.newPage();
|
||||
page.evaluate("() => document.body.style.backgroundColor = 'red'");
|
||||
page.waitForTimeout(500);
|
||||
// First close page manually.
|
||||
page.close();
|
||||
context.close();
|
||||
}
|
||||
List<Path> files = Files.list(videosDir).collect(Collectors.toList());
|
||||
assertEquals(1, files.size());
|
||||
assertTrue(Files.exists(files.get(0)));
|
||||
assertTrue(Files.size(files.get(0)) > 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import org.java_websocket.WebSocket;
|
||||
import org.java_websocket.handshake.ClientHandshake;
|
||||
import org.java_websocket.server.WebSocketServer;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -35,35 +32,10 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestWebSocket extends TestBase {
|
||||
private static WebSocketServerImpl webSocketServer;
|
||||
private static int WS_SERVER_PORT = 8910;
|
||||
|
||||
private static class WebSocketServerImpl extends WebSocketServer {
|
||||
WebSocketServerImpl(InetSocketAddress address) {
|
||||
super(address, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(org.java_websocket.WebSocket webSocket, ClientHandshake clientHandshake) {
|
||||
webSocket.send("incoming");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(org.java_websocket.WebSocket webSocket, int i, String s, boolean b) { }
|
||||
|
||||
@Override
|
||||
public void onMessage(org.java_websocket.WebSocket webSocket, String s) { }
|
||||
|
||||
@Override
|
||||
public void onError(WebSocket webSocket, Exception e) { }
|
||||
|
||||
@Override
|
||||
public void onStart() { }
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
static void startWebSockerServer() {
|
||||
webSocketServer = new WebSocketServerImpl(new InetSocketAddress("localhost", WS_SERVER_PORT));
|
||||
new Thread(webSocketServer).start();
|
||||
static void startWebSockerServer() throws InterruptedException {
|
||||
webSocketServer = WebSocketServerImpl.create();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
|
||||
@@ -104,13 +104,16 @@ class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
static BrowserType getBrowserTypeFromEnv(Playwright playwright) {
|
||||
static String getBrowserNameFromEnv() {
|
||||
String browserName = System.getenv("BROWSER");
|
||||
|
||||
if (browserName == null) {
|
||||
browserName = "chromium";
|
||||
}
|
||||
return browserName;
|
||||
}
|
||||
|
||||
static BrowserType getBrowserTypeFromEnv(Playwright playwright) {
|
||||
String browserName = getBrowserNameFromEnv();
|
||||
switch (browserName) {
|
||||
case "webkit":
|
||||
return playwright.webkit();
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 org.java_websocket.WebSocket;
|
||||
import org.java_websocket.handshake.ClientHandshake;
|
||||
import org.java_websocket.server.WebSocketServer;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
class WebSocketServerImpl extends WebSocketServer implements AutoCloseable {
|
||||
volatile ClientHandshake lastClientHandshake;
|
||||
private final Semaphore startSemaphore = new Semaphore(0);
|
||||
|
||||
private static final AtomicInteger nextWsServerPort = new AtomicInteger(8910);
|
||||
|
||||
static WebSocketServerImpl create() throws InterruptedException {
|
||||
// FIXME: WebSocketServer.stop() doesn't release socket immediately and starting another server
|
||||
// fails with "Address already in use", so we just allocate new port.
|
||||
int port = nextWsServerPort.getAndIncrement();
|
||||
WebSocketServerImpl result = new WebSocketServerImpl(new InetSocketAddress("localhost", port));
|
||||
result.start();
|
||||
result.startSemaphore.acquire();
|
||||
return result;
|
||||
}
|
||||
|
||||
private WebSocketServerImpl(InetSocketAddress address) {
|
||||
super(address, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
this.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(org.java_websocket.WebSocket webSocket, ClientHandshake clientHandshake) {
|
||||
lastClientHandshake = clientHandshake;
|
||||
webSocket.send("incoming");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(org.java_websocket.WebSocket webSocket, int i, String s, boolean b) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(org.java_websocket.WebSocket webSocket, String s) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(WebSocket webSocket, Exception e) {
|
||||
e.printStackTrace();
|
||||
startSemaphore.release();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
startSemaphore.release();
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>parent-pom</artifactId>
|
||||
<version>0.190.0-SNAPSHOT</version>
|
||||
<version>1.11.1</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Playwright Parent Project</name>
|
||||
<description>Java library to automate Chromium, Firefox and WebKit with a single API.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
1.9.1-1614983396000
|
||||
1.11.1-1621490832000
|
||||
|
||||
@@ -14,12 +14,16 @@ trap "cd $(pwd -P)" EXIT
|
||||
cd "$(dirname $0)/.."
|
||||
|
||||
VERSION=$1
|
||||
POM_FILES=(
|
||||
pom.xml
|
||||
tools/api-generator/pom.xml
|
||||
tools/update-docs-version/pom.xml
|
||||
tools/test-local-installation/pom.xml
|
||||
tools/test-spring-boot-starter/pom.xml
|
||||
examples/pom.xml
|
||||
)
|
||||
|
||||
mvn versions:set -DnewVersion=$VERSION
|
||||
|
||||
cd tools/api-generator
|
||||
mvn versions:set -DnewVersion=$VERSION
|
||||
|
||||
cd -
|
||||
cd tools/update-docs-version
|
||||
mvn versions:set -DnewVersion=$VERSION
|
||||
for name in ${POM_FILES[*]};
|
||||
do
|
||||
mvn versions:set -D newVersion=$VERSION -f $name
|
||||
done
|
||||
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "-- tagging: $2"
|
||||
docker tag $1 $2
|
||||
docker push $2
|
||||
@@ -10,7 +10,7 @@ cd "$(dirname $0)/.."
|
||||
./scripts/generate_api.sh
|
||||
|
||||
# Built from source and do local install.
|
||||
mvn clean install --no-transfer-progress -DskipTests
|
||||
mvn clean install --no-transfer-progress -D skipTests
|
||||
|
||||
echo "Updating browser versions in README.md"
|
||||
mvn exec:java --f ./tools/update-docs-version -Dexec.mainClass=com.microsoft.playwright.tools.UpdateBrowserVersions
|
||||
mvn compile exec:java --f ./tools/update-docs-version -D exec.mainClass=com.microsoft.playwright.tools.UpdateBrowserVersions
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>api-generator</artifactId>
|
||||
<version>0.190.0-SNAPSHOT</version>
|
||||
<version>1.11.1</version>
|
||||
<name>Playwright - API Generator</name>
|
||||
<description>
|
||||
This is an internal module used to generate Java API from the upstream Playwright
|
||||
|
||||
@@ -1039,7 +1039,7 @@ public class ApiGenerator {
|
||||
for (JsonElement entry: api) {
|
||||
String name = entry.getAsJsonObject().get("name").getAsString();
|
||||
// We write this one manually.
|
||||
if ("TimeoutError".equals(name)) {
|
||||
if (asList("PlaywrightException", "TimeoutError").contains(name)) {
|
||||
continue;
|
||||
}
|
||||
List<String> lines = new ArrayList<>();
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set +x
|
||||
|
||||
trap "cd $(pwd -P)" EXIT
|
||||
cd "$(dirname $0)"
|
||||
|
||||
|
||||
PROJECT_DIR=$(mktemp -d)
|
||||
echo "Creating project in $PROJECT_DIR"
|
||||
cp -R . $PROJECT_DIR
|
||||
cp -R ../../driver-bundle/src/test/ $PROJECT_DIR/src/
|
||||
cp -R ../../playwright/src/test/ $PROJECT_DIR/src/
|
||||
cd $PROJECT_DIR
|
||||
|
||||
mvn test --no-transfer-progress
|
||||
|
||||
rm -rf $PROJECT_DIR
|
||||
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>test-local-installation</artifactId>
|
||||
<version>1.11.1</version>
|
||||
<name>Test local installation</name>
|
||||
<description>Runs Playwright test suite (copied from playwright module) against locally cached Playwright</description>
|
||||
<properties>
|
||||
<compiler.version>1.8</compiler.version>
|
||||
<gson.version>2.8.6</gson.version>
|
||||
<junit.version>5.7.0</junit.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<websocket.version>1.5.1</websocket.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>playwright</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>${gson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.java-websocket</groupId>
|
||||
<artifactId>Java-WebSocket</artifactId>
|
||||
<version>${websocket.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<source>${compiler.version}</source>
|
||||
<target>${compiler.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0-M5</version>
|
||||
<configuration>
|
||||
<redirectTestOutputToFile>true</redirectTestOutputToFile>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,2 @@
|
||||
This derictory is populated with test files from playwright and playwright-driver projects. They are copied
|
||||
here on each test run.
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.4.3</version>
|
||||
</parent>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>test-spring-boot-starter</artifactId>
|
||||
<version>1.11.1</version>
|
||||
<name>Test Playwright With Spring Boot</name>
|
||||
<properties>
|
||||
<spring.version>2.4.3</spring.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>playwright</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package com.microsoft.playwright.springboottest;
|
||||
|
||||
import com.microsoft.playwright.*;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class TestApp implements CommandLineRunner {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(TestApp.class, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(String... args) {
|
||||
try (Playwright playwright = Playwright.create()) {
|
||||
BrowserType browserType = getBrowserTypeFromEnv(playwright);
|
||||
System.out.println("Running test with " + browserType.name());
|
||||
Browser browser = browserType.launch();
|
||||
BrowserContext context = browser.newContext();
|
||||
Page page = context.newPage();
|
||||
System.out.println(page.evaluate("'SUCCESS: did evaluate in page'"));
|
||||
}
|
||||
}
|
||||
|
||||
static BrowserType getBrowserTypeFromEnv(Playwright playwright) {
|
||||
String browserName = System.getenv("BROWSER");
|
||||
|
||||
if (browserName == null) {
|
||||
browserName = "chromium";
|
||||
}
|
||||
|
||||
switch (browserName) {
|
||||
case "webkit":
|
||||
return playwright.webkit();
|
||||
case "firefox":
|
||||
return playwright.firefox();
|
||||
case "chromium":
|
||||
return playwright.chromium();
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown browser: " + browserName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>com.microsoft.playwright</groupId>
|
||||
<artifactId>update-version</artifactId>
|
||||
<version>0.190.0-SNAPSHOT</version>
|
||||
<version>1.11.1</version>
|
||||
<name>Playwright - Update Version in Documentation</name>
|
||||
<description>
|
||||
This is an internal module used to update versions in the documentation based on
|
||||
@@ -38,4 +38,12 @@
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>snapshots-repo</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
<releases><enabled>false</enabled></releases>
|
||||
<snapshots><enabled>true</enabled></snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
</project>
|
||||
|
||||
Reference in New Issue
Block a user